couchbase-orm 1.1.1 → 2.0.2
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 +4 -4
- data/.github/workflows/test.yml +45 -0
- data/.gitignore +2 -0
- data/.travis.yml +3 -2
- data/CODEOWNERS +1 -0
- data/Gemfile +5 -3
- data/LICENSE +201 -24
- data/README.md +248 -35
- data/ci/run_couchbase.sh +22 -0
- data/couchbase-orm.gemspec +26 -20
- data/lib/couchbase-orm/active_record_compat.rb +92 -0
- data/lib/couchbase-orm/associations.rb +119 -0
- data/lib/couchbase-orm/base.rb +143 -166
- data/lib/couchbase-orm/changeable.rb +512 -0
- data/lib/couchbase-orm/connection.rb +28 -8
- data/lib/couchbase-orm/encrypt.rb +48 -0
- data/lib/couchbase-orm/error.rb +17 -2
- data/lib/couchbase-orm/inspectable.rb +37 -0
- data/lib/couchbase-orm/json_schema/json_validation_error.rb +13 -0
- data/lib/couchbase-orm/json_schema/loader.rb +47 -0
- data/lib/couchbase-orm/json_schema/validation.rb +18 -0
- data/lib/couchbase-orm/json_schema/validator.rb +45 -0
- data/lib/couchbase-orm/json_schema.rb +9 -0
- data/lib/couchbase-orm/json_transcoder.rb +27 -0
- data/lib/couchbase-orm/locale/en.yml +5 -0
- data/lib/couchbase-orm/n1ql.rb +133 -0
- data/lib/couchbase-orm/persistence.rb +61 -52
- data/lib/couchbase-orm/proxies/bucket_proxy.rb +36 -0
- data/lib/couchbase-orm/proxies/collection_proxy.rb +52 -0
- data/lib/couchbase-orm/proxies/n1ql_proxy.rb +40 -0
- data/lib/couchbase-orm/proxies/results_proxy.rb +23 -0
- data/lib/couchbase-orm/railtie.rb +6 -17
- data/lib/couchbase-orm/relation.rb +249 -0
- data/lib/couchbase-orm/strict_loading.rb +21 -0
- data/lib/couchbase-orm/timestamps/created.rb +20 -0
- data/lib/couchbase-orm/timestamps/updated.rb +21 -0
- data/lib/couchbase-orm/timestamps.rb +15 -0
- data/lib/couchbase-orm/types/array.rb +32 -0
- data/lib/couchbase-orm/types/date.rb +9 -0
- data/lib/couchbase-orm/types/date_time.rb +14 -0
- data/lib/couchbase-orm/types/encrypted.rb +17 -0
- data/lib/couchbase-orm/types/nested.rb +43 -0
- data/lib/couchbase-orm/types/timestamp.rb +18 -0
- data/lib/couchbase-orm/types.rb +20 -0
- data/lib/couchbase-orm/utilities/enum.rb +13 -1
- data/lib/couchbase-orm/utilities/has_many.rb +72 -36
- data/lib/couchbase-orm/utilities/ignored_properties.rb +15 -0
- data/lib/couchbase-orm/utilities/index.rb +18 -20
- data/lib/couchbase-orm/utilities/properties_always_exists_in_document.rb +16 -0
- data/lib/couchbase-orm/utilities/query_helper.rb +148 -0
- data/lib/couchbase-orm/utils.rb +25 -0
- data/lib/couchbase-orm/version.rb +1 -1
- data/lib/couchbase-orm/views.rb +38 -41
- data/lib/couchbase-orm.rb +44 -9
- data/lib/ext/query_n1ql.rb +124 -0
- data/lib/rails/generators/couchbase_orm/config/templates/couchbase.yml +3 -2
- data/spec/associations_spec.rb +219 -50
- data/spec/base_spec.rb +296 -14
- data/spec/collection_proxy_spec.rb +29 -0
- data/spec/connection_spec.rb +27 -0
- data/spec/couchbase-orm/active_record_compat_spec.rb +24 -0
- data/spec/couchbase-orm/changeable_spec.rb +16 -0
- data/spec/couchbase-orm/json_schema/validation_spec.rb +23 -0
- data/spec/couchbase-orm/json_schema/validator_spec.rb +13 -0
- data/spec/couchbase-orm/timestamps_spec.rb +85 -0
- data/spec/couchbase-orm/timestamps_spec_models.rb +36 -0
- data/spec/empty-json-schema/.gitkeep +0 -0
- data/spec/enum_spec.rb +34 -0
- data/spec/has_many_spec.rb +101 -54
- data/spec/index_spec.rb +13 -9
- data/spec/json-schema/JsonSchemaBaseTest.json +19 -0
- data/spec/json-schema/entity_snakecase.json +20 -0
- data/spec/json-schema/loader_spec.rb +42 -0
- data/spec/json-schema/specific_path.json +20 -0
- data/spec/json_schema_spec.rb +178 -0
- data/spec/n1ql_spec.rb +193 -0
- data/spec/persistence_spec.rb +49 -9
- data/spec/relation_nested_spec.rb +88 -0
- data/spec/relation_spec.rb +430 -0
- data/spec/support.rb +16 -8
- data/spec/type_array_spec.rb +52 -0
- data/spec/type_encrypted_spec.rb +114 -0
- data/spec/type_nested_spec.rb +191 -0
- data/spec/type_spec.rb +317 -0
- data/spec/utilities/ignored_properties_spec.rb +20 -0
- data/spec/utilities/properties_always_exists_in_document_spec.rb +24 -0
- data/spec/views_spec.rb +32 -11
- metadata +193 -30
data/README.md
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
# Couchbase ORM for Rails
|
2
2
|
|
3
|
-
|
3
|
+
## Documentation
|
4
|
+
https://couchbase-ruby-orm.com
|
4
5
|
|
5
|
-
##
|
6
|
+
## Installation
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
```ruby
|
9
|
+
gem 'couchbase-orm', git: 'https://github.com/Couchbase-Ecosystem/couchbase-ruby-orm'
|
10
|
+
```
|
11
|
+
And then execute:
|
6
12
|
|
7
|
-
|
13
|
+
$ bundle install
|
8
14
|
|
9
|
-
|
10
|
-
=> create config/couchbase.yml
|
15
|
+
## Rails integration
|
11
16
|
|
12
|
-
|
17
|
+
Create a couchbase-orm config file `config/couchbase.yml`
|
13
18
|
|
19
|
+
```yaml
|
14
20
|
common: &common
|
15
|
-
|
21
|
+
connection_string: couchbase://localhost
|
16
22
|
username: dev_user
|
17
23
|
password: dev_password
|
18
24
|
|
@@ -26,10 +32,25 @@ It will generate this `config/couchbase.yml` for you:
|
|
26
32
|
|
27
33
|
# set these environment variables on your production server
|
28
34
|
production:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
connection_string: <%= ENV['COUCHBASE_CONNECTION_STRING'] %>
|
36
|
+
bucket: <%= ENV['COUCHBASE_BUCKET'] %>
|
37
|
+
username: <%= ENV['COUCHBASE_USER'] %>
|
38
|
+
password: <%= ENV['COUCHBASE_PASSWORD'] %>
|
39
|
+
```
|
40
|
+
|
41
|
+
## Setup without Rails
|
42
|
+
|
43
|
+
If you are not using Rails, you can configure couchbase-orm with an initializer:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# config/initializers/couchbase_orm.rb
|
47
|
+
CouchbaseOrm::Connection.config = {
|
48
|
+
connection_string: "couchbase://localhost"
|
49
|
+
username: "dev_user"
|
50
|
+
password: "dev_password"
|
51
|
+
bucket: "dev_bucket"
|
52
|
+
}
|
53
|
+
```
|
33
54
|
|
34
55
|
Views are generated on application load if they don't exist or mismatch.
|
35
56
|
This works fine in production however by default in development models are lazy loaded.
|
@@ -37,16 +58,15 @@ This works fine in production however by default in development models are lazy
|
|
37
58
|
# config/environments/development.rb
|
38
59
|
config.eager_load = true
|
39
60
|
|
40
|
-
|
41
61
|
## Examples
|
42
62
|
|
43
63
|
```ruby
|
44
64
|
require 'couchbase-orm'
|
45
65
|
|
46
66
|
class Post < CouchbaseOrm::Base
|
47
|
-
attribute :title,
|
48
|
-
attribute :body,
|
49
|
-
attribute :draft,
|
67
|
+
attribute :title, :string
|
68
|
+
attribute :body, :string
|
69
|
+
attribute :draft, :boolean
|
50
70
|
end
|
51
71
|
|
52
72
|
p = Post.new(id: 'hello-world',
|
@@ -69,16 +89,45 @@ You can also let the library generate the unique identifier for you:
|
|
69
89
|
p.id #=> "post-abcDE34"
|
70
90
|
```
|
71
91
|
|
72
|
-
You can define connection options on per model basis:
|
92
|
+
<!-- You can define connection options on per model basis:
|
73
93
|
|
74
94
|
```ruby
|
75
95
|
class Post < CouchbaseOrm::Base
|
76
|
-
attribute :title,
|
77
|
-
attribute :body,
|
78
|
-
attribute :draft,
|
96
|
+
attribute :title, :string
|
97
|
+
attribute :body, :string
|
98
|
+
attribute :draft, :boolean
|
79
99
|
|
80
100
|
connect bucket: 'blog', password: ENV['BLOG_BUCKET_PASSWORD']
|
81
101
|
end
|
102
|
+
``` -->
|
103
|
+
|
104
|
+
## Typing
|
105
|
+
|
106
|
+
The following types have been tested :
|
107
|
+
|
108
|
+
- :string
|
109
|
+
- :integer
|
110
|
+
- :float
|
111
|
+
- :boolean
|
112
|
+
- :date
|
113
|
+
- :datetime (stored as iso8601, use precision: n to store more decimal precision)
|
114
|
+
- :timestamp (stored as integer)
|
115
|
+
- :encrypted
|
116
|
+
- see <https://docs.couchbase.com/couchbase-lite/current/c/field-level-encryption.html>
|
117
|
+
- You must store a string that can be encoded in json (not binary data), use base64 if needed
|
118
|
+
- :array (see below)
|
119
|
+
- :nested (see below)
|
120
|
+
|
121
|
+
You can register other types in ActiveModel registry :
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
class DateTimeWith3Decimal < CouchbaseOrm::Types::DateTime
|
125
|
+
def serialize(value)
|
126
|
+
value&.iso8601(3)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
ActiveModel::Type.register(:datetime3decimal, DateTimeWith3Decimal)
|
82
131
|
```
|
83
132
|
|
84
133
|
## Validations
|
@@ -89,7 +138,8 @@ context of rails application. You can also enforce types using ruby
|
|
89
138
|
|
90
139
|
```ruby
|
91
140
|
class Comment < Couchbase::Model
|
92
|
-
attribute :author, :
|
141
|
+
attribute :author, :string
|
142
|
+
attribute :body, :string
|
93
143
|
|
94
144
|
validates_presence_of :author, :body
|
95
145
|
end
|
@@ -102,7 +152,8 @@ can then be used for filtering results or ordering.
|
|
102
152
|
|
103
153
|
```ruby
|
104
154
|
class Comment < CouchbaseOrm::Base
|
105
|
-
attribute :author
|
155
|
+
attribute :author :string
|
156
|
+
attribute :body, :string
|
106
157
|
view :all # => emits :id and will return all comments
|
107
158
|
view :by_author, emit_key: :author
|
108
159
|
|
@@ -110,15 +161,12 @@ can then be used for filtering results or ordering.
|
|
110
161
|
# * the by_author view above
|
111
162
|
# * def find_by_author(author); end
|
112
163
|
index_view :author
|
113
|
-
|
164
|
+
|
114
165
|
# You can make compound keys by passing an array to :emit_key
|
115
166
|
# this allow to query by read/unread comments
|
116
167
|
view :by_read, emit_key: [:user_id, :read]
|
117
168
|
# this allow to query by view_count
|
118
169
|
view :by_view_count, emit_key: [:user_id, :view_count]
|
119
|
-
|
120
|
-
|
121
|
-
|
122
170
|
|
123
171
|
validates_presence_of :author, :body
|
124
172
|
end
|
@@ -128,20 +176,129 @@ You can use `Comment.find_by_author('name')` to obtain all the comments by
|
|
128
176
|
a particular author. The same thing, using the view directly would be:
|
129
177
|
`Comment.by_author(key: 'name')`
|
130
178
|
|
131
|
-
When using a compound key, the usage is the same, you just give the full key :
|
179
|
+
When using a compound key, the usage is the same, you just give the full key :
|
132
180
|
|
133
181
|
```ruby
|
134
182
|
Comment.by_read(key: '["'+user_id+'",false]') # gives all unread comments for one particular user
|
135
|
-
|
183
|
+
|
136
184
|
# or even a range !
|
185
|
+
|
186
|
+
Comment.by_view_count(startkey: '["'+user_id+'",10]', endkey: '["'+user_id+'",20]')
|
137
187
|
|
138
|
-
|
188
|
+
# gives all comments that have been seen more than 10 times but less than 20
|
139
189
|
```
|
140
|
-
|
141
|
-
Check this couchbase help page to learn more on what's possible with compound keys : https://developer.couchbase.com/documentation/server/3.x/admin/Views/views-translateSQL.html
|
190
|
+
Check this couchbase help page to learn more on what's possible with compound keys : <https://developer.couchbase.com/documentation/server/3.x/admin/Views/views-translateSQL.html>
|
142
191
|
|
143
192
|
Ex : Compound keys allows to decide the order of the results, and you can reverse it by passing `descending: true`
|
144
193
|
|
194
|
+
```ruby
|
195
|
+
class Comment < CouchbaseOrm::Base19
|
196
|
+
self.ignored_properties = [:old_name] # ignore old_name property in the model
|
197
|
+
self.properties_always_exists_in_document = true # use is null for nil value instead of not valued for performance purpose, only possible if all properties always exists in document
|
198
|
+
end
|
199
|
+
```
|
200
|
+
You can specify `properties_always_exists_in_document` to true if all properties always exists in document, this will allow to use `is null` instead of `not valued` for nil value, this will improve performance.
|
201
|
+
|
202
|
+
WARNING: If a document exists without a property, the query will failed! So you must be sure that all documents have all properties.
|
203
|
+
|
204
|
+
|
205
|
+
## N1ql
|
206
|
+
|
207
|
+
Like views, it's possible to use N1QL to process some requests used for filtering results or ordering.
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
class Comment < CouchbaseOrm::Base
|
211
|
+
attribute :author, :string
|
212
|
+
attribute :body, :string
|
213
|
+
n1ql :by_author, emit_key: :author
|
214
|
+
|
215
|
+
# Generates two functions:
|
216
|
+
# * the by_author view above
|
217
|
+
# * def find_by_author(author); end
|
218
|
+
index_n1ql :author
|
219
|
+
|
220
|
+
# You can make compound keys by passing an array to :emit_key
|
221
|
+
# this allow to query by read/unread comments
|
222
|
+
n1ql :by_read, emit_key: [:user_id, :read]
|
223
|
+
# this allow to query by view_count
|
224
|
+
n1ql :by_view_count, emit_key: [:user_id, :view_count]
|
225
|
+
|
226
|
+
validates_presence_of :author, :body
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
## Basic Active Record like query engine
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
class Comment < CouchbaseOrm::Base
|
234
|
+
attribute :title, :string
|
235
|
+
attribute :author, :string
|
236
|
+
attribute :category, :string
|
237
|
+
attribute :ratings, :number
|
238
|
+
end
|
239
|
+
|
240
|
+
Comment.where(author: "Anne McCaffrey", category: ['S-F', 'Fantasy']).not(ratings: 0).order(:title).limit(10)
|
241
|
+
|
242
|
+
# Relation can be composed as in AR:
|
243
|
+
|
244
|
+
amc_comments = Comment.where(author: "Anne McCaffrey")
|
245
|
+
|
246
|
+
amc_comments.count
|
247
|
+
|
248
|
+
amc_sf_comments = amc_comments.where(category: 'S-F')
|
249
|
+
|
250
|
+
# pluck is available, but will query all object fields first
|
251
|
+
|
252
|
+
Comment.pluck(:title, :ratings)
|
253
|
+
|
254
|
+
# To load the ids without loading the models
|
255
|
+
|
256
|
+
Comment.where(author: "David Eddings").ids
|
257
|
+
|
258
|
+
# To delete all the models of a relation
|
259
|
+
|
260
|
+
Comment.where(ratings: 0).delete_all
|
261
|
+
```
|
262
|
+
|
263
|
+
## scopes
|
264
|
+
|
265
|
+
Scopes can be written as class method, scope method is not implemented yet.
|
266
|
+
They can be chained as in AR or mixed with relation methods.
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
class Comment < CouchbaseOrm::Base
|
270
|
+
attribute :title, :string
|
271
|
+
attribute :author, :string
|
272
|
+
attribute :category, :string
|
273
|
+
attribute :ratings, :number
|
274
|
+
|
275
|
+
def self.by_author(author)
|
276
|
+
where(author: author)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
Comment.by_author("Anne McCaffrey").where(category: 'S-F').not(ratings: 0).order(:title).limit(10)
|
281
|
+
```
|
282
|
+
|
283
|
+
## Operators
|
284
|
+
|
285
|
+
Several operators are available to filter numerical results : \_gt, \_lt, \_gte, \_lte, \_ne
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
Comment.where(ratings: {_gt: 3})
|
289
|
+
```
|
290
|
+
|
291
|
+
## Range in the where
|
292
|
+
|
293
|
+
You can specify a Range of date or intger in the where clause
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
Person.where(birth_date: DateTime.new(1980, 1, 1)..DateTime.new(1990, 1, 1))
|
297
|
+
Person.where(age: 10..20)
|
298
|
+
|
299
|
+
Person.where(age: 10...20) # to exclude the upper bound
|
300
|
+
```
|
301
|
+
|
145
302
|
## Associations and Indexes
|
146
303
|
|
147
304
|
There are common active record helpers available for use `belongs_to` and `has_many`
|
@@ -155,21 +312,77 @@ There are common active record helpers available for use `belongs_to` and `has_m
|
|
155
312
|
has_many :comments, dependent: :destroy
|
156
313
|
|
157
314
|
# You can ensure an attribute is unique for this model
|
158
|
-
attribute :email,
|
315
|
+
attribute :email, :string
|
159
316
|
ensure_unique :email
|
160
317
|
end
|
161
318
|
```
|
162
319
|
|
320
|
+
By default, `has_many` uses a view for association,
|
321
|
+
but you can define a `type` option to specify an association using N1QL instead:
|
322
|
+
|
323
|
+
```ruby
|
324
|
+
class Comment < CouchbaseOrm::Base
|
325
|
+
belongs_to :author
|
326
|
+
end
|
327
|
+
|
328
|
+
class Author < CouchbaseOrm::Base
|
329
|
+
has_many :comments, type: :n1ql, dependent: :destroy
|
330
|
+
end
|
331
|
+
```
|
332
|
+
|
333
|
+
## Nested
|
334
|
+
|
335
|
+
Attributes can be of type nested, they must specify a type of NestedDocument.
|
336
|
+
The NestedValidation triggers nested validation on parent validation.
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
class Address < CouchbaseOrm::NestedDocument
|
340
|
+
attribute :road, :string
|
341
|
+
attribute :city, :string
|
342
|
+
validates :road, :city, presence: true
|
343
|
+
end
|
344
|
+
|
345
|
+
class Author < CouchbaseOrm::Base
|
346
|
+
attribute :address, :nested, type: Address
|
347
|
+
validates :address, nested: true
|
348
|
+
end
|
349
|
+
```
|
350
|
+
|
351
|
+
Model can be queried using the nested attributes
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
Author.where(address: {road: '1 rue de la paix', city: 'Paris'})
|
355
|
+
```
|
356
|
+
|
357
|
+
## Array
|
358
|
+
|
359
|
+
Attributes can be of type array, they must contain something that can be serialized and deserialized to/from JSON.
|
360
|
+
You can enforce the type of array elements. The type can be a NestedDocument
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
class Book < CouchbaseOrm::NestedDocument
|
364
|
+
attribute :name, :string
|
365
|
+
validates :name, presence: true
|
366
|
+
end
|
367
|
+
|
368
|
+
class Author < CouchbaseOrm::Base
|
369
|
+
attribute things, :array
|
370
|
+
attribute flags, :array, type: :string
|
371
|
+
attribute books, :array, type: Book
|
372
|
+
|
373
|
+
validates :books, nested: true
|
374
|
+
end
|
375
|
+
```
|
163
376
|
|
164
377
|
## Performance Comparison with Couchbase-Ruby-Model
|
165
378
|
|
166
379
|
Basically we migrated an application from [Couchbase Ruby Model](https://github.com/couchbase/couchbase-ruby-model)
|
167
380
|
to [Couchbase-ORM](https://github.com/acaprojects/couchbase-orm) (this project)
|
168
381
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
382
|
+
- Rails 5 production
|
383
|
+
- Puma as the webserver
|
384
|
+
- Running on a 2015 Macbook Pro
|
385
|
+
- Performance test: `siege -c250 -r10 http://localhost:3000/auth/authority`
|
173
386
|
|
174
387
|
The request above pulls the same database document each time and returns it. A simple O(1) operation.
|
175
388
|
|
data/ci/run_couchbase.sh
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
set -x
|
2
|
+
set -e
|
3
|
+
|
4
|
+
VERSION=$1
|
5
|
+
BUCKET=$2
|
6
|
+
USER=$3
|
7
|
+
PASSWORD=$4
|
8
|
+
|
9
|
+
|
10
|
+
wget https://packages.couchbase.com/releases/$VERSION/couchbase-server-enterprise_$VERSION-ubuntu20.04_amd64.deb
|
11
|
+
dpkg -i couchbase-server-enterprise_$VERSION-ubuntu20.04_amd64.deb
|
12
|
+
sleep 8
|
13
|
+
sudo service couchbase-server status
|
14
|
+
/opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1:8091 --cluster-username=admin --cluster-password=password --cluster-ramsize=320 --cluster-index-ramsize=256 --cluster-fts-ramsize=256 --services=data,index,query,fts
|
15
|
+
sleep 5
|
16
|
+
/opt/couchbase/bin/couchbase-cli server-info -c 127.0.0.1:8091 -u admin -p password
|
17
|
+
/opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=$BUCKET --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --wait
|
18
|
+
sleep 1
|
19
|
+
/opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u admin -p password --set --rbac-username $USER --rbac-password $PASSWORD --rbac-name "Auto Tester" --roles admin --auth-domain local
|
20
|
+
curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`type\`)"
|
21
|
+
curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_rating\` ON \`$BUCKET\`(\`rating\`)"
|
22
|
+
curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_name\` ON \`$BUCKET\`(\`name\`)"
|
data/couchbase-orm.gemspec
CHANGED
@@ -1,27 +1,33 @@
|
|
1
|
-
require File.expand_path(
|
1
|
+
require File.expand_path('../lib/couchbase-orm/version', __FILE__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
gem.description = "A Couchbase ORM for Rails"
|
4
|
+
gem.name = 'couchbase-orm'
|
5
|
+
gem.version = CouchbaseOrm::VERSION
|
6
|
+
gem.license = 'Apache-2.0'
|
7
|
+
gem.authors = ['Stephen von Takach', 'Gauthier Monserand', 'Pierre Merlin', 'Julien Burnet-Fauche']
|
8
|
+
gem.homepage = 'https://github.com/Couchbase-Ecosystem/couchbase-ruby-orm'
|
9
|
+
gem.summary = 'Couchbase ORM for Rails'
|
10
|
+
gem.description = 'A Couchbase ORM for Rails'
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
gem.required_ruby_version = '>= 2.7.0'
|
13
|
+
gem.require_paths = ['lib']
|
15
14
|
|
16
|
-
|
17
|
-
gem.add_runtime_dependency 'activemodel', '>= 4.0', '< 6.0'
|
18
|
-
gem.add_runtime_dependency 'radix', '~> 2.2' # converting numbers to and from any base
|
15
|
+
gem.add_runtime_dependency 'activemodel', ENV['ACTIVE_MODEL_VERSION'] || '>= 5.2'
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
gem.add_development_dependency 'minitest', '~> 5.10'
|
17
|
+
gem.add_runtime_dependency 'couchbase', '>= 3.4.2'
|
18
|
+
gem.add_runtime_dependency 'radix', '~> 2.2' # converting numbers to and from any base
|
19
|
+
gem.add_runtime_dependency 'json-schema', '>= 3' # validating JSON against a schema
|
24
20
|
|
25
|
-
|
26
|
-
|
21
|
+
gem.add_development_dependency 'rake', '~> 12.2'
|
22
|
+
gem.add_development_dependency 'rspec', '~> 3.7'
|
23
|
+
gem.add_development_dependency 'yard', '~> 0.9'
|
24
|
+
gem.add_development_dependency 'pry'
|
25
|
+
gem.add_development_dependency 'pry-stack_explorer'
|
26
|
+
gem.add_development_dependency 'simplecov'
|
27
|
+
gem.add_development_dependency 'actionpack'
|
28
|
+
gem.add_development_dependency 'timecop'
|
29
|
+
gem.add_development_dependency 'base64'
|
30
|
+
|
31
|
+
gem.files = `git ls-files`.split("\n")
|
32
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
27
33
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_model'
|
3
|
+
require 'active_support/hash_with_indifferent_access'
|
4
|
+
|
5
|
+
module CouchbaseOrm
|
6
|
+
|
7
|
+
# Set of methods defined in ActiveRecord and needed for CouchbaseOrm
|
8
|
+
# try to avoid dependencies on too many active record classes
|
9
|
+
# by exemple we don't want to go down to the concept of tables
|
10
|
+
module ActiveRecordCompat
|
11
|
+
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def primary_key
|
17
|
+
'id'
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_class?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_names # can't be an alias for now
|
25
|
+
attribute_names
|
26
|
+
end
|
27
|
+
|
28
|
+
def abstract_class?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def connected?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def table_exists?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def _reflect_on_association(_attribute)
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def type_for_attribute(attribute)
|
45
|
+
attribute_types[attribute]
|
46
|
+
end
|
47
|
+
|
48
|
+
if ActiveModel::VERSION::MAJOR < 6
|
49
|
+
def attribute_names
|
50
|
+
attribute_types.keys
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def slice(*methods)
|
56
|
+
HashWithIndifferentAccess.new(methods.flatten.to_h { |method| [method, public_send(method)] })
|
57
|
+
end
|
58
|
+
|
59
|
+
def values_at(*methods)
|
60
|
+
methods.flatten.map! { |method| public_send(method) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def _has_attribute?(attr_name)
|
64
|
+
attribute_names.include?(attr_name.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
def attribute_for_inspect(attr_name)
|
68
|
+
value = send(attr_name)
|
69
|
+
value.inspect
|
70
|
+
end
|
71
|
+
|
72
|
+
if ActiveModel::VERSION::MAJOR < 6
|
73
|
+
def attribute_names
|
74
|
+
self.class.attribute_names
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_attribute?(attr_name)
|
78
|
+
@attributes.key?(attr_name.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def attribute_present?(attribute)
|
82
|
+
value = send(attribute)
|
83
|
+
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _write_attribute(attr_name, value)
|
87
|
+
@attributes.write_from_user(attr_name.to_s, value)
|
88
|
+
value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|