redis3m  1.0.0
All Classes Functions Variables Enumerations Pages
orm.h
1 // Copyright (c) 2014 Luca Marturana. All rights reserved.
2 // Licensed under Apache 2.0, see LICENSE for details
3 
4 #pragma once
5 
6 #include <redis3m/connection.h>
7 #include <map>
8 #include <string>
9 #include <algorithm>
10 #include <boost/foreach.hpp>
11 #include <redis3m/patterns/model.h>
12 #include <redis3m/patterns/script_exec.h>
13 #include <msgpack.hpp>
14 #include <redis3m/utils/file.h>
15 
16 namespace redis3m
17 {
18 namespace patterns
19 {
20 
21 template<typename Model>
30 class orm {
31 public:
32 
40  Model find_by_id(connection::ptr_t conn, const std::string& id)
41  {
42  reply r = conn->run(command("HGETALL")(model_key(id)));
43  if (r.elements().size() > 0 )
44  {
45  std::map<std::string, std::string> map;
46  for (unsigned long i = 0; i < r.elements().size(); i+=2 )
47  {
48  map[r.elements()[i].str()] = r.elements()[i+1].str();
49  }
50  return Model(id, map);
51  }
52  else
53  {
54  return Model();
55  }
56  }
57 
65  Model find_by_unique_field(connection::ptr_t conn, const std::string& field, const std::string& value)
66  {
67  std::string id = conn->run(command("HGET")(unique_field_key(field))(value)).str();
68  if (!id.empty())
69  {
70  return find_by_id(conn, id);
71  }
72  else
73  {
74  return Model();
75  }
76  }
77 
84  bool exists_by_id(connection::ptr_t conn, const std::string& id)
85  {
86  return conn->run(command("SISMEMBER")(collection_key(), id)).integer() == 1;
87  }
88 
95  std::string save(connection::ptr_t conn, const Model& model)
96  {
97  std::map<std::string, std::string> model_map;
98  model_map["name"] = model.model_name();
99  if (model.loaded())
100  {
101  model_map["id"] = model.id();
102  }
103  std::vector<std::string> args;
104  msgpack::sbuffer sbuf; // simple buffer
105 
106  // Pack model data
107  msgpack::pack(&sbuf, model_map);
108  args.push_back(std::string(sbuf.data(), sbuf.size()));
109  sbuf.clear();
110 
111  // pack model attributes
112  std::map<std::string, std::string> attributes = model.to_map();
113  std::vector<std::string> attributes_vector;
114  typedef std::pair<std::string, std::string> strpair;
115  BOOST_FOREACH(const strpair& item, attributes)
116  {
117  attributes_vector.push_back(item.first);
118  attributes_vector.push_back(item.second);
119  }
120 
121  msgpack::pack(&sbuf, attributes_vector);
122  args.push_back(std::string(sbuf.data(), sbuf.size()));
123  sbuf.clear();
124 
125  // pack model indices
126  std::vector<std::pair<std::string, std::string> > indices;
127  BOOST_FOREACH(const std::string& index, Model::indices())
128  {
129  indices.push_back(std::make_pair(index, attributes[index]));
130  }
131  msgpack::pack(&sbuf, indices);
132  args.push_back(std::string(sbuf.data(), sbuf.size()));
133  sbuf.clear();
134 
135  // pack model uniques
136  std::map<std::string, std::string> uniques;
137  BOOST_FOREACH(const std::string& index, Model::uniques())
138  {
139  uniques[index] = attributes[index];
140  }
141  msgpack::pack(&sbuf, uniques);
142  args.push_back(std::string(sbuf.data(), sbuf.size()));
143 
144  reply r = save_script.exec(conn, std::vector<std::string>(), args);
145 
146  return r.str();
147  }
148 
154  void remove(connection::ptr_t conn, const Model& model)
155  {
156  std::map<std::string, std::string> model_map;
157  model_map["name"] = model.model_name();
158  model_map["id"] = model.id();
159  model_map["key"] = model_key(model.id());
160 
161  std::vector<std::string> args;
162  msgpack::sbuffer sbuf; // simple buffer
163 
164  // Pack model data
165  msgpack::pack(&sbuf, model_map);
166  args.push_back(std::string(sbuf.data(), sbuf.size()));
167  sbuf.clear();
168 
169  // pack model uniques
170  std::map<std::string, std::string> attributes = model.to_map();
171  std::map<std::string, std::string> uniques;
172  BOOST_FOREACH(const std::string& index, Model::uniques())
173  {
174  uniques[index] = attributes[index];
175  }
176  msgpack::pack(&sbuf, uniques);
177  args.push_back(std::string(sbuf.data(), sbuf.size()));
178  sbuf.clear();
179 
180  msgpack::pack(&sbuf, Model::tracked());
181  args.push_back(std::string(sbuf.data(), sbuf.size()));
182  sbuf.clear();
183 
184  remove_script.exec(conn, std::vector<std::string>(), args);
185  }
186 
187  std::vector<std::string> list_members(connection::ptr_t conn, const Model& m, const std::string& list_name)
188  {
189  std::vector<std::string> ret;
190  reply lrange = conn->run(command("LRANGE")
191  (tracked_key(m.id(), list_name))
192  ("0")("-1"));
193  BOOST_FOREACH(const reply& r, lrange.elements())
194  {
195  ret.push_back(r.str());
196  }
197  return ret;
198  }
199 
200  void set_add(connection::ptr_t conn, const Model& m, const std::string& set_name, const std::string& entry)
201  {
202  conn->run(command("SADD")(tracked_key(m.id(), set_name))(entry));
203  }
204 
205  void set_remove(connection::ptr_t conn, const Model& m, const std::string& set_name, const std::string& entry)
206  {
207  conn->run(command("SREM")(tracked_key(m.id(), set_name)(entry)));
208  }
209 
210  std::set<std::string> set_members(connection::ptr_t conn, const Model& m, const std::string& set_name)
211  {
212  reply r = conn->run(command("SMEMBERS")(tracked_key(m.id(), set_name)));
213  std::set<std::string> ret;
214  BOOST_FOREACH(const reply& i, r.elements())
215  {
216  ret.insert(i.str());
217  }
218  }
219 
226  inline std::string collection_key()
227  {
228  return Model::model_name() + ":all";
229  }
230 
238  inline std::string collection_id_key()
239  {
240  return Model::model_name() + ":id";
241  }
242 
248  inline std::string model_key(const std::string& id)
249  {
250  return Model::model_name() + ":" + id;
251  }
252 
259  inline std::string tracked_key(const std::string& id, const std::string& key)
260  {
261  return model_key(id) + ":" + key;
262  }
263 
264  inline std::string indexed_field_key(const std::string& field, const std::string& value)
265  {
266  return Model::model_name() + ":indices:" + field + ":" + value;
267  }
268 
269  inline std::string unique_field_key(const std::string& field)
270  {
271  return Model::model_name() + ":uniques:" + field;
272  }
273 
274 private:
275  static script_exec save_script;
276  static script_exec remove_script;
277 };
278 
279 template<typename Model>
280 script_exec orm<Model>::save_script(utils::datadir("/lua/save.lua"), true);
281 
282 template<typename Model>
283 script_exec orm<Model>::remove_script(utils::datadir("/lua/delete.lua"), true);
284 
285 }
286 }
const std::string & str() const
Returns string value if present, otherwise an empty string.
Definition: reply.h:43
bool exists_by_id(connection::ptr_t conn, const std::string &id)
Check if an object exists or not.
Definition: orm.h:84
Object-Redis-Mapper is a convenient pattern to store object on Redis. Useful when you need classic CR...
Definition: orm.h:30
Class useful to define models used by orm and simple_obj_store. REDIS3M_MODEL_RO_ATTRIBUTE(type, name) macro defines automatically an attribute with a public getter. All fields need to be serialized to a std::map<std::string, std::string>. Model class contains various helpers to to that easily.
Definition: model.h:32
std::string tracked_key(const std::string &id, const std::string &key)
Returns full key, related to object.
Definition: orm.h:259
Model find_by_unique_field(connection::ptr_t conn, const std::string &field, const std::string &value)
Find an object by using a unique field.
Definition: orm.h:65
std::map< std::string, std::string > to_map()
Serialize all object data to a string:string map, it will be saved on Redis on a Hash.
Definition: model.h:66
std::string save(connection::ptr_t conn, const Model &model)
Save an object on database, or update it if it's already present.
Definition: orm.h:95
const std::vector< reply > & elements() const
Returns a vector of sub-replies if present, otherwise an empty one.
Definition: reply.h:53
std::string collection_key()
Redis key of a SET containing all object ids. Useful for custom operations. Pay attention to mantain ...
Definition: orm.h:226
Represent a reply received from redis server.
Definition: reply.h:18
Model find_by_id(connection::ptr_t conn, const std::string &id)
As the name says, get an object from id specifying it's unique identifier.
Definition: orm.h:40
const std::string & id() const
Object unique identifier.
Definition: model.h:75
std::string collection_id_key()
Key containing an incremental counter, used to generate an id for new objects. Useful for custom oper...
Definition: orm.h:238
reply exec(connection::ptr_t connection, const std::vector< std::string > &keys=std::vector< std::string >(), const std::vector< std::string > &args=std::vector< std::string >())
Execute the script. First trying with EVALSHA, then with EVAL.
Definition: script_exec.cpp:31
std::string model_key(const std::string &id)
Returns Redis Key used to save object data.
Definition: orm.h:248