couch_potato 1.7.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +50 -0
  3. data/.gitignore +3 -0
  4. data/CHANGES.md +180 -130
  5. data/Gemfile +4 -0
  6. data/README.md +61 -85
  7. data/Rakefile +11 -10
  8. data/couch_potato-rspec.gemspec +2 -1
  9. data/couch_potato.gemspec +9 -7
  10. data/gemfiles/active_support_5_0 +6 -0
  11. data/gemfiles/active_support_5_1 +7 -0
  12. data/gemfiles/active_support_5_2 +6 -0
  13. data/gemfiles/active_support_6_0 +6 -0
  14. data/gemfiles/active_support_6_1 +6 -0
  15. data/gemfiles/active_support_7_0 +6 -0
  16. data/lib/couch_potato/database.rb +170 -71
  17. data/lib/couch_potato/persistence/dirty_attributes.rb +3 -21
  18. data/lib/couch_potato/persistence/magic_timestamps.rb +3 -3
  19. data/lib/couch_potato/persistence/properties.rb +15 -10
  20. data/lib/couch_potato/persistence/simple_property.rb +0 -4
  21. data/lib/couch_potato/persistence/type_caster.rb +11 -6
  22. data/lib/couch_potato/persistence.rb +0 -1
  23. data/lib/couch_potato/railtie.rb +6 -11
  24. data/lib/couch_potato/validation.rb +8 -0
  25. data/lib/couch_potato/version.rb +2 -2
  26. data/lib/couch_potato/view/base_view_spec.rb +8 -32
  27. data/lib/couch_potato/view/custom_views.rb +4 -3
  28. data/lib/couch_potato/view/flex_view_spec.rb +121 -0
  29. data/lib/couch_potato/view/view_parameters.rb +34 -0
  30. data/lib/couch_potato.rb +37 -16
  31. data/spec/callbacks_spec.rb +45 -19
  32. data/spec/conflict_handling_spec.rb +1 -2
  33. data/spec/property_spec.rb +12 -3
  34. data/spec/railtie_spec.rb +10 -0
  35. data/spec/spec_helper.rb +4 -3
  36. data/spec/unit/active_model_compliance_spec.rb +7 -3
  37. data/spec/unit/attributes_spec.rb +54 -1
  38. data/spec/unit/caching_spec.rb +105 -0
  39. data/spec/unit/couch_potato_spec.rb +70 -5
  40. data/spec/unit/create_spec.rb +5 -4
  41. data/spec/unit/database_spec.rb +239 -135
  42. data/spec/unit/dirty_attributes_spec.rb +5 -26
  43. data/spec/unit/flex_view_spec_spec.rb +17 -0
  44. data/spec/unit/model_view_spec_spec.rb +1 -1
  45. data/spec/unit/rspec_stub_db_spec.rb +31 -0
  46. data/spec/unit/validation_spec.rb +42 -2
  47. data/spec/unit/view_query_spec.rb +12 -7
  48. data/spec/views_spec.rb +214 -103
  49. data/vendor/pouchdb-collate/LICENSE +202 -0
  50. data/vendor/pouchdb-collate/pouchdb-collate.js +430 -0
  51. metadata +47 -36
  52. data/.ruby-version +0 -1
  53. data/.travis.yml +0 -21
  54. data/gemfiles/active_support_4_0 +0 -11
  55. data/gemfiles/active_support_4_1 +0 -11
  56. data/gemfiles/active_support_4_2 +0 -11
  57. data/lib/couch_potato/persistence/deep_dirty_attributes.rb +0 -180
  58. data/spec/unit/deep_dirty_attributes_spec.rb +0 -434
@@ -1,434 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class Cover
4
- include CouchPotato::Persistence
5
-
6
- def initialize(*args)
7
- self._id = SecureRandom.uuid
8
- super
9
- end
10
-
11
- property :color
12
- end
13
-
14
- class Page
15
- include CouchPotato::Persistence
16
-
17
- def initialize(*args)
18
- self._id = SecureRandom.uuid
19
- super
20
- end
21
-
22
- property :number
23
- property :headline
24
- end
25
-
26
- class Book
27
- include CouchPotato::Persistence
28
- include CouchPotato::Persistence::DeepDirtyAttributes
29
-
30
- property :title
31
- property :cover, :type => Cover
32
- property :authors, :type => [String]
33
- property :pages, :type => [Page]
34
- end
35
-
36
- class TextBook < Book
37
- property :edition
38
- end
39
-
40
- describe "deep dirty attribute tracking" do
41
- describe "standard dirty checking" do
42
- describe "_changed?" do
43
- it "should return true if only root simple properties have changed" do
44
- book = Book.new(:title => "A")
45
- book.title = "B"
46
- expect(book).to be_title_changed
47
- expect(book).to be_changed
48
- end
49
- end
50
-
51
- describe "_was" do
52
- it "gives access to old values of simple root properties" do
53
- book = Book.new(:title => "A")
54
- book.title = "B"
55
- expect(book.title_was).to eq("A")
56
- expect(book.title_change).to eq(["A", "B"])
57
- end
58
- end
59
-
60
- describe "_change" do
61
- it "returns standard _change" do
62
- book = Book.new(:title => "A")
63
- book.title = "B"
64
- expect(book.title_change).to eq(["A", "B"])
65
- end
66
- end
67
- end
68
-
69
- describe "single nested document" do
70
- describe "_changed?" do
71
- it "should return true if a nested attribute has changed" do
72
- book = Book.new(:cover => Cover.new(:color => "red"))
73
- book.cover.color = "blue"
74
- expect(book).to be_cover_changed
75
- expect(book).to be_changed
76
- end
77
-
78
- it "should return true if changed to a different document" do
79
- book = Book.new(:cover => Cover.new(:color => "red"))
80
- book.cover = Cover.new(:color => "blue")
81
- expect(book).to be_cover_changed
82
- expect(book).to be_changed
83
- end
84
-
85
- it "should return false if changed to a clone of the original document" do
86
- book = Book.new(:cover => Cover.new(:color => "red"))
87
- book.cover = book.cover.clone
88
- expect(book).not_to be_cover_changed
89
- expect(book).not_to be_changed
90
- end
91
-
92
- it "should return false if set to nil and unchanged" do
93
- book = Book.new
94
- expect(book).not_to be_cover_changed
95
- expect(book).not_to be_changed
96
- end
97
-
98
- it "should return true when reassigned with changes but the same _id" do
99
- book = Book.new(:cover => Cover.new(:_id => "cid", :color => "red"))
100
- book.cover = Cover.new(:_id => "cid", :color => "blue")
101
- expect(book).to be_cover_changed
102
- expect(book).to be_changed
103
- end
104
- end
105
-
106
- describe "_was" do
107
- it "gives access to the old value" do
108
- book = Book.new(:cover => Cover.new(:color => "red"))
109
- book.cover.color = "blue"
110
- expect(book.cover_was.color).to eq("red")
111
- end
112
- end
113
-
114
- describe "_change" do
115
- it "should return the standard changes when a nested document is reassigned" do
116
- book = Book.new(:cover => Cover.new(:color => "red"))
117
- book.cover = Cover.new(:color => "blue")
118
- expect(book.cover_change[0]).to be_a Cover
119
- expect(book.cover_change[0].color).to eq("red")
120
- expect(book.cover_change[1]).to be_a Cover
121
- expect(book.cover_change[1].color).to eq("blue")
122
- end
123
-
124
- it "should return the standard changes when a nested document is reassigned from nil" do
125
- book = Book.new
126
- book.cover = Cover.new
127
- expect(book.cover_change[0]).to eq(nil)
128
- expect(book.cover_change[1]).to eq(book.cover)
129
- end
130
-
131
- it "should return the standard changes when a nested document is reassigned to nil" do
132
- cover = Cover.new
133
- book = Book.new(:cover => cover)
134
- book.cover = nil
135
- expect(book.cover_change[0]).to eq(cover)
136
- expect(book.cover_change[1]).to eq(nil)
137
- end
138
-
139
- it "should return the nested changes when a nested document is changed" do
140
- book = Book.new(:cover => Cover.new(:color => "red"))
141
- book.cover.color = "blue"
142
- expect(book.cover_change[0]).to be_a Cover
143
- expect(book.cover_change[0].color).to eq("red")
144
- expect(book.cover_change[1]).to eq(book.cover.changes)
145
- end
146
-
147
- it "should return the nested changes when reassigned with changes but the same _id" do
148
- book = Book.new(:cover => Cover.new(:_id => "cid", :color => "red"))
149
- book.cover = Cover.new(:_id => "cid", :color => "blue")
150
- expect(book.cover_change[0]).to be_a Cover
151
- expect(book.cover_change[0].color).to eq("red")
152
- expect(book.cover_change[1]).to eq({"color" => ["red", "blue"]})
153
- end
154
- end
155
- end
156
-
157
- describe "simple array" do
158
- describe "_changed?" do
159
- it "returns true if the array is reassigned" do
160
- book = Book.new(:authors => ["Sarah"])
161
- book.authors = ["Jane"]
162
- expect(book).to be_authors_changed
163
- end
164
-
165
- it "returns true if an item is added" do
166
- book = Book.new(:authors => ["Jane"])
167
- book.authors << "Sue"
168
- expect(book).to be_authors_changed
169
- expect(book).to be_changed
170
- end
171
-
172
- it "returns true if an item is removed" do
173
- book = Book.new(:authors => ["Sue"])
174
- book.authors.delete "Sue"
175
- expect(book).to be_authors_changed
176
- expect(book).to be_changed
177
- end
178
-
179
- it "returns false if an empty array is unchanged" do
180
- book = Book.new(:authors => [])
181
- book.authors = []
182
- expect(book).not_to be_authors_changed
183
- expect(book).not_to be_changed
184
- end
185
- end
186
-
187
- describe "_was" do
188
- it "gives access to the old values" do
189
- book = Book.new(:authors => ["Jane"])
190
- book.authors << "Sue"
191
- expect(book.authors_was).to eq(["Jane"])
192
- end
193
- end
194
-
195
- describe "_change" do
196
- it "returns a hash of added and removed items" do
197
- book = Book.new(:authors => ["Jane"])
198
- book.authors << "Sue"
199
- book.authors.delete "Jane"
200
- expect(book.authors_change[0]).to eq(["Jane"])
201
- expect(book.authors_change[1]).to be_a HashWithIndifferentAccess
202
- expect(book.authors_change[1][:added]).to eq(["Sue"])
203
- expect(book.authors_change[1][:removed]).to eq(["Jane"])
204
- end
205
-
206
- it "returns a hash of added and removed items when the array is reassigned" do
207
- book = Book.new(:authors => ["Jane"])
208
- book.authors = ["Sue"]
209
- expect(book.authors_change[0]).to eq(["Jane"])
210
- expect(book.authors_change[1]).to be_a HashWithIndifferentAccess
211
- expect(book.authors_change[1][:added]).to eq(["Sue"])
212
- expect(book.authors_change[1][:removed]).to eq(["Jane"])
213
- end
214
-
215
- it "returns a hash of added items when the value is changed from nil to an array" do
216
- book = Book.new
217
- book.authors = ["Sue"]
218
- expect(book.authors_change[0]).to eq([])
219
- expect(book.authors_change[1]).to be_a HashWithIndifferentAccess
220
- expect(book.authors_change[1][:added]).to eq(["Sue"])
221
- expect(book.authors_change[1][:removed]).to eq([])
222
- end
223
-
224
- it "returns a hash of removed items when the value is changed from an array to nil" do
225
- book = Book.new(:authors => ["Jane"])
226
- book.authors = nil
227
- expect(book.authors_change[0]).to eq(["Jane"])
228
- expect(book.authors_change[1]).to be_a HashWithIndifferentAccess
229
- expect(book.authors_change[1][:added]).to eq([])
230
- expect(book.authors_change[1][:removed]).to eq(["Jane"])
231
- end
232
- end
233
- end
234
-
235
- describe "document array" do
236
- describe "_changed?" do
237
- it "returns true if an item is changed" do
238
- book = Book.new(:pages => [Page.new(:number => 1)])
239
- book.pages[0].number = 2
240
- expect(book).to be_pages_changed
241
- expect(book).to be_changed
242
- end
243
-
244
- it "returns true if an item is added" do
245
- book = Book.new(:pages => [Page.new(:number => 1)])
246
- book.pages << Page.new(:number => 2)
247
- expect(book).to be_pages_changed
248
- expect(book).to be_changed
249
- end
250
-
251
- it "returns true if an items is removed" do
252
- book = Book.new(:pages => [Page.new(:number => 1)])
253
- book.pages.delete_at 0
254
- expect(book).to be_pages_changed
255
- expect(book).to be_changed
256
- end
257
-
258
- it "returns true if an item is replaced" do
259
- book = Book.new(:pages => [Page.new(:number => 1)])
260
- book.pages[0] = Page.new(:number => 2)
261
- expect(book).to be_pages_changed
262
- expect(book).to be_changed
263
- end
264
-
265
- it "returns false if an item is replaced with a clone" do
266
- book = Book.new(:pages => [Page.new(:number => 1)])
267
- book.pages[0] = book.pages[0].clone
268
- expect(book).not_to be_pages_changed
269
- expect(book).not_to be_changed
270
- end
271
-
272
- it "returns true if an item is replaced with changes but the same _id" do
273
- book = Book.new(:pages => [Page.new(:_id => "pid", :number => 1)])
274
- book.pages[0] = Page.new(:_id => "pid", :number => 2)
275
- expect(book).to be_pages_changed
276
- expect(book).to be_changed
277
- end
278
-
279
- it "returns false if an empty array is unchanged" do
280
- book = Book.new(:pages => [])
281
- book.pages = []
282
- expect(book).not_to be_authors_changed
283
- expect(book).not_to be_changed
284
- end
285
- end
286
-
287
- describe "_was" do
288
- it "gives access to the old values" do
289
- book = Book.new(:pages => [Page.new(:number => 1)])
290
- book.pages[0].number = 2
291
- expect(book.pages_was[0].number).to eq(1)
292
- end
293
- end
294
-
295
- describe "_change" do
296
- it "returns a changes hash with added, removed, and changed items" do
297
- p1 = Page.new
298
- p2 = Page.new(:headline => "A")
299
- p3 = Page.new
300
- book = Book.new(:pages => [p1, p2])
301
- pages = book.pages.clone
302
- book.pages = [p2]
303
- p2.headline = "B"
304
- book.pages << p3
305
- expect(book.pages_change[0]).to eq(pages)
306
- expect(book.pages_change[1]).to be_a HashWithIndifferentAccess
307
- expect(book.pages_change[1][:added]).to eq([p3])
308
- expect(book.pages_change[1][:removed]).to eq([p1])
309
- expect(book.pages_change[1][:changed][0][0]).to be_a Page
310
- expect(book.pages_change[1][:changed][0][0].headline).to eq("A")
311
- expect(book.pages_change[1][:changed][0][1]).to eq(p2.changes)
312
- end
313
-
314
- it "returns added items when changing from nil to an array" do
315
- p1 = Page.new
316
- p2 = Page.new(:headline => "A")
317
- book = Book.new
318
- book.pages = [p1, p2]
319
- expect(book.pages_change[0]).to eq([])
320
- expect(book.pages_change[1]).to be_a HashWithIndifferentAccess
321
- expect(book.pages_change[1][:added]).to eq([p1, p2])
322
- expect(book.pages_change[1][:removed]).to eq([])
323
- expect(book.pages_change[1][:changed]).to eq([])
324
- end
325
-
326
- it "does not return unchanged cloned items as changes" do
327
- book = Book.new(:pages => [Page.new(:number => 1)])
328
- book.pages[0] = book.pages[0].clone
329
- expect(book.pages_change).to be_nil
330
- end
331
-
332
- it "returns changes if an item is replaced with changes but the same _id" do
333
- book = Book.new(:pages => [Page.new(:_id => "pid", :number => 1)])
334
- pages = book.pages.clone
335
- book.pages[0] = Page.new(:_id => "pid", :number => 2)
336
- expect(book.pages_change[0]).to eq(pages)
337
- expect(book.pages_change[1]).to be_a HashWithIndifferentAccess
338
- expect(book.pages_change[1][:added]).to eq([])
339
- expect(book.pages_change[1][:removed]).to eq([])
340
- expect(book.pages_change[1][:changed]).to eq([[pages[0], {"number" => [1, 2]}]])
341
- end
342
- end
343
- end
344
-
345
- describe "changes" do
346
- it "includes simple property changes" do
347
- book = Book.new(:title => "Title A")
348
- book.title = "Title B"
349
- expect(book.changes[:title]).to eq(book.title_change)
350
- end
351
-
352
- it "includes embedded document changes" do
353
- book = Book.new(:cover => Cover.new(:color => "red"))
354
- cover = book.cover.clone
355
- book.cover.color = "blue"
356
- expect(book.changes[:cover]).to eq(book.cover_change)
357
- end
358
-
359
- it "does not include unchanged embedded documents" do
360
- book = Book.new(:cover => Cover.new(:color => "red"))
361
- expect(book.changes).not_to have_key :cover
362
- end
363
-
364
- it "includes simple array changes" do
365
- book = Book.new(:authors => ["Sarah"])
366
- book.authors = ["Jane"]
367
- expect(book.changes[:authors]).to eq(book.authors_change)
368
- end
369
-
370
- it "does not include unchanged simple arrays" do
371
- book = Book.new(:authors => ["Sarah"])
372
- expect(book.changes).not_to have_key :authors
373
- end
374
-
375
- it "includes document array changes" do
376
- book = Book.new(:pages => [Page.new(:number => 1)])
377
- book.pages = [Page.new(:number => 2)]
378
- expect(book.changes[:pages]).to eq(book.pages_change)
379
- end
380
-
381
- it "does not include unchanged document arrays" do
382
- book = Book.new(:pages => [Page.new(:number => 1)])
383
- expect(book.changes).not_to have_key :pages
384
- end
385
- end
386
-
387
- describe "after save" do
388
- before :each do
389
- book = Book.json_create(:_id => "1", :title => "A", :cover => {:color => "red"}, :pages => [{:_id => "p1", :number => 1}, {:_id => "p2", :number => 2}])
390
- @couchrest_db = double('database', :info => nil, :save_doc => {}, :get => book)
391
- @db = CouchPotato::Database.new(@couchrest_db)
392
- @book = @db.load_document "1"
393
- end
394
-
395
- it "should reset all attributes to not dirty" do
396
- @book.title = "B"
397
- @book.cover.color = "blue"
398
- @db.save! @book
399
- expect(@book).not_to be_dirty
400
- expect(@book.cover).not_to be_dirty
401
- end
402
-
403
- it "should reset all elements in a document array" do
404
- @book.pages.each(&:is_dirty)
405
- @db.save! @book
406
- expect(@book).not_to be_dirty
407
- @book.pages.each do |page|
408
- expect(page).not_to be_dirty
409
- end
410
- end
411
-
412
- it "should reset a forced dirty state" do
413
- @book.is_dirty
414
- @db.save! @book
415
- expect(@book).not_to be_dirty
416
- end
417
-
418
- it "clears old values" do
419
- @book.cover.color = "blue"
420
- @db.save! @book
421
- expect(@book.cover_was).to be_nil
422
- expect(@book.cover_change).to be_nil
423
- end
424
- end
425
-
426
- describe "on inherited models" do
427
- it "still uses deep dirty tracking" do
428
- book = TextBook.new(:pages => [Page.new(:number => 1)])
429
- book.pages[0].number = 2
430
- expect(book).to be_pages_changed
431
- expect(book).to be_changed
432
- end
433
- end
434
- end