cozy-pouch-link 48.25.0 → 49.0.0
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.
- package/dist/CozyPouchLink.js +593 -237
- package/dist/CozyPouchLink.spec.js +67 -42
- package/dist/PouchManager.js +317 -254
- package/dist/PouchManager.spec.js +91 -58
- package/dist/helpers.js +79 -0
- package/dist/helpers.spec.js +85 -1
- package/dist/jsonapi.js +54 -7
- package/dist/jsonapi.spec.js +57 -14
- package/dist/localStorage.js +646 -207
- package/dist/localStorage.spec.js +48 -0
- package/dist/mango.js +72 -20
- package/dist/mango.spec.js +1 -1
- package/dist/migrations/adapter.js +1 -1
- package/dist/platformWeb.js +120 -0
- package/dist/remote.js +39 -5
- package/dist/remote.spec.js +214 -0
- package/dist/replicateOnce.js +337 -0
- package/dist/startReplication.js +70 -45
- package/dist/startReplication.spec.js +374 -39
- package/dist/types.js +80 -0
- package/dist/utils.js +11 -2
- package/package.json +9 -5
- package/types/AccessToken.d.ts +16 -0
- package/types/CozyPouchLink.d.ts +228 -0
- package/types/PouchManager.d.ts +86 -0
- package/types/__tests__/fixtures.d.ts +48 -0
- package/types/__tests__/mocks.d.ts +4 -0
- package/types/helpers.d.ts +17 -0
- package/types/index.d.ts +1 -0
- package/types/jsonapi.d.ts +19 -0
- package/types/localStorage.d.ts +124 -0
- package/types/logger.d.ts +2 -0
- package/types/loop.d.ts +60 -0
- package/types/mango.d.ts +3 -0
- package/types/migrations/adapter.d.ts +18 -0
- package/types/platformWeb.d.ts +17 -0
- package/types/remote.d.ts +6 -0
- package/types/replicateOnce.d.ts +29 -0
- package/types/startReplication.d.ts +12 -0
- package/types/types.d.ts +104 -0
- package/types/utils.d.ts +3 -0
|
@@ -19,10 +19,17 @@ jest.mock('./remote', () => ({
|
|
|
19
19
|
|
|
20
20
|
import * as rep from './startReplication'
|
|
21
21
|
import PouchDB from 'pouchdb-browser'
|
|
22
|
-
import
|
|
22
|
+
import {
|
|
23
|
+
LOCALSTORAGE_SYNCED_KEY,
|
|
24
|
+
LOCALSTORAGE_WARMUPEDQUERIES_KEY,
|
|
25
|
+
PouchLocalStorage
|
|
26
|
+
} from './localStorage'
|
|
27
|
+
import { platformWeb } from './platformWeb'
|
|
23
28
|
|
|
24
29
|
import { fetchRemoteLastSequence, fetchRemoteInstance } from './remote'
|
|
25
30
|
|
|
31
|
+
const ls = new PouchLocalStorage(platformWeb.storage)
|
|
32
|
+
|
|
26
33
|
const sleep = delay => {
|
|
27
34
|
return new Promise(resolve => {
|
|
28
35
|
setTimeout(resolve, delay)
|
|
@@ -63,7 +70,7 @@ describe('PouchManager', () => {
|
|
|
63
70
|
getReplicationURL,
|
|
64
71
|
onSync = jest.fn()
|
|
65
72
|
|
|
66
|
-
beforeEach(() => {
|
|
73
|
+
beforeEach(async () => {
|
|
67
74
|
getReplicationURL = () => 'http://replicationURL.local'
|
|
68
75
|
managerOptions = {
|
|
69
76
|
replicationDelay: 16,
|
|
@@ -72,6 +79,7 @@ describe('PouchManager', () => {
|
|
|
72
79
|
prefix: 'cozy.tools'
|
|
73
80
|
}
|
|
74
81
|
manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
82
|
+
await manager.init()
|
|
75
83
|
const pouch = manager.getPouch('io.cozy.todos')
|
|
76
84
|
const replication = mocks.pouchReplication({
|
|
77
85
|
direction: 'pull',
|
|
@@ -133,6 +141,7 @@ describe('PouchManager', () => {
|
|
|
133
141
|
'io.cozy.readonly': { strategy: 'fromRemote' }
|
|
134
142
|
}
|
|
135
143
|
})
|
|
144
|
+
await manager.init()
|
|
136
145
|
const normalPouch = manager.getPouch('io.cozy.todos')
|
|
137
146
|
const readOnlyPouch = manager.getPouch('io.cozy.readonly')
|
|
138
147
|
readOnlyPouch.replicate = {}
|
|
@@ -155,6 +164,7 @@ describe('PouchManager', () => {
|
|
|
155
164
|
}
|
|
156
165
|
}
|
|
157
166
|
)
|
|
167
|
+
await manager.init()
|
|
158
168
|
const normalPouch = manager.getPouch('io.cozy.todos')
|
|
159
169
|
const readOnlyPouch = manager.getPouch('io.cozy.readonly')
|
|
160
170
|
readOnlyPouch.replicate = {}
|
|
@@ -162,6 +172,9 @@ describe('PouchManager', () => {
|
|
|
162
172
|
const writeOnlyPouch = manager.getPouch('io.cozy.writeonly')
|
|
163
173
|
writeOnlyPouch.replicate = {}
|
|
164
174
|
writeOnlyPouch.replicate.to = jest.fn()
|
|
175
|
+
manager.updateSyncInfo('io.cozy.todos')
|
|
176
|
+
manager.updateSyncInfo('io.cozy.readonly')
|
|
177
|
+
manager.updateSyncInfo('io.cozy.writeonly')
|
|
165
178
|
manager.startReplicationLoop()
|
|
166
179
|
await sleep(1000)
|
|
167
180
|
expect(readOnlyPouch.replicate.from).toHaveBeenCalled()
|
|
@@ -214,6 +227,7 @@ describe('PouchManager', () => {
|
|
|
214
227
|
it('should call on sync with doctype updates', async () => {
|
|
215
228
|
jest.spyOn(manager, 'replicateOnce')
|
|
216
229
|
onSync.mockReset()
|
|
230
|
+
manager.updateSyncInfo('io.cozy.todos')
|
|
217
231
|
await manager.replicateOnce()
|
|
218
232
|
expect(onSync).toHaveBeenCalledWith({
|
|
219
233
|
'io.cozy.todos': [
|
|
@@ -231,14 +245,16 @@ describe('PouchManager', () => {
|
|
|
231
245
|
|
|
232
246
|
it('should add pouch plugin', async () => {
|
|
233
247
|
const options = { ...managerOptions, pouch: { plugins: ['myPlugin'] } }
|
|
234
|
-
new PouchManager(['io.cozy.todos'], options)
|
|
248
|
+
const manager = new PouchManager(['io.cozy.todos'], options)
|
|
249
|
+
await manager.init()
|
|
235
250
|
expect(PouchDB.plugin).toHaveBeenCalledTimes(1)
|
|
236
251
|
})
|
|
237
252
|
|
|
238
253
|
it('should instanciate pouch with options', async () => {
|
|
239
254
|
const pouchOptions = { adapter: 'cordova-sqlite', location: 'default' }
|
|
240
255
|
const options = { ...managerOptions, pouch: { options: pouchOptions } }
|
|
241
|
-
new PouchManager(['io.cozy.todos'], options)
|
|
256
|
+
const manager = new PouchManager(['io.cozy.todos'], options)
|
|
257
|
+
await manager.init()
|
|
242
258
|
expect(PouchDB).toHaveBeenCalledWith(
|
|
243
259
|
'cozy.tools_io.cozy.todos',
|
|
244
260
|
pouchOptions
|
|
@@ -246,33 +262,36 @@ describe('PouchManager', () => {
|
|
|
246
262
|
})
|
|
247
263
|
|
|
248
264
|
describe('getPersistedSyncedDoctypes', () => {
|
|
249
|
-
it('should return an empty array if local storage is empty', () => {
|
|
250
|
-
expect(ls.getPersistedSyncedDoctypes()).toEqual({})
|
|
265
|
+
it('should return an empty array if local storage is empty', async () => {
|
|
266
|
+
expect(await ls.getPersistedSyncedDoctypes()).toEqual({})
|
|
251
267
|
})
|
|
252
268
|
|
|
253
|
-
it('should return an empty array if local storage contains something that is not an array', () => {
|
|
254
|
-
localStorage.__STORE__[
|
|
255
|
-
expect(ls.getPersistedSyncedDoctypes()).toEqual({})
|
|
269
|
+
it('should return an empty array if local storage contains something that is not an array', async () => {
|
|
270
|
+
localStorage.__STORE__[LOCALSTORAGE_SYNCED_KEY] = 'true'
|
|
271
|
+
expect(await ls.getPersistedSyncedDoctypes()).toEqual({})
|
|
256
272
|
})
|
|
257
273
|
|
|
258
|
-
it('should return the list of doctypes if local storage contains one', () => {
|
|
274
|
+
it('should return the list of doctypes if local storage contains one', async () => {
|
|
259
275
|
const persistedSyncedDoctypes = {
|
|
260
276
|
'io.cozy.todos': { date: '2021-08-11T13:48:06.085Z' }
|
|
261
277
|
}
|
|
262
|
-
localStorage.__STORE__[
|
|
278
|
+
localStorage.__STORE__[LOCALSTORAGE_SYNCED_KEY] = JSON.stringify(
|
|
279
|
+
persistedSyncedDoctypes
|
|
280
|
+
)
|
|
281
|
+
expect(await ls.getPersistedSyncedDoctypes()).toEqual(
|
|
263
282
|
persistedSyncedDoctypes
|
|
264
283
|
)
|
|
265
|
-
expect(ls.getPersistedSyncedDoctypes()).toEqual(persistedSyncedDoctypes)
|
|
266
284
|
})
|
|
267
285
|
})
|
|
268
286
|
|
|
269
287
|
describe('persistSyncedDoctypes', () => {
|
|
270
|
-
it('should put the list of synced doctypes in localStorage', () => {
|
|
288
|
+
it('should put the list of synced doctypes in localStorage', async () => {
|
|
271
289
|
const manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
290
|
+
await manager.init()
|
|
272
291
|
manager.syncedDoctypes = ['io.cozy.todos']
|
|
273
292
|
ls.persistSyncedDoctypes(manager.syncedDoctypes)
|
|
274
293
|
|
|
275
|
-
expect(localStorage.__STORE__[
|
|
294
|
+
expect(localStorage.__STORE__[LOCALSTORAGE_SYNCED_KEY]).toEqual(
|
|
276
295
|
JSON.stringify(manager.syncedDoctypes)
|
|
277
296
|
)
|
|
278
297
|
})
|
|
@@ -287,126 +306,139 @@ describe('PouchManager', () => {
|
|
|
287
306
|
MockDate.reset()
|
|
288
307
|
})
|
|
289
308
|
|
|
290
|
-
it('should add the doctype to synced doctypes', () => {
|
|
309
|
+
it('should add the doctype to synced doctypes', async () => {
|
|
291
310
|
const manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
292
|
-
manager.
|
|
311
|
+
await manager.init()
|
|
312
|
+
await manager.updateSyncInfo('io.cozy.todos')
|
|
293
313
|
expect(Object.keys(manager.syncedDoctypes)).toEqual(['io.cozy.todos'])
|
|
294
314
|
})
|
|
295
315
|
|
|
296
|
-
it('should persist the new synced doctypes list', () => {
|
|
316
|
+
it('should persist the new synced doctypes list', async () => {
|
|
297
317
|
const manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
318
|
+
await manager.init()
|
|
298
319
|
|
|
299
|
-
manager.updateSyncInfo('io.cozy.todos')
|
|
300
|
-
expect(localStorage.__STORE__[
|
|
320
|
+
await manager.updateSyncInfo('io.cozy.todos')
|
|
321
|
+
expect(localStorage.__STORE__[LOCALSTORAGE_SYNCED_KEY]).toEqual(
|
|
301
322
|
JSON.stringify({
|
|
302
|
-
'io.cozy.todos': {
|
|
323
|
+
'io.cozy.todos': {
|
|
324
|
+
date: '2021-08-01T00:00:00.000Z',
|
|
325
|
+
status: 'synced'
|
|
326
|
+
}
|
|
303
327
|
})
|
|
304
328
|
)
|
|
305
329
|
})
|
|
306
330
|
})
|
|
307
331
|
|
|
308
|
-
describe('
|
|
332
|
+
describe('getSyncStatus', () => {
|
|
309
333
|
let manager
|
|
310
334
|
|
|
311
|
-
beforeEach(() => {
|
|
335
|
+
beforeEach(async () => {
|
|
312
336
|
manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
337
|
+
await manager.init()
|
|
313
338
|
})
|
|
314
339
|
|
|
315
|
-
it(
|
|
316
|
-
manager.updateSyncInfo('io.cozy.todos')
|
|
317
|
-
expect(manager.
|
|
340
|
+
it(`should return 'synced' if the doctype is synced`, async () => {
|
|
341
|
+
await manager.updateSyncInfo('io.cozy.todos')
|
|
342
|
+
expect(manager.getSyncStatus('io.cozy.todos')).toBe('synced')
|
|
318
343
|
})
|
|
319
344
|
|
|
320
|
-
it(
|
|
321
|
-
expect(manager.
|
|
345
|
+
it(`should return 'not_synced' if the doctype is not synced`, () => {
|
|
346
|
+
expect(manager.getSyncStatus('io.cozy.todos')).toBe('not_synced')
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
it('should return status if updateSyncInfo was called with custom status', async () => {
|
|
350
|
+
await manager.updateSyncInfo('io.cozy.todos', 'not_complete')
|
|
351
|
+
expect(manager.getSyncStatus('io.cozy.todos')).toBe('not_complete')
|
|
322
352
|
})
|
|
323
353
|
})
|
|
324
354
|
|
|
325
355
|
describe('destroySyncedDoctypes', () => {
|
|
326
|
-
it('should destroy the local storage item', () => {
|
|
327
|
-
ls.destroySyncedDoctypes()
|
|
356
|
+
it('should destroy the local storage item', async () => {
|
|
357
|
+
await ls.destroySyncedDoctypes()
|
|
328
358
|
|
|
329
359
|
expect(localStorage.removeItem).toHaveBeenLastCalledWith(
|
|
330
|
-
|
|
360
|
+
LOCALSTORAGE_SYNCED_KEY
|
|
331
361
|
)
|
|
332
362
|
})
|
|
333
|
-
it('should reset syncedDoctypes', () => {
|
|
363
|
+
it('should reset syncedDoctypes', async () => {
|
|
334
364
|
manager.syncedDoctypes = {
|
|
335
365
|
'io.cozy.todos': { date: '2021-08-11T13:48:06.085Z' }
|
|
336
366
|
}
|
|
337
|
-
manager.clearSyncedDoctypes()
|
|
367
|
+
await manager.clearSyncedDoctypes()
|
|
338
368
|
expect(manager.syncedDoctypes).toEqual({})
|
|
339
369
|
})
|
|
340
370
|
})
|
|
341
371
|
|
|
342
372
|
describe('getPersistedWarmedUpQueriess', () => {
|
|
343
|
-
it('should return an empty object if local storage is empty', () => {
|
|
344
|
-
expect(ls.getPersistedWarmedUpQueries()).toEqual({})
|
|
373
|
+
it('should return an empty object if local storage is empty', async () => {
|
|
374
|
+
expect(await ls.getPersistedWarmedUpQueries()).toEqual({})
|
|
345
375
|
})
|
|
346
376
|
|
|
347
|
-
it('should return the list of queries if local storage contains ones', () => {
|
|
377
|
+
it('should return the list of queries if local storage contains ones', async () => {
|
|
348
378
|
const persistedQueries = [query().options.as]
|
|
349
|
-
localStorage.__STORE__[
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
expect(ls.getPersistedWarmedUpQueries()).toEqual(persistedQueries)
|
|
379
|
+
localStorage.__STORE__[LOCALSTORAGE_WARMUPEDQUERIES_KEY] = JSON.stringify(
|
|
380
|
+
persistedQueries
|
|
381
|
+
)
|
|
382
|
+
expect(await ls.getPersistedWarmedUpQueries()).toEqual(persistedQueries)
|
|
353
383
|
})
|
|
354
384
|
})
|
|
355
385
|
|
|
356
386
|
describe('persistWarmedUpQueries', () => {
|
|
357
|
-
it('should put the list of warmedUpQueries in localStorage', () => {
|
|
387
|
+
it('should put the list of warmedUpQueries in localStorage', async () => {
|
|
358
388
|
const manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
389
|
+
await manager.init()
|
|
359
390
|
manager.warmedUpQueries = { 'io.cozy.todos': ['query1', 'query2'] }
|
|
360
|
-
ls.persistWarmedUpQueries(manager.warmedUpQueries)
|
|
391
|
+
await ls.persistWarmedUpQueries(manager.warmedUpQueries)
|
|
361
392
|
|
|
362
|
-
expect(
|
|
363
|
-
|
|
364
|
-
)
|
|
393
|
+
expect(localStorage.__STORE__[LOCALSTORAGE_WARMUPEDQUERIES_KEY]).toEqual(
|
|
394
|
+
JSON.stringify(manager.warmedUpQueries)
|
|
395
|
+
)
|
|
365
396
|
})
|
|
366
397
|
})
|
|
367
398
|
|
|
368
399
|
describe('areQueriesWarmedUp', () => {
|
|
369
400
|
let manager
|
|
370
401
|
|
|
371
|
-
beforeEach(() => {
|
|
402
|
+
beforeEach(async () => {
|
|
372
403
|
manager = new PouchManager(['io.cozy.todos'], managerOptions)
|
|
404
|
+
await manager.init()
|
|
373
405
|
})
|
|
374
406
|
|
|
375
|
-
it('should return true if all the queries are warmuped', () => {
|
|
407
|
+
it('should return true if all the queries are warmuped', async () => {
|
|
376
408
|
manager.warmedUpQueries = {
|
|
377
409
|
'io.cozy.todos': [query1().options.as, query2().options.as]
|
|
378
410
|
}
|
|
379
|
-
ls.persistWarmedUpQueries(manager.warmedUpQueries)
|
|
411
|
+
await ls.persistWarmedUpQueries(manager.warmedUpQueries)
|
|
380
412
|
|
|
381
413
|
expect(
|
|
382
|
-
manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
414
|
+
await manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
383
415
|
).toBe(true)
|
|
384
416
|
})
|
|
385
417
|
|
|
386
|
-
it('should return false if at least one query is not warmuped', () => {
|
|
418
|
+
it('should return false if at least one query is not warmuped', async () => {
|
|
387
419
|
manager.warmedUpQueries = {
|
|
388
420
|
'io.cozy.todos': [query2().options.as]
|
|
389
421
|
}
|
|
390
|
-
ls.persistWarmedUpQueries()
|
|
422
|
+
await ls.persistWarmedUpQueries()
|
|
391
423
|
|
|
392
424
|
expect(
|
|
393
|
-
manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
425
|
+
await manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
394
426
|
).toBe(false)
|
|
395
427
|
})
|
|
396
428
|
|
|
397
|
-
it('should return false if the queries are not been done', () => {
|
|
429
|
+
it('should return false if the queries are not been done', async () => {
|
|
398
430
|
expect(
|
|
399
|
-
manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
431
|
+
await manager.areQueriesWarmedUp('io.cozy.todos', [query1(), query2()])
|
|
400
432
|
).toBe(false)
|
|
401
433
|
})
|
|
402
434
|
})
|
|
403
435
|
|
|
404
436
|
describe('clearWarmedupQueries', () => {
|
|
405
|
-
it('should clear the local storage item', () => {
|
|
437
|
+
it('should clear the local storage item', async () => {
|
|
406
438
|
manager.clearWarmedUpQueries()
|
|
407
439
|
|
|
408
440
|
expect(localStorage.removeItem).toHaveBeenLastCalledWith(
|
|
409
|
-
|
|
441
|
+
LOCALSTORAGE_WARMUPEDQUERIES_KEY
|
|
410
442
|
)
|
|
411
443
|
})
|
|
412
444
|
it('should reset warmedupQueries', () => {
|
|
@@ -490,7 +522,7 @@ describe('PouchManager', () => {
|
|
|
490
522
|
describe('warmupQueries', () => {
|
|
491
523
|
let manager
|
|
492
524
|
const executeMock = jest.fn()
|
|
493
|
-
beforeEach(() => {
|
|
525
|
+
beforeEach(async () => {
|
|
494
526
|
let newManagerOptions = {
|
|
495
527
|
...managerOptions,
|
|
496
528
|
executeQuery: executeMock,
|
|
@@ -502,6 +534,7 @@ describe('PouchManager', () => {
|
|
|
502
534
|
}
|
|
503
535
|
}
|
|
504
536
|
manager = new PouchManager(['io.cozy.todos'], newManagerOptions)
|
|
537
|
+
await manager.init()
|
|
505
538
|
})
|
|
506
539
|
|
|
507
540
|
it('should executes warmeupQueries on the first replicationLoop only', async () => {
|
|
@@ -524,7 +557,7 @@ describe('PouchManager', () => {
|
|
|
524
557
|
.definition()
|
|
525
558
|
.toDefinition()
|
|
526
559
|
)
|
|
527
|
-
expect(ls.getPersistedWarmedUpQueries()).toEqual({
|
|
560
|
+
expect(await ls.getPersistedWarmedUpQueries()).toEqual({
|
|
528
561
|
'io.cozy.todos': ['query1', 'query2']
|
|
529
562
|
})
|
|
530
563
|
//Simulation of a loop. Let's replicate again
|
|
@@ -541,7 +574,7 @@ describe('PouchManager', () => {
|
|
|
541
574
|
|
|
542
575
|
await manager.replicateOnce()
|
|
543
576
|
await sleep(10)
|
|
544
|
-
expect(ls.getPersistedWarmedUpQueries()).toEqual({})
|
|
577
|
+
expect(await ls.getPersistedWarmedUpQueries()).toEqual({})
|
|
545
578
|
expect(manager.warmedUpQueries['io.cozy.todos']).toBeUndefined()
|
|
546
579
|
})
|
|
547
580
|
})
|
package/dist/helpers.js
CHANGED
|
@@ -15,8 +15,18 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
|
|
|
15
15
|
|
|
16
16
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
17
17
|
|
|
18
|
+
var _merge = _interopRequireDefault(require("lodash/merge"));
|
|
19
|
+
|
|
18
20
|
var _startsWith = _interopRequireDefault(require("lodash/startsWith"));
|
|
19
21
|
|
|
22
|
+
var _logger = _interopRequireDefault(require("./logger"));
|
|
23
|
+
|
|
24
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
25
|
+
|
|
26
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
27
|
+
|
|
28
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
29
|
+
|
|
20
30
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
21
31
|
|
|
22
32
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
@@ -186,5 +196,74 @@ helpers.insertBulkDocs = /*#__PURE__*/function () {
|
|
|
186
196
|
};
|
|
187
197
|
}();
|
|
188
198
|
|
|
199
|
+
helpers.normalizeFindSelector = function (_ref5) {
|
|
200
|
+
var selector = _ref5.selector,
|
|
201
|
+
sort = _ref5.sort,
|
|
202
|
+
indexedFields = _ref5.indexedFields,
|
|
203
|
+
partialFilter = _ref5.partialFilter;
|
|
204
|
+
var findSelector = selector || {};
|
|
205
|
+
|
|
206
|
+
if (indexedFields) {
|
|
207
|
+
var _iterator = _createForOfIteratorHelper(indexedFields),
|
|
208
|
+
_step;
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
212
|
+
var indexedField = _step.value;
|
|
213
|
+
|
|
214
|
+
if (!Object.keys(findSelector).includes(indexedField)) {
|
|
215
|
+
var selectorJson = JSON.stringify(selector);
|
|
216
|
+
|
|
217
|
+
_logger.default.warn("".concat(indexedField, " was missing in selector, it has been automatically added from indexed fields. Please consider adding this field to your query's selector as required by PouchDB. The query's selector is: ").concat(selectorJson));
|
|
218
|
+
|
|
219
|
+
findSelector[indexedField] = {
|
|
220
|
+
$gt: null
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch (err) {
|
|
225
|
+
_iterator.e(err);
|
|
226
|
+
} finally {
|
|
227
|
+
_iterator.f();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (sort) {
|
|
232
|
+
var sortedFields = sort.flatMap(function (s) {
|
|
233
|
+
return Object.keys(s);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
var _iterator2 = _createForOfIteratorHelper(sortedFields),
|
|
237
|
+
_step2;
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
241
|
+
var sortedField = _step2.value;
|
|
242
|
+
|
|
243
|
+
if (!Object.keys(findSelector).includes(sortedField)) {
|
|
244
|
+
var _selectorJson = JSON.stringify(selector);
|
|
245
|
+
|
|
246
|
+
_logger.default.warn("".concat(sortedField, " was missing in selector, it has been automatically added from sorted fields. Please consider adding this field to your query's selector as required by PouchDB. The query's selector is: ").concat(_selectorJson));
|
|
247
|
+
|
|
248
|
+
findSelector[sortedField] = {
|
|
249
|
+
$gt: null
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch (err) {
|
|
254
|
+
_iterator2.e(err);
|
|
255
|
+
} finally {
|
|
256
|
+
_iterator2.f();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
var mergedSelector = partialFilter ? (0, _merge.default)(_objectSpread({}, findSelector), partialFilter) : findSelector;
|
|
261
|
+
return Object.keys(mergedSelector).length > 0 ? mergedSelector : {
|
|
262
|
+
_id: {
|
|
263
|
+
$gt: null
|
|
264
|
+
}
|
|
265
|
+
}; // PouchDB does not accept empty selector
|
|
266
|
+
};
|
|
267
|
+
|
|
189
268
|
var _default = helpers;
|
|
190
269
|
exports.default = _default;
|
package/dist/helpers.spec.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import helpers from './helpers'
|
|
2
|
-
const {
|
|
2
|
+
const {
|
|
3
|
+
withoutDesignDocuments,
|
|
4
|
+
isDeletedDocument,
|
|
5
|
+
isDesignDocument,
|
|
6
|
+
normalizeFindSelector
|
|
7
|
+
} = helpers
|
|
3
8
|
|
|
4
9
|
import PouchDB from 'pouchdb-browser'
|
|
5
10
|
import PouchDBFind from 'pouchdb-find'
|
|
@@ -113,4 +118,83 @@ describe('Helpers', () => {
|
|
|
113
118
|
expect(isDeletedDocument({ _id: 'notdeleted' })).toBeFalsy()
|
|
114
119
|
})
|
|
115
120
|
})
|
|
121
|
+
|
|
122
|
+
describe('normalizeFindSelector', () => {
|
|
123
|
+
it('should add indexed fields in the selector if they are missing', () => {
|
|
124
|
+
const selector = {
|
|
125
|
+
SOME_FIELD: { $gt: null }
|
|
126
|
+
}
|
|
127
|
+
const sort = undefined
|
|
128
|
+
const indexedFields = ['SOME_INDEXED_FIELD']
|
|
129
|
+
|
|
130
|
+
const findSelector = normalizeFindSelector({
|
|
131
|
+
selector,
|
|
132
|
+
sort,
|
|
133
|
+
indexedFields
|
|
134
|
+
})
|
|
135
|
+
expect(findSelector).toStrictEqual({
|
|
136
|
+
SOME_FIELD: { $gt: null },
|
|
137
|
+
SOME_INDEXED_FIELD: { $gt: null }
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should add sorted fields in the selector if they are missing', () => {
|
|
142
|
+
const selector = {}
|
|
143
|
+
const sort = [{ SOME_SORTED_FIELD: 'asc' }]
|
|
144
|
+
const indexedFields = undefined
|
|
145
|
+
|
|
146
|
+
const findSelector = normalizeFindSelector({
|
|
147
|
+
selector,
|
|
148
|
+
sort,
|
|
149
|
+
indexedFields
|
|
150
|
+
})
|
|
151
|
+
expect(findSelector).toStrictEqual({
|
|
152
|
+
SOME_SORTED_FIELD: { $gt: null }
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should add indexed fields AND sorted fields in the selector if they are missing', () => {
|
|
157
|
+
const selector = undefined
|
|
158
|
+
const sort = [{ SOME_SORTED_FIELD: 'asc' }]
|
|
159
|
+
const indexedFields = ['SOME_INDEXED_FIELD']
|
|
160
|
+
|
|
161
|
+
const findSelector = normalizeFindSelector({
|
|
162
|
+
selector,
|
|
163
|
+
sort,
|
|
164
|
+
indexedFields
|
|
165
|
+
})
|
|
166
|
+
expect(findSelector).toStrictEqual({
|
|
167
|
+
SOME_INDEXED_FIELD: { $gt: null },
|
|
168
|
+
SOME_SORTED_FIELD: { $gt: null }
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('should prevent empty selector by adding a selector on _id when no selector is provided', () => {
|
|
173
|
+
const selector = undefined
|
|
174
|
+
const sort = undefined
|
|
175
|
+
const indexedFields = undefined
|
|
176
|
+
|
|
177
|
+
const findSelector = normalizeFindSelector({
|
|
178
|
+
selector,
|
|
179
|
+
sort,
|
|
180
|
+
indexedFields
|
|
181
|
+
})
|
|
182
|
+
expect(findSelector).toStrictEqual({ _id: { $gt: null } })
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('should not add selector on _id when no selector is provided but there are some indexed fields', () => {
|
|
186
|
+
const selector = undefined
|
|
187
|
+
const sort = undefined
|
|
188
|
+
const indexedFields = ['SOME_INDEXED_FIELD']
|
|
189
|
+
|
|
190
|
+
const findSelector = normalizeFindSelector({
|
|
191
|
+
selector,
|
|
192
|
+
sort,
|
|
193
|
+
indexedFields
|
|
194
|
+
})
|
|
195
|
+
expect(findSelector).toStrictEqual({
|
|
196
|
+
SOME_INDEXED_FIELD: { $gt: null }
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
})
|
|
116
200
|
})
|
package/dist/jsonapi.js
CHANGED
|
@@ -9,12 +9,16 @@ exports.fromPouchResult = exports.normalizeDoc = void 0;
|
|
|
9
9
|
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
|
|
12
|
+
var _cozyClient = require("cozy-client");
|
|
13
|
+
|
|
12
14
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
13
15
|
|
|
14
16
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
15
17
|
|
|
16
|
-
var normalizeDoc = function normalizeDoc(doc, doctype) {
|
|
17
|
-
var id = doc._id || doc.id;
|
|
18
|
+
var normalizeDoc = function normalizeDoc(doc, doctype, client) {
|
|
19
|
+
var id = doc._id || doc.id;
|
|
20
|
+
var relationships = doc.relationships,
|
|
21
|
+
referenced_by = doc.referenced_by; // PouchDB sends back .rev attribute but we do not want to
|
|
18
22
|
// keep it on the server. It is potentially higher than the
|
|
19
23
|
// _rev.
|
|
20
24
|
|
|
@@ -24,23 +28,66 @@ var normalizeDoc = function normalizeDoc(doc, doctype) {
|
|
|
24
28
|
id: id,
|
|
25
29
|
_id: id,
|
|
26
30
|
_rev: _rev,
|
|
27
|
-
_type: doctype
|
|
31
|
+
_type: doctype,
|
|
32
|
+
relationships: _objectSpread(_objectSpread({}, relationships), {}, {
|
|
33
|
+
referenced_by: referenced_by
|
|
34
|
+
})
|
|
28
35
|
});
|
|
29
36
|
|
|
30
37
|
if (normalizedDoc.rev) {
|
|
31
38
|
delete normalizedDoc.rev;
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
normalizeAppsLinks(normalizedDoc, doctype, client);
|
|
34
42
|
return normalizedDoc;
|
|
35
43
|
};
|
|
36
44
|
|
|
37
45
|
exports.normalizeDoc = normalizeDoc;
|
|
38
46
|
|
|
47
|
+
var normalizeAppsLinks = function normalizeAppsLinks(docRef, doctype, client) {
|
|
48
|
+
if (doctype !== 'io.cozy.apps') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var webLink = (0, _cozyClient.generateWebLink)({
|
|
53
|
+
cozyUrl: client.getStackClient().uri,
|
|
54
|
+
slug: docRef.slug,
|
|
55
|
+
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested',
|
|
56
|
+
pathname: '',
|
|
57
|
+
hash: '',
|
|
58
|
+
searchParams: []
|
|
59
|
+
});
|
|
60
|
+
docRef.links = {
|
|
61
|
+
self: "/apps/".concat(docRef.slug),
|
|
62
|
+
related: webLink,
|
|
63
|
+
icon: "/apps/".concat(docRef.slug, "/icon/").concat(docRef.version)
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
39
67
|
var filterDeletedDocumentsFromRows = function filterDeletedDocumentsFromRows(doc) {
|
|
40
68
|
return !!doc;
|
|
41
69
|
};
|
|
42
70
|
|
|
43
|
-
var fromPouchResult = function fromPouchResult(
|
|
71
|
+
var fromPouchResult = function fromPouchResult(_ref) {
|
|
72
|
+
var res = _ref.res,
|
|
73
|
+
withRows = _ref.withRows,
|
|
74
|
+
doctype = _ref.doctype,
|
|
75
|
+
client = _ref.client;
|
|
76
|
+
|
|
77
|
+
// Sometimes, queries are transformed by Collections and they call a dedicated
|
|
78
|
+
// cozy-stack route. When this is the case, we want to be able to replicate the same
|
|
79
|
+
// query from cozy-pouch-link. It is not possible as-is because the received data
|
|
80
|
+
// is not the same as the one stored in the Couch database
|
|
81
|
+
// To handle this, we store the received data in the Pouch with a dedicated id and
|
|
82
|
+
// we store the query result in a `cozyPouchData` attribute
|
|
83
|
+
// So when `cozyPouchData` attribute exists, we know that we want to return its content
|
|
84
|
+
// as the result of the query
|
|
85
|
+
if (res.cozyPouchData) {
|
|
86
|
+
return {
|
|
87
|
+
data: res.cozyPouchData
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
44
91
|
if (withRows) {
|
|
45
92
|
var docs = res.rows ? res.rows.map(function (row) {
|
|
46
93
|
return row.doc;
|
|
@@ -48,7 +95,7 @@ var fromPouchResult = function fromPouchResult(res, withRows, doctype) {
|
|
|
48
95
|
var offset = res.offset || 0;
|
|
49
96
|
return {
|
|
50
97
|
data: docs.map(function (doc) {
|
|
51
|
-
return normalizeDoc(doc, doctype);
|
|
98
|
+
return normalizeDoc(doc, doctype, client);
|
|
52
99
|
}),
|
|
53
100
|
meta: {
|
|
54
101
|
count: docs.length
|
|
@@ -59,8 +106,8 @@ var fromPouchResult = function fromPouchResult(res, withRows, doctype) {
|
|
|
59
106
|
} else {
|
|
60
107
|
return {
|
|
61
108
|
data: Array.isArray(res) ? res.map(function (doc) {
|
|
62
|
-
return normalizeDoc(doc, doctype);
|
|
63
|
-
}) : normalizeDoc(res, doctype)
|
|
109
|
+
return normalizeDoc(doc, doctype, client);
|
|
110
|
+
}) : normalizeDoc(res, doctype, client)
|
|
64
111
|
};
|
|
65
112
|
}
|
|
66
113
|
};
|