lotus-rethinkdb 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +17 -0
- data/lib/lotus/model/adapters/rethinkdb/collection.rb +205 -0
- data/lib/lotus/model/adapters/rethinkdb/command.rb +66 -0
- data/lib/lotus/model/adapters/rethinkdb/query.rb +364 -0
- data/lib/lotus/model/adapters/rethinkdb_adapter.rb +234 -0
- data/lib/lotus/rethinkdb/version.rb +16 -0
- data/lib/lotus-rethinkdb.rb +2 -0
- data/lotus-rethinkdb.gemspec +29 -0
- data/test/model/adapters/rethinkdb/query_test.rb +0 -0
- data/test/model/adapters/rethinkdb_adapter_test.rb +562 -0
- data/test/test_helper.rb +29 -0
- data/test/version_test.rb +7 -0
- metadata +164 -0
@@ -0,0 +1,364 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'lotus/utils/kernel'
|
3
|
+
require 'rethinkdb'
|
4
|
+
|
5
|
+
module Lotus
|
6
|
+
module Model
|
7
|
+
module Adapters
|
8
|
+
module Rethinkdb
|
9
|
+
# Query the database with a powerful API.
|
10
|
+
#
|
11
|
+
# All the methods are chainable, it allows advanced composition of
|
12
|
+
# ReQL conditions.
|
13
|
+
#
|
14
|
+
# This works as a lazy filtering mechanism: the documents are fetched
|
15
|
+
# from the database only when needed.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# query.where(language: 'ruby')
|
20
|
+
# .and(framework: 'lotus')
|
21
|
+
# .desc(:users_count).all
|
22
|
+
#
|
23
|
+
# # the documents are fetched only when we invoke #all
|
24
|
+
#
|
25
|
+
# It implements Ruby's `Enumerable` and borrows some methods from
|
26
|
+
# `Array`. Expect a query to act like them.
|
27
|
+
#
|
28
|
+
# @since 0.1.0
|
29
|
+
class Query
|
30
|
+
include RethinkDB::Shortcuts
|
31
|
+
include Enumerable
|
32
|
+
extend Forwardable
|
33
|
+
|
34
|
+
def_delegators :all, :each, :to_s, :empty?
|
35
|
+
|
36
|
+
# @attr_reader conditions [Array] an accumulator for the called
|
37
|
+
# methods
|
38
|
+
#
|
39
|
+
# @since 0.1.0
|
40
|
+
# @api private
|
41
|
+
attr_reader :conditions
|
42
|
+
|
43
|
+
# Initialize a query
|
44
|
+
#
|
45
|
+
# @param collection [Lotus::Model::Adapters::Rethinkdb::Collection]
|
46
|
+
# the collection to query
|
47
|
+
#
|
48
|
+
# @param blk [Proc] an optional block that gets yielded in the
|
49
|
+
# context of the current query
|
50
|
+
#
|
51
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Query]
|
52
|
+
def initialize(collection, context = nil, &blk)
|
53
|
+
@collection, @context = collection, context
|
54
|
+
@conditions = []
|
55
|
+
|
56
|
+
instance_eval(&blk) if block_given?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Resolves the query by fetching documents from the database and
|
60
|
+
# translating them into entities.
|
61
|
+
#
|
62
|
+
# @return [Array] a collection of entities
|
63
|
+
#
|
64
|
+
# @since 0.1.0
|
65
|
+
def all
|
66
|
+
scoped.execute
|
67
|
+
end
|
68
|
+
|
69
|
+
# Adds a condition like SQL `WHERE` using r.filter().
|
70
|
+
#
|
71
|
+
# It accepts a `Hash` with only one pair.
|
72
|
+
# The key must be the name of the field expressed as a `Symbol`.
|
73
|
+
# The value is the one used by the ReQL query
|
74
|
+
#
|
75
|
+
# @param condition [Hash]
|
76
|
+
#
|
77
|
+
# @return self
|
78
|
+
#
|
79
|
+
# @since 0.1.0
|
80
|
+
#
|
81
|
+
# @example Fixed value
|
82
|
+
#
|
83
|
+
# query.where(language: 'ruby')
|
84
|
+
#
|
85
|
+
# # => r.filter(language: 'ruby')
|
86
|
+
#
|
87
|
+
# @example Multiple conditions
|
88
|
+
#
|
89
|
+
# query.where(language: 'ruby')
|
90
|
+
# .where(framework: 'lotus')
|
91
|
+
#
|
92
|
+
# # => r.filter(language: 'ruby').filter('framework: 'lotus')
|
93
|
+
#
|
94
|
+
# @example Blocks
|
95
|
+
#
|
96
|
+
# query.where { |doc| doc['age'] > 10 }
|
97
|
+
#
|
98
|
+
# # => r.filter { |doc| doc.bracket('age').gt('10') }
|
99
|
+
def where(condition = nil, &blk)
|
100
|
+
condition = condition || blk ||
|
101
|
+
fail(ArgumentError, 'You need to specify a condition.')
|
102
|
+
conditions.push([:filter, condition])
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
alias_method :and, :where
|
107
|
+
|
108
|
+
# Pluck only the specified fields. Documents without the fields are
|
109
|
+
# omitted.
|
110
|
+
#
|
111
|
+
# By default a query includes all the fields of a table.
|
112
|
+
#
|
113
|
+
# @param fields [Array<Symbol>]
|
114
|
+
#
|
115
|
+
# @return self
|
116
|
+
#
|
117
|
+
# @since 0.1.0
|
118
|
+
#
|
119
|
+
# @example Single field
|
120
|
+
#
|
121
|
+
# query.pluck(:name)
|
122
|
+
#
|
123
|
+
# # => r.pluck(:name)
|
124
|
+
#
|
125
|
+
# @example Multiple fields
|
126
|
+
#
|
127
|
+
# query.pluck(:name, :year)
|
128
|
+
#
|
129
|
+
# # => r.pluck(:name, :year)
|
130
|
+
def pluck(*fields)
|
131
|
+
conditions.push([:pluck, *fields])
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
# Limit the number of documents to return.
|
136
|
+
#
|
137
|
+
# This operation is performed at the database level with r.limit().
|
138
|
+
#
|
139
|
+
# @param number [Fixnum]
|
140
|
+
#
|
141
|
+
# @return self
|
142
|
+
#
|
143
|
+
# @since 0.1.0
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
#
|
147
|
+
# query.limit(1)
|
148
|
+
#
|
149
|
+
# # => r.limit(1)
|
150
|
+
def limit(number)
|
151
|
+
conditions.push([:limit, number])
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
# Specify the ascending order of the documents, sorted by the given
|
156
|
+
# fields or index. Identify an index using `{ index: :key }`.
|
157
|
+
#
|
158
|
+
# The last invokation of this method takes precidence. Previously
|
159
|
+
# called sorts will be overwritten by RethinkDB.
|
160
|
+
#
|
161
|
+
# @param fields [Array<Symbol, Hash>] the field names, optionally with
|
162
|
+
# an index identifier
|
163
|
+
#
|
164
|
+
# @return self
|
165
|
+
#
|
166
|
+
# @since 0.1.0
|
167
|
+
#
|
168
|
+
# @see Lotus::Model::Adapters::Rethinkdb::Query#desc
|
169
|
+
#
|
170
|
+
# @example Single field
|
171
|
+
#
|
172
|
+
# query.order(:name)
|
173
|
+
#
|
174
|
+
# # => r.order_by(:name)
|
175
|
+
#
|
176
|
+
# @example Multiple columns
|
177
|
+
#
|
178
|
+
# query.order(:name, :year)
|
179
|
+
#
|
180
|
+
# # => r.order_by(:name, :year)
|
181
|
+
#
|
182
|
+
# @example Single index
|
183
|
+
#
|
184
|
+
# query.order(index: :date)
|
185
|
+
#
|
186
|
+
# # => r.order_by(index: :date)
|
187
|
+
#
|
188
|
+
# @example Mixed fields and index
|
189
|
+
#
|
190
|
+
# query.order(:name, :year, index: :date)
|
191
|
+
#
|
192
|
+
# # => r.order_by(:name, :year, index: :date)
|
193
|
+
def order(*fields)
|
194
|
+
conditions.push([:order_by, *fields])
|
195
|
+
self
|
196
|
+
end
|
197
|
+
|
198
|
+
alias_method :asc, :order
|
199
|
+
|
200
|
+
# Specify the descending order of the documents, sorted by the given
|
201
|
+
# fields or index. Identify an index using `{ index: :key }`.
|
202
|
+
#
|
203
|
+
# The last invokation of this method takes precidence. Previously
|
204
|
+
# called sorts will be overwritten by RethinkDB.
|
205
|
+
#
|
206
|
+
# @return self
|
207
|
+
#
|
208
|
+
# @since 0.1.0
|
209
|
+
#
|
210
|
+
# @see Lotus::Model::Adapters::Rethinkdb::Query#desc
|
211
|
+
#
|
212
|
+
# @example Single field
|
213
|
+
#
|
214
|
+
# query.desc(:name)
|
215
|
+
#
|
216
|
+
# # => r.order_by(r.desc(:name))
|
217
|
+
#
|
218
|
+
# @example Multiple columns
|
219
|
+
#
|
220
|
+
# query.desc(:name, :year)
|
221
|
+
#
|
222
|
+
# # => r.order_by(r.desc(:name), r.desc(:year))
|
223
|
+
#
|
224
|
+
# @example Single index
|
225
|
+
#
|
226
|
+
# query.desc(index: :date)
|
227
|
+
#
|
228
|
+
# # => r.order_by(index: r.desc(:date))
|
229
|
+
#
|
230
|
+
# @example Mixed fields and index
|
231
|
+
#
|
232
|
+
# query.desc(r.desc(:name), r.desc(:year), index: r.desc(:date))
|
233
|
+
#
|
234
|
+
# # => r.order_by(:name, :year, index: :date)
|
235
|
+
def desc(*fields)
|
236
|
+
conditions.push([:order_by, *_desc_wrapper(*fields)])
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
# Apply all the conditions and returns a filtered collection.
|
241
|
+
#
|
242
|
+
# This operation is idempotent, and the returned result didn't
|
243
|
+
# fetched the documents yet.
|
244
|
+
#
|
245
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Collection]
|
246
|
+
#
|
247
|
+
# @since 0.1.0
|
248
|
+
def scoped
|
249
|
+
scope = @collection
|
250
|
+
|
251
|
+
conditions.each do |(method, *args)|
|
252
|
+
scope = scope.public_send(method, *args)
|
253
|
+
end
|
254
|
+
|
255
|
+
scope
|
256
|
+
end
|
257
|
+
|
258
|
+
protected
|
259
|
+
|
260
|
+
# Handles missing methods for query combinations
|
261
|
+
#
|
262
|
+
# @api private
|
263
|
+
# @since 0.1.0
|
264
|
+
#
|
265
|
+
# @see Lotus::Model::Adapters:Rethinkdb::Query#apply
|
266
|
+
def method_missing(m, *args, &blk)
|
267
|
+
if @context.respond_to?(m)
|
268
|
+
apply @context.public_send(m, *args, &blk)
|
269
|
+
else
|
270
|
+
super
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
# Returns a new query that is the result of the merge of the current
|
277
|
+
# conditions with the ones of the given query.
|
278
|
+
#
|
279
|
+
# This is used to combine queries together in a Repository.
|
280
|
+
#
|
281
|
+
# @param query [Lotus::Model::Adapters::Rethinkdb::Query] the query
|
282
|
+
# to apply
|
283
|
+
#
|
284
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Query] a new query with
|
285
|
+
# the merged conditions
|
286
|
+
#
|
287
|
+
# @api private
|
288
|
+
# @since 0.1.0
|
289
|
+
#
|
290
|
+
# @example
|
291
|
+
# require 'lotus/model'
|
292
|
+
#
|
293
|
+
# class ArticleRepository
|
294
|
+
# include Lotus::Repository
|
295
|
+
#
|
296
|
+
# def self.by_author(author)
|
297
|
+
# query do
|
298
|
+
# where(author_id: author.id)
|
299
|
+
# end
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# def self.rank
|
303
|
+
# query.desc(:comments_count)
|
304
|
+
# end
|
305
|
+
#
|
306
|
+
# def self.rank_by_author(author)
|
307
|
+
# rank.by_author(author)
|
308
|
+
# end
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
# # The code above combines two queries: `rank` and `by_author`.
|
312
|
+
# #
|
313
|
+
# # The first class method `rank` returns a `Rethinkdb::Query`
|
314
|
+
# # instance which doesn't respond to `by_author`. How to solve
|
315
|
+
# # this problem?
|
316
|
+
# #
|
317
|
+
# # 1. When we use `query` to fabricate a `Rethinkdb::Query` we
|
318
|
+
# # pass the current context (the repository itself) to the query
|
319
|
+
# # initializer.
|
320
|
+
# #
|
321
|
+
# # 2. When that query receives the `by_author` message, it's
|
322
|
+
# # captured by `method_missing` and dispatched to the repository.
|
323
|
+
# #
|
324
|
+
# # 3. The class method `by_author` returns a query too.
|
325
|
+
# #
|
326
|
+
# # 4. We just return a new query that is the result of the current
|
327
|
+
# # query's conditions (`rank`) and of the conditions from
|
328
|
+
# # `by_author`.
|
329
|
+
# #
|
330
|
+
# # You're welcome ;)
|
331
|
+
def apply(query)
|
332
|
+
dup.tap do |result|
|
333
|
+
result.conditions.push(*query.conditions)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# Wrap the given fields with a desc operator.
|
338
|
+
#
|
339
|
+
# @return [Array] the wrapped fields
|
340
|
+
#
|
341
|
+
# @api private
|
342
|
+
# @since 0.1.0
|
343
|
+
def _desc_wrapper(*fields)
|
344
|
+
Array(fields).map do |field|
|
345
|
+
if field.is_a?(Hash)
|
346
|
+
field.merge(field) { |_k, v| r.desc(v) }
|
347
|
+
else
|
348
|
+
r.desc(field)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
# Run the enclosed block on the database.
|
354
|
+
#
|
355
|
+
# @api private
|
356
|
+
# @since 0.1.0
|
357
|
+
def _run
|
358
|
+
yield.run(@connection)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'lotus/model/adapters/abstract'
|
2
|
+
require 'lotus/model/adapters/rethinkdb/collection'
|
3
|
+
require 'lotus/model/adapters/rethinkdb/command'
|
4
|
+
require 'lotus/model/adapters/rethinkdb/query'
|
5
|
+
require 'rethinkdb'
|
6
|
+
|
7
|
+
module Lotus
|
8
|
+
module Model
|
9
|
+
module Adapters
|
10
|
+
# Adapter for RethinkDB databases
|
11
|
+
#
|
12
|
+
# @see Lotus::Model::Adapters::Implementation
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.1.0
|
16
|
+
class RethinkdbAdapter < Abstract
|
17
|
+
include ::RethinkDB::Shortcuts
|
18
|
+
|
19
|
+
# Initialize the adapter.
|
20
|
+
#
|
21
|
+
# Lotus::Model uses RethinkDB.
|
22
|
+
#
|
23
|
+
# @param mapper [Object] the database mapper
|
24
|
+
# @param connection [RethinkDB::Connection] the database connection
|
25
|
+
#
|
26
|
+
# @return [Lotus::Model::Adapters::RethinkdbAdapter]
|
27
|
+
#
|
28
|
+
# @see Lotus::Model::Mapper
|
29
|
+
# @see http://rethinkdb.com/api/ruby/
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def initialize(mapper, connection)
|
34
|
+
super(mapper)
|
35
|
+
@connection = connection
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates or updates a document in the database for the given entity.
|
39
|
+
#
|
40
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
41
|
+
# @param entity [#id, #id=] the entity to persist
|
42
|
+
#
|
43
|
+
# @return [Object] the entity
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
# @since 0.1.0
|
47
|
+
def persist(collection, entity)
|
48
|
+
if entity.id
|
49
|
+
update(collection, entity)
|
50
|
+
else
|
51
|
+
create(collection, entity)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Creates a document in the database for the given entity.
|
56
|
+
# It assigns the `id` attribute, in case of success.
|
57
|
+
#
|
58
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
59
|
+
# @param entity [#id=] the entity to create
|
60
|
+
#
|
61
|
+
# @return [Object] the entity
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
# @since 0.1.0
|
65
|
+
def create(collection, entity)
|
66
|
+
entity.id = command(
|
67
|
+
query(collection)
|
68
|
+
).create(entity)
|
69
|
+
entity
|
70
|
+
end
|
71
|
+
|
72
|
+
# Updates a document in the database corresponding to the given entity.
|
73
|
+
#
|
74
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
75
|
+
# @param entity [#id] the entity to update
|
76
|
+
#
|
77
|
+
# @return [Object] the entity
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
# @since 0.1.0
|
81
|
+
def update(collection, entity)
|
82
|
+
command(
|
83
|
+
_find(collection, entity.id)
|
84
|
+
).update(entity)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Deletes a document in the database corresponding to the given entity.
|
88
|
+
#
|
89
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
90
|
+
# @param entity [#id] the entity to delete
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
# @since 0.1.0
|
94
|
+
def delete(collection, entity)
|
95
|
+
command(
|
96
|
+
_find(collection, entity.id)
|
97
|
+
).delete
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns all the documents for the given collection
|
101
|
+
#
|
102
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
103
|
+
#
|
104
|
+
# @return [Array] all the documents
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
# @since 0.1.0
|
108
|
+
def all(collection)
|
109
|
+
query(collection).all
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a unique document from the given collection, with the given
|
113
|
+
# id.
|
114
|
+
#
|
115
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
116
|
+
# @param id [Object] the identity of the object.
|
117
|
+
#
|
118
|
+
# @return [Object] the entity
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
# @since 0.1.0
|
122
|
+
def find(collection, id)
|
123
|
+
_first(
|
124
|
+
_find(collection, id)
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
# This method is not implemented. RethinkDB does not have sequential
|
129
|
+
# primary keys.
|
130
|
+
#
|
131
|
+
# @param _collection [Symbol] the target collection (it must be mapped)
|
132
|
+
#
|
133
|
+
# @raise [NotImplementedError]
|
134
|
+
#
|
135
|
+
# @since 0.1.0
|
136
|
+
def first(_collection)
|
137
|
+
fail NotImplementedError
|
138
|
+
end
|
139
|
+
|
140
|
+
# This method is not implemented. RethinkDB does not have sequential
|
141
|
+
# primary keys.
|
142
|
+
#
|
143
|
+
# @param _collection [Symbol] the target collection (it must be mapped)
|
144
|
+
#
|
145
|
+
# @raise [NotImplementedError]
|
146
|
+
#
|
147
|
+
# @since 0.1.0
|
148
|
+
def last(_collection)
|
149
|
+
fail NotImplementedError
|
150
|
+
end
|
151
|
+
|
152
|
+
# Deletes all the documents from the given collection.
|
153
|
+
#
|
154
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
155
|
+
#
|
156
|
+
# @api private
|
157
|
+
# @since 0.1.0
|
158
|
+
def clear(collection)
|
159
|
+
command(query(collection)).clear
|
160
|
+
end
|
161
|
+
|
162
|
+
# Fabricates a command for the given query.
|
163
|
+
#
|
164
|
+
# @param query [Lotus::Model::Adapters::Rethinkdb::Query] the query
|
165
|
+
# object to act on.
|
166
|
+
#
|
167
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Command]
|
168
|
+
#
|
169
|
+
# @see Lotus::Model::Adapters::Rethinkdb::Command
|
170
|
+
#
|
171
|
+
# @api private
|
172
|
+
# @since 0.1.0
|
173
|
+
def command(query)
|
174
|
+
Rethinkdb::Command.new(query)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Fabricates a query
|
178
|
+
#
|
179
|
+
# @param collection [Symbol] the target collection (it must be mapped).
|
180
|
+
# @param blk [Proc] a block of code to be executed in the context of
|
181
|
+
# the query.
|
182
|
+
#
|
183
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Query]
|
184
|
+
#
|
185
|
+
# @see Lotus::Model::Adapters::Rethinkdb::Query
|
186
|
+
#
|
187
|
+
# @api private
|
188
|
+
# @since 0.1.0
|
189
|
+
def query(collection, context = nil, &blk)
|
190
|
+
Rethinkdb::Query.new(_collection(collection), context, &blk)
|
191
|
+
end
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
# Returns a collection from the given name.
|
196
|
+
#
|
197
|
+
# @param name [Symbol] a name of the collection (it must be mapped).
|
198
|
+
#
|
199
|
+
# @return [Lotus::Model::Adapters::Rethinkdb::Collection]
|
200
|
+
#
|
201
|
+
# @see Lotus::Model::Adapters::Rethinkdb::Collection
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
# @since 0.1.0
|
205
|
+
def _collection(name)
|
206
|
+
Rethinkdb::Collection.new(
|
207
|
+
@connection, r.table(name), _mapped_collection(name)
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def _mapped_collection(name)
|
212
|
+
@mapper.collection(name)
|
213
|
+
end
|
214
|
+
|
215
|
+
def _find(collection, id)
|
216
|
+
identity = _identity(collection)
|
217
|
+
query(collection).where(identity => _id(collection, identity, id))
|
218
|
+
end
|
219
|
+
|
220
|
+
def _first(query)
|
221
|
+
query.limit(1).first
|
222
|
+
end
|
223
|
+
|
224
|
+
def _identity(collection)
|
225
|
+
_mapped_collection(collection).identity
|
226
|
+
end
|
227
|
+
|
228
|
+
def _id(collection, column, value)
|
229
|
+
_mapped_collection(collection).deserialize_attribute(column, value)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lotus/rethinkdb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'lotus-rethinkdb'
|
8
|
+
spec.version = Lotus::Model::Adapters::Rethinkdb::VERSION
|
9
|
+
spec.authors = ['Angelo Ashmore']
|
10
|
+
spec.email = ['angeloashmore@gmail.com']
|
11
|
+
spec.summary = 'RethinkDB adapter for Lotus::Model'
|
12
|
+
spec.description = 'RethinkDB adapter for Lotus::Model'
|
13
|
+
spec.homepage = 'https://github.com/angeloashmore/lotus-rethinkdb'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n")
|
17
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'lotus-model', '~> 0.2'
|
22
|
+
spec.add_runtime_dependency 'rethinkdb', '~> 1.15'
|
23
|
+
spec.add_runtime_dependency 'activesupport', '~> 4.2'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
26
|
+
spec.add_development_dependency 'minitest', '~> 5.5'
|
27
|
+
spec.add_development_dependency 'minitest-line', '~> 0.6.2'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
end
|
File without changes
|