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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +45 -0
  3. data/.gitignore +2 -0
  4. data/.travis.yml +3 -2
  5. data/CODEOWNERS +1 -0
  6. data/Gemfile +5 -3
  7. data/LICENSE +201 -24
  8. data/README.md +248 -35
  9. data/ci/run_couchbase.sh +22 -0
  10. data/couchbase-orm.gemspec +26 -20
  11. data/lib/couchbase-orm/active_record_compat.rb +92 -0
  12. data/lib/couchbase-orm/associations.rb +119 -0
  13. data/lib/couchbase-orm/base.rb +143 -166
  14. data/lib/couchbase-orm/changeable.rb +512 -0
  15. data/lib/couchbase-orm/connection.rb +28 -8
  16. data/lib/couchbase-orm/encrypt.rb +48 -0
  17. data/lib/couchbase-orm/error.rb +17 -2
  18. data/lib/couchbase-orm/inspectable.rb +37 -0
  19. data/lib/couchbase-orm/json_schema/json_validation_error.rb +13 -0
  20. data/lib/couchbase-orm/json_schema/loader.rb +47 -0
  21. data/lib/couchbase-orm/json_schema/validation.rb +18 -0
  22. data/lib/couchbase-orm/json_schema/validator.rb +45 -0
  23. data/lib/couchbase-orm/json_schema.rb +9 -0
  24. data/lib/couchbase-orm/json_transcoder.rb +27 -0
  25. data/lib/couchbase-orm/locale/en.yml +5 -0
  26. data/lib/couchbase-orm/n1ql.rb +133 -0
  27. data/lib/couchbase-orm/persistence.rb +61 -52
  28. data/lib/couchbase-orm/proxies/bucket_proxy.rb +36 -0
  29. data/lib/couchbase-orm/proxies/collection_proxy.rb +52 -0
  30. data/lib/couchbase-orm/proxies/n1ql_proxy.rb +40 -0
  31. data/lib/couchbase-orm/proxies/results_proxy.rb +23 -0
  32. data/lib/couchbase-orm/railtie.rb +6 -17
  33. data/lib/couchbase-orm/relation.rb +249 -0
  34. data/lib/couchbase-orm/strict_loading.rb +21 -0
  35. data/lib/couchbase-orm/timestamps/created.rb +20 -0
  36. data/lib/couchbase-orm/timestamps/updated.rb +21 -0
  37. data/lib/couchbase-orm/timestamps.rb +15 -0
  38. data/lib/couchbase-orm/types/array.rb +32 -0
  39. data/lib/couchbase-orm/types/date.rb +9 -0
  40. data/lib/couchbase-orm/types/date_time.rb +14 -0
  41. data/lib/couchbase-orm/types/encrypted.rb +17 -0
  42. data/lib/couchbase-orm/types/nested.rb +43 -0
  43. data/lib/couchbase-orm/types/timestamp.rb +18 -0
  44. data/lib/couchbase-orm/types.rb +20 -0
  45. data/lib/couchbase-orm/utilities/enum.rb +13 -1
  46. data/lib/couchbase-orm/utilities/has_many.rb +72 -36
  47. data/lib/couchbase-orm/utilities/ignored_properties.rb +15 -0
  48. data/lib/couchbase-orm/utilities/index.rb +18 -20
  49. data/lib/couchbase-orm/utilities/properties_always_exists_in_document.rb +16 -0
  50. data/lib/couchbase-orm/utilities/query_helper.rb +148 -0
  51. data/lib/couchbase-orm/utils.rb +25 -0
  52. data/lib/couchbase-orm/version.rb +1 -1
  53. data/lib/couchbase-orm/views.rb +38 -41
  54. data/lib/couchbase-orm.rb +44 -9
  55. data/lib/ext/query_n1ql.rb +124 -0
  56. data/lib/rails/generators/couchbase_orm/config/templates/couchbase.yml +3 -2
  57. data/spec/associations_spec.rb +219 -50
  58. data/spec/base_spec.rb +296 -14
  59. data/spec/collection_proxy_spec.rb +29 -0
  60. data/spec/connection_spec.rb +27 -0
  61. data/spec/couchbase-orm/active_record_compat_spec.rb +24 -0
  62. data/spec/couchbase-orm/changeable_spec.rb +16 -0
  63. data/spec/couchbase-orm/json_schema/validation_spec.rb +23 -0
  64. data/spec/couchbase-orm/json_schema/validator_spec.rb +13 -0
  65. data/spec/couchbase-orm/timestamps_spec.rb +85 -0
  66. data/spec/couchbase-orm/timestamps_spec_models.rb +36 -0
  67. data/spec/empty-json-schema/.gitkeep +0 -0
  68. data/spec/enum_spec.rb +34 -0
  69. data/spec/has_many_spec.rb +101 -54
  70. data/spec/index_spec.rb +13 -9
  71. data/spec/json-schema/JsonSchemaBaseTest.json +19 -0
  72. data/spec/json-schema/entity_snakecase.json +20 -0
  73. data/spec/json-schema/loader_spec.rb +42 -0
  74. data/spec/json-schema/specific_path.json +20 -0
  75. data/spec/json_schema_spec.rb +178 -0
  76. data/spec/n1ql_spec.rb +193 -0
  77. data/spec/persistence_spec.rb +49 -9
  78. data/spec/relation_nested_spec.rb +88 -0
  79. data/spec/relation_spec.rb +430 -0
  80. data/spec/support.rb +16 -8
  81. data/spec/type_array_spec.rb +52 -0
  82. data/spec/type_encrypted_spec.rb +114 -0
  83. data/spec/type_nested_spec.rb +191 -0
  84. data/spec/type_spec.rb +317 -0
  85. data/spec/utilities/ignored_properties_spec.rb +20 -0
  86. data/spec/utilities/properties_always_exists_in_document_spec.rb +24 -0
  87. data/spec/views_spec.rb +32 -11
  88. metadata +193 -30
@@ -0,0 +1,191 @@
1
+ require File.expand_path("../support", __FILE__)
2
+
3
+ require "active_model"
4
+
5
+ class SubTypeTest < CouchbaseOrm::NestedDocument
6
+ attribute :name, :string
7
+ attribute :tags, :array, type: :string
8
+ attribute :milestones, :array, type: :date
9
+ attribute :flags, :array, type: :boolean
10
+ attribute :things
11
+ attribute :child, :nested, type: SubTypeTest
12
+ end
13
+
14
+ class TypeNestedTest < CouchbaseOrm::Base
15
+ attribute :main, :nested, type: SubTypeTest
16
+ attribute :others, :array, type: SubTypeTest
17
+ attribute :flags, :array, type: :boolean
18
+ end
19
+
20
+ describe CouchbaseOrm::Types::Nested do
21
+ it "should be able to store and retrieve a nested object" do
22
+ obj = TypeNestedTest.new
23
+ obj.main = SubTypeTest.new
24
+ obj.main.name = "foo"
25
+ obj.main.tags = ["foo", "bar"]
26
+ obj.main.child = SubTypeTest.new(name: "bar")
27
+ obj.save!
28
+
29
+ obj = TypeNestedTest.find(obj.id)
30
+ expect(obj.main.name).to eq "foo"
31
+ expect(obj.main.tags).to eq ["foo", "bar"]
32
+ expect(obj.main.child.name).to eq "bar"
33
+ end
34
+
35
+ it "should be able to store and retrieve an array of nested objects" do
36
+ obj = TypeNestedTest.new
37
+ obj.others = [SubTypeTest.new, SubTypeTest.new]
38
+ obj.others[0].name = "foo"
39
+ obj.others[0].tags = ["foo", "bar"]
40
+ obj.others[1].name = "bar"
41
+ obj.others[1].tags = ["bar", "baz"]
42
+ obj.others[1].child = SubTypeTest.new(name: "baz")
43
+ obj.save!
44
+
45
+ obj = TypeNestedTest.find(obj.id)
46
+ expect(obj.others[0].name).to eq "foo"
47
+ expect(obj.others[0].tags).to eq ["foo", "bar"]
48
+ expect(obj.others[1].name).to eq "bar"
49
+ expect(obj.others[1].tags).to eq ["bar", "baz"]
50
+ expect(obj.others[1].child.name).to eq "baz"
51
+ end
52
+
53
+ it "should serialize to JSON" do
54
+ obj = TypeNestedTest.new
55
+ obj.others = [SubTypeTest.new, SubTypeTest.new]
56
+ obj.others[0].name = "foo"
57
+ obj.others[0].tags = ["foo", "bar"]
58
+ obj.others[1].name = "bar"
59
+ obj.others[1].tags = ["bar", "baz"]
60
+ obj.others[1].child = SubTypeTest.new(name: "baz")
61
+ obj.save!
62
+
63
+ obj = TypeNestedTest.find(obj.id)
64
+ expect(obj.send(:serialized_attributes)).to eq ({
65
+ "id" => obj.id,
66
+ "main" => nil,
67
+ "flags" => [],
68
+ "others" => [
69
+ {
70
+ "name" => "foo",
71
+ "tags" => ["foo", "bar"],
72
+ "milestones" => [],
73
+ "flags" => [],
74
+ "things" => nil,
75
+ "child" => nil
76
+ },
77
+ {
78
+ "name" => "bar",
79
+ "tags" => ["bar", "baz"],
80
+ "milestones" => [],
81
+ "flags" => [],
82
+ "things" => nil,
83
+ "child" => {
84
+ "name" => "baz",
85
+ "tags" => [],
86
+ "milestones" => [],
87
+ "flags" => [],
88
+ "things" => nil,
89
+ "child" => nil
90
+ }
91
+ }
92
+ ]
93
+ })
94
+ end
95
+
96
+ it "should not have a save method" do
97
+ expect(SubTypeTest.new).to_not respond_to(:save)
98
+ end
99
+
100
+ it "should not cast a list" do
101
+ expect{CouchbaseOrm::Types::Nested.new(type: SubTypeTest).cast([1,2,3])}.to raise_error(ArgumentError)
102
+ end
103
+
104
+ it "should not serialize a list" do
105
+ expect{CouchbaseOrm::Types::Nested.new(type: SubTypeTest).serialize([1,2,3])}.to raise_error(ArgumentError)
106
+ end
107
+
108
+ it "should save a object with nested changes" do
109
+ obj = TypeNestedTest.new
110
+ obj.main = SubTypeTest.new(name: "foo")
111
+ obj.others = [SubTypeTest.new(name: "foo"), SubTypeTest.new(name: "bar")]
112
+ obj.flags = [false, true]
113
+ obj.save!
114
+ obj.main.name = "bar"
115
+ obj.others[0].name = "bar"
116
+ obj.others[1].name = "baz"
117
+ obj.flags[0] = true
118
+
119
+ obj.save!
120
+ obj = TypeNestedTest.find(obj.id)
121
+ expect(obj.main.name).to eq "bar"
122
+ expect(obj.others[0].name).to eq "bar"
123
+ expect(obj.others[1].name).to eq "baz"
124
+ expect(obj.flags).to eq [true, true]
125
+ end
126
+
127
+ describe "Validations" do
128
+ class SubWithValidation < CouchbaseOrm::NestedDocument
129
+ attribute :id, :string
130
+ attribute :name
131
+ attribute :label
132
+ attribute :child, :nested, type: SubWithValidation
133
+ validates :name, presence: true
134
+ validates :child, nested: true
135
+ end
136
+
137
+ class WithValidationParent < CouchbaseOrm::Base
138
+ attribute :child, :nested, type: SubWithValidation
139
+ attribute :children, :array, type: SubWithValidation
140
+ validates :child, :children, nested: true
141
+ end
142
+
143
+ it "should generate an id" do
144
+ expect(SubWithValidation.new.id).to be_present
145
+ end
146
+
147
+ it "should not regenerate the id after reloading parent" do
148
+ obj = WithValidationParent.new
149
+ obj.child = SubWithValidation.new(name: "foo")
150
+ obj.save!
151
+ expect(obj.child.id).to be_present
152
+ old_id = obj.child.id
153
+ obj.reload
154
+ expect(obj.child.id).to eq(old_id)
155
+ end
156
+
157
+ it "should not override the param id" do
158
+ expect(SubWithValidation.new(id: "foo").id).to eq "foo"
159
+ end
160
+
161
+ it "should validate the nested object" do
162
+ obj = WithValidationParent.new
163
+ obj.child = SubWithValidation.new
164
+ expect(obj).to_not be_valid
165
+ expect(obj.errors[:child]).to eq ["is invalid"]
166
+ expect(obj.child.errors[:name]).to eq ["can't be blank"]
167
+ end
168
+
169
+ it "should validate the nested objects in an array" do
170
+ obj = WithValidationParent.new
171
+ obj.children = [SubWithValidation.new(name: "foo"), SubWithValidation.new]
172
+ expect(obj).to_not be_valid
173
+ expect(obj.errors[:children]).to eq ["is invalid"]
174
+ expect(obj.children[1].errors[:name]).to eq ["can't be blank"]
175
+ end
176
+
177
+ it "should validate the nested in the nested object" do
178
+ obj = WithValidationParent.new
179
+ obj.child = SubWithValidation.new name: "foo", label: "parent"
180
+ obj.child.child = SubWithValidation.new label: "child"
181
+
182
+ expect(obj).to_not be_valid
183
+ expect(obj.child).to_not be_valid
184
+ expect(obj.child.child).to_not be_valid
185
+
186
+ expect(obj.errors[:child]).to eq ["is invalid"]
187
+ expect(obj.child.errors[:child]).to eq ["is invalid"]
188
+ expect(obj.child.child.errors[:name]).to eq ["can't be blank"]
189
+ end
190
+ end
191
+ end
data/spec/type_spec.rb ADDED
@@ -0,0 +1,317 @@
1
+ require File.expand_path("../support", __FILE__)
2
+ require "timecop"
3
+ require "active_model"
4
+ require "couchbase-orm/types"
5
+
6
+ class DateTimeWith3Decimal < CouchbaseOrm::Types::DateTime
7
+ def serialize(value)
8
+ value&.iso8601(3)
9
+ end
10
+ end
11
+
12
+ ActiveModel::Type.register(:datetime3decimal, DateTimeWith3Decimal)
13
+
14
+ class TypeTest < CouchbaseOrm::Base
15
+ attribute :name, :string
16
+ attribute :age, :integer
17
+ attribute :size, :float
18
+ attribute :renewal_date, :date
19
+ attribute :subscribed_at, :datetime
20
+ attribute :some_time, :timestamp
21
+ attribute :precision3_time, :datetime3decimal
22
+ attribute :precision6_time, :datetime, precision: 6
23
+
24
+ attribute :created_at, :datetime, precision: 6
25
+ attribute :updated_at, :datetime, precision: 6
26
+
27
+ attribute :active, :boolean
28
+
29
+ index :age, presence: false
30
+ index :renewal_date, presence: false
31
+ index :some_time, presence: false
32
+ index :precision3_time, presence: false
33
+ end
34
+
35
+ class N1qlTypeTest < CouchbaseOrm::Base
36
+ attribute :name, :string
37
+ attribute :age, :integer
38
+ attribute :size, :float
39
+ attribute :renewal_date, :date
40
+ attribute :subscribed_at, :datetime
41
+ attribute :some_time, :timestamp
42
+ attribute :precision3_time, :datetime3decimal
43
+ attribute :active, :boolean
44
+
45
+ index_n1ql :name, validate: false
46
+ index_n1ql :age, validate: false
47
+ index_n1ql :size, validate: false
48
+ index_n1ql :active, validate: false
49
+ index_n1ql :renewal_date, validate: false
50
+ index_n1ql :some_time, validate: false
51
+ index_n1ql :subscribed_at, validate: false
52
+ index_n1ql :precision3_time, validate: false
53
+ n1ql :by_both_dates, emit_key: [:renewal_date, :subscribed_at], presence: false
54
+ end
55
+
56
+ TypeTest.ensure_design_document!
57
+ N1qlTypeTest.ensure_design_document!
58
+
59
+ describe CouchbaseOrm::Types::Timestamp do
60
+ it "should cast an integer to time" do
61
+ t = Time.at(Time.now.to_i)
62
+ expect(CouchbaseOrm::Types::Timestamp.new.cast(t.to_i)).to eq(t)
63
+ end
64
+ it "should cast an integer string to time" do
65
+ t = Time.at(Time.now.to_i)
66
+ expect(CouchbaseOrm::Types::Timestamp.new.cast(t.to_s)).to eq(t)
67
+ end
68
+ end
69
+
70
+ describe CouchbaseOrm::Types::Date do
71
+ it "should cast an string to date" do
72
+ d = Date.today
73
+ expect(CouchbaseOrm::Types::Date.new.cast(d.to_s)).to eq(d)
74
+ end
75
+
76
+ it "should serialize date to string" do
77
+ d = Date.today
78
+ expect(CouchbaseOrm::Types::Date.new.serialize(d)).to eq(d.to_s)
79
+ end
80
+
81
+ it "should get the type from the registry" do
82
+ expect(ActiveModel::Type.lookup(:date)).to eq(CouchbaseOrm::Types::Date.new)
83
+ end
84
+ end
85
+
86
+ describe CouchbaseOrm::Base do
87
+ before(:each) do
88
+ TypeTest.delete_all
89
+ N1qlTypeTest.delete_all
90
+ end
91
+
92
+ it "should be typed" do
93
+ expect(N1qlTypeTest.attribute_types["name"]).to be_a(ActiveModel::Type::String)
94
+ end
95
+
96
+ it "should be createable" do
97
+ t = TypeTest.create!
98
+ expect(t).to be_a(TypeTest)
99
+ end
100
+
101
+ it "should be able to set attributes" do
102
+ t = TypeTest.new
103
+ t.name = "joe"
104
+ t.age = 20
105
+ t.size = 1.5
106
+ t.renewal_date = Date.today
107
+ t.subscribed_at = Time.now
108
+ t.active = true
109
+ t.save!
110
+
111
+ expect(t.name).to eq("joe")
112
+ expect(t.age).to eq(20)
113
+ expect(t.size).to eq(1.5)
114
+ expect(t.renewal_date).to eq(Date.today)
115
+ expect(t.subscribed_at).to be_a(Time)
116
+ expect(t.active).to eq(true)
117
+ end
118
+
119
+ it "should be able to set attributes with a hash" do
120
+ t = TypeTest.new(name: "joe", age: 20, size: 1.5, renewal_date: Date.today, subscribed_at: Time.now, active: true)
121
+ t.save!
122
+
123
+ expect(t.name).to eq("joe")
124
+ expect(t.age).to eq(20)
125
+ expect(t.size).to eq(1.5)
126
+ expect(t.renewal_date).to eq(Date.today)
127
+ expect(t.subscribed_at).to be_a(Time)
128
+ expect(t.active).to eq(true)
129
+ end
130
+
131
+ it "should be able to be stored and retrieved" do
132
+ now = Time.now
133
+ t = TypeTest.create!(name: "joe", age: 20, size: 1.5, renewal_date: Date.today, subscribed_at: now, active: true)
134
+ t2 = TypeTest.find(t.id)
135
+
136
+ expect(t2.name).to eq("joe")
137
+ expect(t2.age).to eq(20)
138
+ expect(t2.size).to eq(1.5)
139
+ expect(t2.renewal_date).to eq(Date.today)
140
+ expect(t2.subscribed_at).to eq(now.utc.change(usec: 0))
141
+ expect(t2.active).to eq(true)
142
+ end
143
+
144
+ it "should be able to query by age" do
145
+ t = TypeTest.create!(age: 20)
146
+ _t2 = TypeTest.create!(age: 40)
147
+ expect(TypeTest.find_by_age(20)).to eq t
148
+ end
149
+
150
+ it "should be able to query by age and type cast" do
151
+ t = TypeTest.create!(age: "20")
152
+ expect(TypeTest.find_by_age(20)).to eq t
153
+ expect(TypeTest.find_by_age("20")).to eq t
154
+ end
155
+
156
+ it "should be able to query by date" do
157
+ t = TypeTest.create!(renewal_date: Date.today)
158
+ _t2 = TypeTest.create!(renewal_date: Date.today + 1)
159
+ expect(TypeTest.find_by_renewal_date(Date.today)).to eq t
160
+ end
161
+
162
+ it "should be able to query by date and type cast" do
163
+ t = TypeTest.create!(renewal_date: Date.today.to_s)
164
+ expect(TypeTest.find_by_renewal_date(Date.today)).to eq t
165
+ expect(TypeTest.find_by_renewal_date(Date.today.to_s)).to eq t
166
+ end
167
+
168
+ it "should be able to query by time" do
169
+ now = Time.now
170
+ t = TypeTest.create!(name: "t", some_time: now)
171
+ _t2 = TypeTest.create!(name: "t2", some_time: now + 1)
172
+ expect(TypeTest.find_by_some_time(now)).to eq t
173
+ end
174
+
175
+ it "should be able to query by time and type cast" do
176
+ now = Time.now
177
+ now_s = now.to_i.to_s
178
+ t = TypeTest.create!(some_time: now_s)
179
+ expect(TypeTest.find_by_some_time(now)).to eq t
180
+ expect(TypeTest.find_by_some_time(now_s)).to eq t
181
+ end
182
+
183
+ it "should be able to query by custom type" do
184
+ now = Time.now
185
+ t = TypeTest.create!(precision3_time: now)
186
+ _t2 = TypeTest.create!(precision3_time: now + 1)
187
+ expect(TypeTest.find_by_precision3_time(now)).to eq t
188
+ end
189
+
190
+ it "should be able to query by custom type and type cast" do
191
+ now = Time.now
192
+ now_s = now.utc.iso8601(3)
193
+ t = TypeTest.create!(precision3_time: now_s)
194
+ expect(TypeTest.find_by_precision3_time(now)).to eq t
195
+ expect(TypeTest.find_by_precision3_time(now_s)).to eq t
196
+ end
197
+
198
+ it "should be able to set attributes with a hash with indifferent access" do
199
+ t = TypeTest.new(ActiveSupport::HashWithIndifferentAccess.new(name: "joe", age: 20, size: 1.5, renewal_date: Date.today, subscribed_at: Time.now, active: true))
200
+ t.save!
201
+
202
+ expect(t.name).to eq("joe")
203
+ expect(t.age).to eq(20)
204
+ expect(t.size).to eq(1.5)
205
+ expect(t.renewal_date).to eq(Date.today)
206
+ expect(t.subscribed_at).to be_a(Time)
207
+ expect(t.active).to eq(true)
208
+ end
209
+
210
+ it "should be able to type cast attributes" do
211
+ t = TypeTest.new(name: "joe", age: "20", size: "1.5", renewal_date: Date.today.to_s, subscribed_at: Time.now.to_s, active: "true")
212
+ t.save!
213
+
214
+ expect(t.name).to eq("joe")
215
+ expect(t.age).to eq(20)
216
+ expect(t.size).to eq(1.5)
217
+ expect(t.renewal_date).to eq(Date.today)
218
+ expect(t.subscribed_at).to be_a(Time)
219
+ expect(t.active).to eq(true)
220
+ end
221
+
222
+ it "should be consistent with active record on failed cast" do
223
+ t = TypeTest.new(name: "joe", age: "joe", size: "joe", renewal_date: "joe", subscribed_at: "joe", active: "true")
224
+ t.save!
225
+
226
+ expect(t.age).to eq 0
227
+ expect(t.size).to eq 0.0
228
+ expect(t.renewal_date).to eq nil
229
+ expect(t.subscribed_at).to eq nil
230
+ expect(t.active).to eq true
231
+ end
232
+
233
+ it "should be able to query by name" do
234
+ t = N1qlTypeTest.create!(name: "joe")
235
+ _t2 = N1qlTypeTest.create!(name: "john")
236
+ expect(N1qlTypeTest.find_by_name("joe").to_a).to eq [t]
237
+ end
238
+
239
+ it "should be able to query by nil value" do
240
+ t = N1qlTypeTest.create!()
241
+ _t2 = N1qlTypeTest.create!(name: "john")
242
+ expect(N1qlTypeTest.find_by_name(nil).to_a).to eq [t]
243
+ end
244
+
245
+ it "should be able to query by array value" do
246
+ t = N1qlTypeTest.create!(name: "laura")
247
+ t2 = N1qlTypeTest.create!(name: "joe")
248
+ _t3 = N1qlTypeTest.create!(name: "john")
249
+ expect(N1qlTypeTest.find_by_name(["laura", "joe"]).to_a).to match_array [t, t2]
250
+ end
251
+
252
+ it "should be able to query by integer" do
253
+ t = N1qlTypeTest.create!(age: 20)
254
+ t2 = N1qlTypeTest.create!(age: 20)
255
+ _t3 = N1qlTypeTest.create!(age: 40)
256
+ expect(N1qlTypeTest.find_by_age(20).to_a).to match_array [t, t2]
257
+ end
258
+
259
+ it "should be able to query by integer and type cast" do
260
+ t = N1qlTypeTest.create!(age: "20")
261
+ expect(N1qlTypeTest.find_by_age(20).to_a).to eq [t]
262
+ expect(N1qlTypeTest.find_by_age("20").to_a).to eq [t]
263
+ end
264
+
265
+ it "should be able to query by date" do
266
+ t = N1qlTypeTest.create!(renewal_date: Date.today)
267
+ _t2 = N1qlTypeTest.create!(renewal_date: Date.today + 1)
268
+ expect(N1qlTypeTest.find_by_renewal_date(Date.today).to_a).to eq [t]
269
+ end
270
+
271
+ it "should be able to query by datetime" do
272
+ now = Time.now
273
+ t = N1qlTypeTest.create!(subscribed_at: now)
274
+ _t2 = N1qlTypeTest.create!(subscribed_at: now + 1)
275
+ expect(N1qlTypeTest.find_by_subscribed_at(now).to_a).to eq [t]
276
+ end
277
+
278
+ it "should be able to query by timestamp" do
279
+ now = Time.now
280
+ t = N1qlTypeTest.create!(some_time: now)
281
+ _t2 = N1qlTypeTest.create!(some_time: now + 1)
282
+ expect(N1qlTypeTest.find_by_some_time(now).to_a).to eq [t]
283
+ end
284
+
285
+ it "should be able to query by custom type" do
286
+ now = Time.now
287
+ t = N1qlTypeTest.create!(precision3_time: now)
288
+ _t2 = N1qlTypeTest.create!(precision3_time: now + 1)
289
+ expect(N1qlTypeTest.find_by_precision3_time(now).to_a).to eq [t]
290
+ end
291
+
292
+ it "should be able to query by boolean" do
293
+ t = N1qlTypeTest.create!(active: true)
294
+ _t2 = N1qlTypeTest.create!(active: false)
295
+ expect(N1qlTypeTest.find_by_active(true).to_a).to eq [t]
296
+ end
297
+
298
+ it "should be able to query by float" do
299
+ t = N1qlTypeTest.create!(size: 1.5)
300
+ _t2 = N1qlTypeTest.create!(size: 2.5)
301
+ expect(N1qlTypeTest.find_by_size(1.5).to_a).to eq [t]
302
+ end
303
+
304
+ it "should set datetime with precision" do
305
+ time = Time.at(1667499592.5170466123)
306
+ Timecop.freeze(time) do
307
+ test = TypeTest.create!(precision3_time: 1667499592.5170466123, some_time: 1667499592.5170466123, precision6_time: Time.now)
308
+
309
+ expect(test.created_at).to eq(time.floor(6))
310
+ expect(test.updated_at).to eq(time.floor(6))
311
+
312
+ expect(test.some_time).to eq(time.floor)
313
+ expect(test.precision3_time).to eq(time.floor(3))
314
+ expect(test.precision6_time).to eq(time.floor(6))
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,20 @@
1
+ require 'couchbase-orm/utilities/ignored_properties'
2
+
3
+ class DummyClass
4
+ extend CouchbaseOrm::IgnoredProperties
5
+ end
6
+
7
+ class DummyClass2
8
+ extend CouchbaseOrm::IgnoredProperties
9
+ end
10
+
11
+ RSpec.describe CouchbaseOrm::IgnoredProperties do
12
+
13
+ describe '#ignored_properties=' do
14
+ it 'does not mixup ignored properties between classes' do
15
+ DummyClass.ignored_properties = [:property1, :property2]
16
+ expect(DummyClass.ignored_properties).to eq(['property1', 'property2'])
17
+ expect(DummyClass2.ignored_properties).to be_empty
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ require 'couchbase-orm/utilities/properties_always_exists_in_document'
2
+
3
+ class DummyClass
4
+ extend CouchbaseOrm::PropertiesAlwaysExistsInDocument
5
+ end
6
+
7
+ class DummyClass2
8
+ extend CouchbaseOrm::PropertiesAlwaysExistsInDocument
9
+ end
10
+
11
+ RSpec.describe CouchbaseOrm::PropertiesAlwaysExistsInDocument do
12
+
13
+ describe '#properties_always_exists_in_document=' do
14
+ it 'Checks properties_always_exists_in_document value when initialize or not' do
15
+ DummyClass.properties_always_exists_in_document = true
16
+ expect(DummyClass.properties_always_exists_in_document).to be(true)
17
+ expect(DummyClass2.properties_always_exists_in_document).to be(false)
18
+ end
19
+
20
+ it 'raises error when a non boolean value is passed' do
21
+ expect { DummyClass.properties_always_exists_in_document = 'toto' }.to raise_error(ArgumentError)
22
+ end
23
+ end
24
+ end
data/spec/views_spec.rb CHANGED
@@ -7,21 +7,41 @@ class ViewTest < CouchbaseOrm::Base
7
7
  attribute :name, type: String
8
8
  enum rating: [:awesome, :good, :okay, :bad], default: :okay
9
9
 
10
- view :all
11
- view :by_rating, emit_key: :rating
10
+ view :vall
12
11
 
13
12
  # This generates both:
14
- # view :by_rating, emit_key: :rating # same as above
13
+ # view :by_rating, emit_key: :rating
15
14
  # def self.find_by_rating(rating); end # also provide this helper function
16
15
  index_view :rating
17
16
  end
18
17
 
19
18
 
20
19
  describe CouchbaseOrm::Views do
20
+ before(:each) do
21
+ ViewTest.delete_all
22
+ rescue Couchbase::Error::DesignDocumentNotFound
23
+ # ignore (FIXME: check before merge) mainly because if there is nothing in all we should not have an error
24
+ end
25
+
26
+ after(:each) do
27
+ ViewTest.delete_all
28
+ rescue Couchbase::Error::InternalServerFailure
29
+ # ignore (FIXME: check before merge)
30
+ rescue Couchbase::Error::DesignDocumentNotFound
31
+ # ignore (FIXME: check before merge) (7.1)
32
+ end
33
+
34
+ it "should not allow n1ql to override existing methods" do
35
+ expect { ViewTest.view :all }.to raise_error(ArgumentError)
36
+ end
37
+
21
38
  it "should save a new design document" do
22
39
  begin
23
- ViewTest.bucket.delete_design_doc(ViewTest.design_document)
24
- rescue Libcouchbase::Error::HttpResponseError
40
+ ViewTest.bucket.view_indexes.drop_design_document(ViewTest.design_document, :production)
41
+ rescue Couchbase::Error::InternalServerFailure
42
+ # ignore if design document does not exist
43
+ rescue Couchbase::Error::DesignDocumentNotFound
44
+ # ignore if design document does not exist (7.1)
25
45
  end
26
46
  expect(ViewTest.ensure_design_document!).to be(true)
27
47
  end
@@ -29,12 +49,16 @@ describe CouchbaseOrm::Views do
29
49
  it "should not re-save a design doc if nothing has changed" do
30
50
  expect(ViewTest.ensure_design_document!).to be(false)
31
51
  end
52
+
53
+ it "should return an empty array when there is no objects" do
54
+ expect(ViewTest.vall).to eq([])
55
+ end
32
56
 
33
57
  it "should perform a map-reduce and return the view" do
34
58
  ViewTest.ensure_design_document!
35
- mod = ViewTest.create! name: :bob, rating: :good
59
+ ViewTest.create! name: :bob, rating: :good
36
60
 
37
- docs = ViewTest.all.collect { |ob|
61
+ docs = ViewTest.vall.collect { |ob|
38
62
  ob.destroy
39
63
  ob.name
40
64
  }
@@ -47,7 +71,7 @@ describe CouchbaseOrm::Views do
47
71
  ViewTest.create! name: :jane, rating: :awesome
48
72
  ViewTest.create! name: :greg, rating: :bad
49
73
 
50
- docs = ViewTest.by_rating(descending: :true).collect { |ob|
74
+ docs = ViewTest.by_rating(order: :descending).collect { |ob|
51
75
  ob.destroy
52
76
  ob.name
53
77
  }
@@ -64,9 +88,6 @@ describe CouchbaseOrm::Views do
64
88
  docs = ViewTest.find_by_rating(1).collect { |ob|
65
89
  ob.name
66
90
  }
67
- ViewTest.all.stream { |ob|
68
- ob.destroy
69
- }
70
91
 
71
92
  expect(Set.new(docs)).to eq(Set.new(['bob', 'jane']))
72
93
  end