wcc-contentful 0.4.0.pre.alpha → 1.0.0.pre.rc3

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 (69) hide show
  1. checksums.yaml +5 -5
  2. data/Guardfile +43 -0
  3. data/README.md +246 -11
  4. data/Rakefile +5 -0
  5. data/app/controllers/wcc/contentful/webhook_controller.rb +25 -24
  6. data/app/jobs/wcc/contentful/webhook_enable_job.rb +36 -2
  7. data/config/routes.rb +1 -1
  8. data/doc +1 -0
  9. data/lib/tasks/download_schema.rake +12 -0
  10. data/lib/wcc/contentful.rb +70 -16
  11. data/lib/wcc/contentful/active_record_shim.rb +72 -0
  12. data/lib/wcc/contentful/configuration.rb +177 -46
  13. data/lib/wcc/contentful/content_type_indexer.rb +14 -0
  14. data/lib/wcc/contentful/downloads_schema.rb +112 -0
  15. data/lib/wcc/contentful/engine.rb +33 -14
  16. data/lib/wcc/contentful/event.rb +171 -0
  17. data/lib/wcc/contentful/events.rb +41 -0
  18. data/lib/wcc/contentful/exceptions.rb +3 -0
  19. data/lib/wcc/contentful/indexed_representation.rb +2 -2
  20. data/lib/wcc/contentful/instrumentation.rb +31 -0
  21. data/lib/wcc/contentful/link.rb +28 -0
  22. data/lib/wcc/contentful/link_visitor.rb +122 -0
  23. data/lib/wcc/contentful/middleware.rb +7 -0
  24. data/lib/wcc/contentful/middleware/store.rb +158 -0
  25. data/lib/wcc/contentful/middleware/store/caching_middleware.rb +114 -0
  26. data/lib/wcc/contentful/model.rb +37 -3
  27. data/lib/wcc/contentful/model_builder.rb +1 -0
  28. data/lib/wcc/contentful/model_methods.rb +40 -15
  29. data/lib/wcc/contentful/model_singleton_methods.rb +47 -30
  30. data/lib/wcc/contentful/rake.rb +4 -0
  31. data/lib/wcc/contentful/rspec.rb +46 -0
  32. data/lib/wcc/contentful/services.rb +61 -27
  33. data/lib/wcc/contentful/simple_client.rb +81 -25
  34. data/lib/wcc/contentful/simple_client/management.rb +43 -10
  35. data/lib/wcc/contentful/simple_client/response.rb +61 -22
  36. data/lib/wcc/contentful/simple_client/typhoeus_adapter.rb +17 -17
  37. data/lib/wcc/contentful/store.rb +7 -66
  38. data/lib/wcc/contentful/store/README.md +85 -0
  39. data/lib/wcc/contentful/store/base.rb +34 -119
  40. data/lib/wcc/contentful/store/cdn_adapter.rb +71 -12
  41. data/lib/wcc/contentful/store/factory.rb +186 -0
  42. data/lib/wcc/contentful/store/instrumentation.rb +55 -0
  43. data/lib/wcc/contentful/store/interface.rb +82 -0
  44. data/lib/wcc/contentful/store/memory_store.rb +27 -24
  45. data/lib/wcc/contentful/store/postgres_store.rb +268 -101
  46. data/lib/wcc/contentful/store/postgres_store/schema_1.sql +73 -0
  47. data/lib/wcc/contentful/store/postgres_store/schema_2.sql +21 -0
  48. data/lib/wcc/contentful/store/query.rb +246 -0
  49. data/lib/wcc/contentful/store/query/interface.rb +63 -0
  50. data/lib/wcc/contentful/store/rspec_examples.rb +48 -0
  51. data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +629 -0
  52. data/lib/wcc/contentful/store/rspec_examples/include_param.rb +283 -0
  53. data/lib/wcc/contentful/store/rspec_examples/nested_queries.rb +342 -0
  54. data/lib/wcc/contentful/sync_engine.rb +181 -0
  55. data/lib/wcc/contentful/test.rb +7 -0
  56. data/lib/wcc/contentful/test/attributes.rb +56 -0
  57. data/lib/wcc/contentful/test/double.rb +76 -0
  58. data/lib/wcc/contentful/test/factory.rb +101 -0
  59. data/lib/wcc/contentful/version.rb +1 -1
  60. data/wcc-contentful.gemspec +23 -11
  61. metadata +299 -116
  62. data/Gemfile +0 -6
  63. data/app/jobs/wcc/contentful/delayed_sync_job.rb +0 -63
  64. data/lib/wcc/contentful/client_ext.rb +0 -28
  65. data/lib/wcc/contentful/graphql.rb +0 -14
  66. data/lib/wcc/contentful/graphql/builder.rb +0 -177
  67. data/lib/wcc/contentful/graphql/types.rb +0 -54
  68. data/lib/wcc/contentful/simple_client/http_adapter.rb +0 -24
  69. data/lib/wcc/contentful/store/lazy_cache_store.rb +0 -161
@@ -0,0 +1,629 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/BlockDelimiters
4
+
5
+ RSpec.shared_examples 'basic store' do
6
+ let(:entry) do
7
+ JSON.parse(<<~JSON)
8
+ {
9
+ "sys": {
10
+ "space": {
11
+ "sys": {
12
+ "type": "Link",
13
+ "linkType": "Space",
14
+ "id": "343qxys30lid"
15
+ }
16
+ },
17
+ "id": "1qLdW7i7g4Ycq6i4Cckg44",
18
+ "type": "Entry",
19
+ "createdAt": "2018-03-09T23:39:27.737Z",
20
+ "updatedAt": "2018-03-09T23:39:27.737Z",
21
+ "revision": 1,
22
+ "contentType": {
23
+ "sys": {
24
+ "type": "Link",
25
+ "linkType": "ContentType",
26
+ "id": "redirect"
27
+ }
28
+ }
29
+ },
30
+ "fields": {
31
+ "slug": {
32
+ "en-US": "redirect-with-slug-and-url"
33
+ },
34
+ "url": {
35
+ "en-US": "http://www.google.com"
36
+ },
37
+ "page": {
38
+ "en-US": {
39
+ "sys": {
40
+ "type": "Link",
41
+ "linkType": "Entry",
42
+ "id": "2zKTmej544IakmIqoEu0y8"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ JSON
49
+ end
50
+
51
+ let(:page) do
52
+ JSON.parse(<<~JSON)
53
+ {
54
+ "sys": {
55
+ "space": {
56
+ "sys": {
57
+ "type": "Link",
58
+ "linkType": "Space",
59
+ "id": "343qxys30lid"
60
+ }
61
+ },
62
+ "id": "2zKTmej544IakmIqoEu0y8",
63
+ "type": "Entry",
64
+ "createdAt": "2018-03-09T23:39:27.737Z",
65
+ "updatedAt": "2018-03-09T23:39:27.737Z",
66
+ "revision": 1,
67
+ "contentType": {
68
+ "sys": {
69
+ "type": "Link",
70
+ "linkType": "ContentType",
71
+ "id": "page"
72
+ }
73
+ }
74
+ },
75
+ "fields": {
76
+ "slug": {
77
+ "en-US": "some-page"
78
+ },
79
+ "hero": {
80
+ "en-US": {
81
+ "sys": {
82
+ "type": "Link",
83
+ "linkType": "Asset",
84
+ "id": "3pWma8spR62aegAWAWacyA"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ JSON
91
+ end
92
+
93
+ let(:asset) do
94
+ JSON.parse(<<~JSON)
95
+ {
96
+ "sys": {
97
+ "space": {
98
+ "sys": {
99
+ "type": "Link",
100
+ "linkType": "Space",
101
+ "id": "343qxys30lid"
102
+ }
103
+ },
104
+ "id": "3pWma8spR62aegAWAWacyA",
105
+ "type": "Asset",
106
+ "createdAt": "2018-02-12T19:53:39.309Z",
107
+ "updatedAt": "2018-02-12T19:53:39.309Z",
108
+ "revision": 1
109
+ },
110
+ "fields": {
111
+ "title": {
112
+ "en-US": "apple-touch-icon"
113
+ },
114
+ "file": {
115
+ "en-US": {
116
+ "url": "//images.contentful.com/343qxys30lid/3pWma8spR62aegAWAWacyA/1beaebf5b66d2405ff9c9769a74db709/apple-touch-icon.png",
117
+ "details": {
118
+ "size": 40832,
119
+ "image": {
120
+ "width": 180,
121
+ "height": 180
122
+ }
123
+ },
124
+ "fileName": "apple-touch-icon.png",
125
+ "contentType": "image/png"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ JSON
131
+ end
132
+
133
+ before do
134
+ allow(WCC::Contentful).to receive(:types)
135
+ .and_return({
136
+ 'root' => double(fields: {
137
+ 'name' => double(name: 'name', type: :String, array: false),
138
+ 'link' => double(name: 'link', type: :Link, array: false),
139
+ 'links' => double(name: 'links', type: :Link, array: true)
140
+ }),
141
+ 'shallow' => double(fields: {
142
+ 'name' => double(name: 'name', type: :String, array: false)
143
+ }),
144
+ 'deep' => double(fields: {
145
+ 'name' => double(name: 'name', type: :String, array: false),
146
+ 'subLink' => double(name: 'subLink', type: :Link, array: false)
147
+ })
148
+ })
149
+ end
150
+
151
+ describe '#set/#find' do
152
+ describe 'ensures that the stored value is of type Hash' do
153
+ it 'should not raise an error if value is a Hash' do
154
+ data = { token: 'jenny_8675309' }
155
+
156
+ # assert
157
+ expect { subject.set('sync:token', data) }.to_not raise_error
158
+ end
159
+
160
+ it 'should raise an error if the value is not a Hash' do
161
+ data = 'jenny_8675309'
162
+ expect { subject.set('sync:token', data) }.to raise_error(ArgumentError)
163
+ end
164
+ end
165
+
166
+ it 'stores and finds data by ID' do
167
+ data = { 'key' => 'val', '1' => { 'deep' => 9 } }
168
+
169
+ # act
170
+ subject.set('1234', data)
171
+ found = subject.find('1234')
172
+
173
+ # assert
174
+ expect(found).to eq(data)
175
+ end
176
+
177
+ it 'find returns nil if key doesnt exist' do
178
+ data = { 'key' => 'val', '1' => { 'deep' => 9 } }
179
+ subject.set('1234', data)
180
+
181
+ # act
182
+ found = subject.find('asdf')
183
+
184
+ # assert
185
+ expect(found).to be_nil
186
+ end
187
+
188
+ it 'find accepts hint param' do
189
+ subject.set('1qLdW7i7g4Ycq6i4Cckg44', entry)
190
+ subject.set('3pWma8spR62aegAWAWacyA', asset)
191
+
192
+ # act
193
+ found_entry = subject.find('1qLdW7i7g4Ycq6i4Cckg44', hint: 'Entry')
194
+ found_asset = subject.find('3pWma8spR62aegAWAWacyA', hint: 'Asset')
195
+
196
+ # assert
197
+ expect(found_entry.dig('sys', 'id')).to eq(entry.dig('sys', 'id'))
198
+ expect(found_asset.dig('sys', 'id')).to eq(asset.dig('sys', 'id'))
199
+ end
200
+
201
+ it 'set returns prior value if exists' do
202
+ data = { 'key' => 'val', '1' => { 'deep' => 9 } }
203
+ data2 = { 'key' => 'val', '2' => { 'deep' => 11 } }
204
+
205
+ # act
206
+ prior1 = subject.set('1234', data)
207
+ prior2 = subject.set('1234', data2)
208
+
209
+ # assert
210
+ expect(prior1).to be_nil
211
+ expect(prior2).to eq(data)
212
+ expect(subject.find('1234')).to eq(data2)
213
+ end
214
+ end
215
+
216
+ describe '#delete' do
217
+ it 'deletes an item out of the store' do
218
+ data = { 'key' => 'val', '1' => { 'deep' => 9 } }
219
+ subject.set('9999', data)
220
+
221
+ # act
222
+ deleted = subject.delete('9999')
223
+
224
+ # assert
225
+ expect(deleted).to eq(data)
226
+ expect(subject.find('9999')).to be_nil
227
+ end
228
+
229
+ it "returns nil if item doesn't exist" do
230
+ data = { 'key' => 'val', '1' => { 'deep' => 9 } }
231
+ subject.set('9999', data)
232
+
233
+ # act
234
+ deleted = subject.delete('asdf')
235
+
236
+ # assert
237
+ expect(deleted).to be_nil
238
+ expect(subject.find('9999')).to eq(data)
239
+ end
240
+ end
241
+
242
+ describe '#index' do
243
+ let(:deleted_entry) do
244
+ JSON.parse(<<~JSON)
245
+ {
246
+ "sys": {
247
+ "space": {
248
+ "sys": {
249
+ "type": "Link",
250
+ "linkType": "Space",
251
+ "id": "343qxys30lid"
252
+ }
253
+ },
254
+ "id": "6HQsABhZDiWmi0ekCouUuy",
255
+ "type": "DeletedEntry",
256
+ "createdAt": "2018-03-13T19:45:44.454Z",
257
+ "updatedAt": "2018-03-13T19:45:44.454Z",
258
+ "deletedAt": "2018-03-13T19:45:44.454Z",
259
+ "environment": {
260
+ "sys": {
261
+ "type": "Link",
262
+ "linkType": "Environment",
263
+ "id": "98322ee2-6dee-4651-b3a5-743be50fb107"
264
+ }
265
+ },
266
+ "revision": 1
267
+ }
268
+ }
269
+ JSON
270
+ end
271
+
272
+ let(:deleted_asset) do
273
+ JSON.parse(<<~JSON)
274
+ {
275
+ "sys": {
276
+ "space": {
277
+ "sys": {
278
+ "type": "Link",
279
+ "linkType": "Space",
280
+ "id": "343qxys30lid"
281
+ }
282
+ },
283
+ "id": "3pWma8spR62aegAWAWacyA",
284
+ "type": "DeletedAsset",
285
+ "createdAt": "2018-03-20T18:44:58.270Z",
286
+ "updatedAt": "2018-03-20T18:44:58.270Z",
287
+ "deletedAt": "2018-03-20T18:44:58.270Z",
288
+ "environment": {
289
+ "sys": {
290
+ "type": "Link",
291
+ "linkType": "Environment",
292
+ "id": "98322ee2-6dee-4651-b3a5-743be50fb107"
293
+ }
294
+ },
295
+ "revision": 1
296
+ }
297
+ }
298
+ JSON
299
+ end
300
+
301
+ it 'stores an "Entry"' do
302
+ # act
303
+ prev = subject.index(entry)
304
+
305
+ # assert
306
+ expect(prev).to eq(entry)
307
+ expect(subject.find('1qLdW7i7g4Ycq6i4Cckg44', hint: 'Entry')).to eq(entry)
308
+ end
309
+
310
+ it 'updates an "Entry" when exists' do
311
+ existing = { 'test' => { 'data' => 'asdf' } }
312
+ subject.set('1qLdW7i7g4Ycq6i4Cckg44', existing)
313
+
314
+ # act
315
+ latest = subject.index(entry)
316
+
317
+ # assert
318
+ expect(latest).to eq(entry)
319
+ expect(subject.find('1qLdW7i7g4Ycq6i4Cckg44')).to eq(entry)
320
+ end
321
+
322
+ it 'does not overwrite an entry if revision is lower' do
323
+ initial = entry
324
+ updated = entry.deep_dup
325
+ updated['sys']['revision'] = 2
326
+ updated['fields']['slug']['en-US'] = 'test slug'
327
+
328
+ subject.index(updated)
329
+
330
+ # act
331
+ latest = subject.index(initial)
332
+
333
+ # assert
334
+ expect(latest).to eq(updated)
335
+ expect(subject.find('1qLdW7i7g4Ycq6i4Cckg44')).to eq(updated)
336
+ end
337
+
338
+ it 'stores an "Asset"' do
339
+ # act
340
+ latest = subject.index(asset)
341
+
342
+ # assert
343
+ expect(latest).to eq(asset)
344
+ expect(subject.find('3pWma8spR62aegAWAWacyA', hint: 'Asset')).to eq(asset)
345
+ end
346
+
347
+ it 'updates an "Asset" when exists' do
348
+ existing = { 'test' => { 'data' => 'asdf' } }
349
+ subject.set('3pWma8spR62aegAWAWacyA', existing)
350
+
351
+ # act
352
+ latest = subject.index(asset)
353
+
354
+ # assert
355
+ expect(latest).to eq(asset)
356
+ expect(subject.find('3pWma8spR62aegAWAWacyA')).to eq(asset)
357
+ end
358
+
359
+ it 'does not overwrite an asset if revision is lower' do
360
+ initial = asset
361
+ updated = asset.deep_dup
362
+ updated['sys']['revision'] = 2
363
+ updated['fields']['title']['en-US'] = 'test title'
364
+
365
+ subject.index(updated)
366
+
367
+ # act
368
+ latest = subject.index(initial)
369
+
370
+ # assert
371
+ expect(latest).to eq(updated)
372
+ expect(subject.find('3pWma8spR62aegAWAWacyA')).to eq(updated)
373
+ end
374
+
375
+ it 'removes a "DeletedEntry"' do
376
+ existing = { 'test' => { 'data' => 'asdf' } }
377
+ subject.set('6HQsABhZDiWmi0ekCouUuy', existing)
378
+
379
+ # act
380
+ latest = subject.index(deleted_entry)
381
+
382
+ # assert
383
+ expect(latest).to be_nil
384
+ expect(subject.find('6HQsABhZDiWmi0ekCouUuy')).to be_nil
385
+ end
386
+
387
+ it 'does not remove if "DeletedEntry" revision is lower' do
388
+ existing = entry
389
+ existing['sys']['id'] = deleted_entry.dig('sys', 'id')
390
+ existing['sys']['revision'] = deleted_entry.dig('sys', 'revision') + 1
391
+ subject.index(existing)
392
+
393
+ # act
394
+ latest = subject.index(deleted_entry)
395
+
396
+ # assert
397
+ expect(latest).to eq(existing)
398
+ expect(subject.find(deleted_entry.dig('sys', 'id'))).to eq(existing)
399
+ end
400
+
401
+ it 'removes a "DeletedAsset"' do
402
+ existing = { 'test' => { 'data' => 'asdf' } }
403
+ subject.set('3pWma8spR62aegAWAWacyA', existing)
404
+
405
+ # act
406
+ latest = subject.index(deleted_asset)
407
+
408
+ # assert
409
+ expect(latest).to be_nil
410
+ expect(subject.find('3pWma8spR62aegAWAWacyA')).to be_nil
411
+ end
412
+
413
+ it 'does not remove if "DeletedAsset" revision is lower' do
414
+ existing = asset
415
+ existing['sys']['id'] = deleted_asset.dig('sys', 'id')
416
+ existing['sys']['revision'] = deleted_asset.dig('sys', 'revision') + 1
417
+ subject.index(existing)
418
+
419
+ # act
420
+ latest = subject.index(deleted_asset)
421
+
422
+ # assert
423
+ expect(latest).to eq(existing)
424
+ expect(subject.find(deleted_asset.dig('sys', 'id'))).to eq(existing)
425
+ end
426
+ end
427
+
428
+ describe '#find_by' do
429
+ it 'finds first of content type' do
430
+ content_types = %w[test1 test2 test3 test4]
431
+ data =
432
+ 1.upto(10).map do |i|
433
+ {
434
+ 'sys' => {
435
+ 'id' => "k#{i}",
436
+ 'contentType' => { 'sys' => { 'id' => content_types[i % content_types.length] } }
437
+ },
438
+ 'fields' => { 'name' => { 'en-US' => "test#{i}" } }
439
+ }
440
+ end
441
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
442
+
443
+ # act
444
+ found = subject.find_by(content_type: 'test3')
445
+
446
+ # assert
447
+ # expect one of these, but order is not defined
448
+ expect(%w[k2 k6 k10]).to include(found.dig('sys', 'id'))
449
+ end
450
+
451
+ it 'returns nil when cant find content type' do
452
+ content_types = %w[test1]
453
+ data =
454
+ 1.upto(4).map do |i|
455
+ {
456
+ 'sys' => {
457
+ 'id' => "k#{i}",
458
+ 'contentType' => { 'sys' => { 'id' => content_types[i % content_types.length] } }
459
+ },
460
+ 'fields' => { 'name' => { 'en-US' => "test#{i}" } }
461
+ }
462
+ end
463
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
464
+
465
+ # act
466
+ nonexistent_content_type = subject.find_by(content_type: 'test2')
467
+
468
+ # assert
469
+ expect(nonexistent_content_type).to be nil
470
+ end
471
+
472
+ it 'can apply filter object' do
473
+ data =
474
+ 1.upto(10).map do |i|
475
+ {
476
+ 'sys' => { 'id' => "k#{i}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
477
+ 'fields' => { 'name' => { 'en-US' => "test#{i}" } }
478
+ }
479
+ end
480
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
481
+
482
+ # act
483
+ found = subject.find_by(content_type: 'test1', filter: { 'name' => 'test4' })
484
+
485
+ # assert
486
+ expect(found).to_not be_nil
487
+ expect(found['sys']['id']).to eq('k4')
488
+ end
489
+
490
+ it 'can find by ID directly' do
491
+ [entry, page, asset].each { |d| subject.set(d.dig('sys', 'id'), d) }
492
+
493
+ # act
494
+ found = subject.find_by(content_type: 'Asset', filter: { id: '3pWma8spR62aegAWAWacyA' })
495
+
496
+ # assert
497
+ expect(found).to eq(asset)
498
+ end
499
+
500
+ it 'filter object can find value in array' do
501
+ content_types = %w[test1 test2 test3 test4]
502
+ data =
503
+ 1.upto(10).map do |i|
504
+ {
505
+ 'sys' => {
506
+ 'id' => "k#{i}",
507
+ 'contentType' => { 'sys' => { 'id' => content_types[i % content_types.length] } }
508
+ },
509
+ 'fields' => { 'name' => { 'en-US' => ["test#{i}", "test_2_#{i}"] } }
510
+ }
511
+ end
512
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
513
+
514
+ # act
515
+ found = subject.find_by(content_type: 'test2', filter: { 'name' => { eq: 'test_2_5' } })
516
+
517
+ # assert
518
+ expect(found).to_not be_nil
519
+ expect(found.dig('sys', 'id')).to eq('k5')
520
+ end
521
+
522
+ it 'allows properties named `*sys*`' do
523
+ %w[One Two].each do |field|
524
+ subject.set("id#{field}", {
525
+ 'sys' => {
526
+ 'id' => "id#{field}",
527
+ 'contentType' => {
528
+ 'sys' => {
529
+ 'id' => 'system'
530
+ }
531
+ }
532
+ },
533
+ 'fields' => {
534
+ 'system' => {
535
+ 'en-US' => field
536
+ }
537
+ }
538
+ })
539
+ end
540
+
541
+ # act
542
+ found = subject.find_by(content_type: 'system', filter: { system: 'Two' })
543
+
544
+ # assert
545
+ expect(found).to_not be_nil
546
+ expect(found.dig('sys', 'id')).to eq('idTwo')
547
+ expect(found.dig('fields', 'system', 'en-US')).to eq('Two')
548
+ end
549
+ end
550
+
551
+ describe '#find_all' do
552
+ it 'find_all can apply filter query' do
553
+ data =
554
+ 1.upto(10).map do |i|
555
+ {
556
+ 'sys' => { 'id' => "k#{i}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
557
+ 'fields' => { 'name' => { 'en-US' => "test#{i}" } }
558
+ }
559
+ end
560
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
561
+
562
+ # act
563
+ found = subject.find_all(content_type: 'test1').eq('name', 'test4')
564
+
565
+ # assert
566
+ expect(found.count).to eq(1)
567
+ expect(found.first['sys']['id']).to eq('k4')
568
+ end
569
+
570
+ it 'find_all filters on content type' do
571
+ content_types = %w[test1 test2 test3 test4]
572
+ data =
573
+ 1.upto(10).map do |i|
574
+ {
575
+ 'sys' => {
576
+ 'id' => "k#{i}",
577
+ 'contentType' => { 'sys' => { 'id' => content_types[i % content_types.length] } }
578
+ },
579
+ 'fields' => { 'name' => { 'en-US' => "test#{i}" } }
580
+ }
581
+ end
582
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
583
+
584
+ # act
585
+ found = subject.find_all(content_type: 'test2').to_a
586
+
587
+ # assert
588
+ expect(found.count).to eq(3)
589
+ expect(found.map { |d| d.dig('sys', 'id') }).to eq(
590
+ %w[k1 k5 k9]
591
+ )
592
+ end
593
+
594
+ it 'filter query eq can find value in array' do
595
+ content_types = %w[test1 test2 test3 test4]
596
+ data =
597
+ 1.upto(10).map do |i|
598
+ {
599
+ 'sys' => {
600
+ 'id' => "k#{i}",
601
+ 'contentType' => { 'sys' => { 'id' => content_types[i % content_types.length] } }
602
+ },
603
+ 'fields' => { 'name' => { 'en-US' => ["test#{i}", "test_2_#{i}"] } }
604
+ }
605
+ end
606
+ data.each { |d| subject.set(d.dig('sys', 'id'), d) }
607
+
608
+ # act
609
+ found = subject.find_all(content_type: 'test2')
610
+ .apply('name' => { eq: 'test_2_5' })
611
+
612
+ # assert
613
+ expect(found.count).to eq(1)
614
+ expect(found.first.dig('sys', 'id')).to eq('k5')
615
+ end
616
+ end
617
+
618
+ def make_link_to(id, link_type = 'Entry')
619
+ {
620
+ 'sys' => {
621
+ 'type' => 'Link',
622
+ 'linkType' => link_type,
623
+ 'id' => id
624
+ }
625
+ }
626
+ end
627
+ end
628
+
629
+ # rubocop:enable Style/BlockDelimiters