couchbase-orm 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) 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/README.md +237 -31
  8. data/ci/run_couchbase.sh +22 -0
  9. data/couchbase-orm.gemspec +26 -20
  10. data/lib/couchbase-orm/active_record_compat.rb +92 -0
  11. data/lib/couchbase-orm/associations.rb +119 -0
  12. data/lib/couchbase-orm/base.rb +143 -166
  13. data/lib/couchbase-orm/changeable.rb +512 -0
  14. data/lib/couchbase-orm/connection.rb +28 -8
  15. data/lib/couchbase-orm/encrypt.rb +48 -0
  16. data/lib/couchbase-orm/error.rb +17 -2
  17. data/lib/couchbase-orm/inspectable.rb +37 -0
  18. data/lib/couchbase-orm/json_schema/json_validation_error.rb +13 -0
  19. data/lib/couchbase-orm/json_schema/loader.rb +47 -0
  20. data/lib/couchbase-orm/json_schema/validation.rb +18 -0
  21. data/lib/couchbase-orm/json_schema/validator.rb +45 -0
  22. data/lib/couchbase-orm/json_schema.rb +9 -0
  23. data/lib/couchbase-orm/json_transcoder.rb +27 -0
  24. data/lib/couchbase-orm/locale/en.yml +5 -0
  25. data/lib/couchbase-orm/n1ql.rb +133 -0
  26. data/lib/couchbase-orm/persistence.rb +61 -52
  27. data/lib/couchbase-orm/proxies/bucket_proxy.rb +36 -0
  28. data/lib/couchbase-orm/proxies/collection_proxy.rb +52 -0
  29. data/lib/couchbase-orm/proxies/n1ql_proxy.rb +40 -0
  30. data/lib/couchbase-orm/proxies/results_proxy.rb +23 -0
  31. data/lib/couchbase-orm/railtie.rb +6 -17
  32. data/lib/couchbase-orm/relation.rb +249 -0
  33. data/lib/couchbase-orm/strict_loading.rb +21 -0
  34. data/lib/couchbase-orm/timestamps/created.rb +20 -0
  35. data/lib/couchbase-orm/timestamps/updated.rb +21 -0
  36. data/lib/couchbase-orm/timestamps.rb +15 -0
  37. data/lib/couchbase-orm/types/array.rb +32 -0
  38. data/lib/couchbase-orm/types/date.rb +9 -0
  39. data/lib/couchbase-orm/types/date_time.rb +14 -0
  40. data/lib/couchbase-orm/types/encrypted.rb +17 -0
  41. data/lib/couchbase-orm/types/nested.rb +43 -0
  42. data/lib/couchbase-orm/types/timestamp.rb +18 -0
  43. data/lib/couchbase-orm/types.rb +20 -0
  44. data/lib/couchbase-orm/utilities/enum.rb +13 -1
  45. data/lib/couchbase-orm/utilities/has_many.rb +72 -36
  46. data/lib/couchbase-orm/utilities/ignored_properties.rb +15 -0
  47. data/lib/couchbase-orm/utilities/index.rb +18 -20
  48. data/lib/couchbase-orm/utilities/properties_always_exists_in_document.rb +16 -0
  49. data/lib/couchbase-orm/utilities/query_helper.rb +148 -0
  50. data/lib/couchbase-orm/utils.rb +25 -0
  51. data/lib/couchbase-orm/version.rb +1 -1
  52. data/lib/couchbase-orm/views.rb +38 -41
  53. data/lib/couchbase-orm.rb +44 -9
  54. data/lib/ext/query_n1ql.rb +124 -0
  55. data/lib/rails/generators/couchbase_orm/config/templates/couchbase.yml +3 -2
  56. data/spec/associations_spec.rb +219 -50
  57. data/spec/base_spec.rb +296 -14
  58. data/spec/collection_proxy_spec.rb +29 -0
  59. data/spec/connection_spec.rb +27 -0
  60. data/spec/couchbase-orm/active_record_compat_spec.rb +24 -0
  61. data/spec/couchbase-orm/changeable_spec.rb +16 -0
  62. data/spec/couchbase-orm/json_schema/validation_spec.rb +23 -0
  63. data/spec/couchbase-orm/json_schema/validator_spec.rb +13 -0
  64. data/spec/couchbase-orm/timestamps_spec.rb +85 -0
  65. data/spec/couchbase-orm/timestamps_spec_models.rb +36 -0
  66. data/spec/empty-json-schema/.gitkeep +0 -0
  67. data/spec/enum_spec.rb +34 -0
  68. data/spec/has_many_spec.rb +101 -54
  69. data/spec/index_spec.rb +13 -9
  70. data/spec/json-schema/JsonSchemaBaseTest.json +19 -0
  71. data/spec/json-schema/entity_snakecase.json +20 -0
  72. data/spec/json-schema/loader_spec.rb +42 -0
  73. data/spec/json-schema/specific_path.json +20 -0
  74. data/spec/json_schema_spec.rb +178 -0
  75. data/spec/n1ql_spec.rb +193 -0
  76. data/spec/persistence_spec.rb +49 -9
  77. data/spec/relation_nested_spec.rb +88 -0
  78. data/spec/relation_spec.rb +430 -0
  79. data/spec/support.rb +16 -8
  80. data/spec/type_array_spec.rb +52 -0
  81. data/spec/type_encrypted_spec.rb +114 -0
  82. data/spec/type_nested_spec.rb +191 -0
  83. data/spec/type_spec.rb +317 -0
  84. data/spec/utilities/ignored_properties_spec.rb +20 -0
  85. data/spec/utilities/properties_always_exists_in_document_spec.rb +24 -0
  86. data/spec/views_spec.rb +32 -11
  87. metadata +192 -29
@@ -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