ar_sync 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,7 @@
1
1
  import ArSyncApi from './ArSyncApi'
2
+ export type Request = { api: string; query: any; params?: any; id?: IDType }
3
+
4
+ type IDType = number | string
2
5
 
3
6
  class ModelBatchRequest {
4
7
  timer: number | null = null
@@ -6,8 +9,8 @@ class ModelBatchRequest {
6
9
  Map<string,
7
10
  {
8
11
  query,
9
- requests: Map<number, {
10
- id: number
12
+ requests: Map<IDType, {
13
+ id: IDType
11
14
  model?
12
15
  callbacks: {
13
16
  resolve: (model: any) => void
@@ -17,7 +20,7 @@ class ModelBatchRequest {
17
20
  }
18
21
  >
19
22
  >()
20
- fetch(api: string, query, id: number) {
23
+ fetch(api: string, query, id: IDType) {
21
24
  this.setTimer()
22
25
  return new Promise((resolve, reject) => {
23
26
  const queryJSON = JSON.stringify(query)
@@ -36,7 +39,7 @@ class ModelBatchRequest {
36
39
  const ids = Array.from(requests.keys())
37
40
  ArSyncApi.syncFetch({ api, query, params: { ids } }).then((models: any[]) => {
38
41
  for (const model of models) {
39
- const req = requests.get(model.id)
42
+ const req = requests.get(model._sync.id)
40
43
  if (req) req.model = model
41
44
  }
42
45
  requests.forEach(({ model, callbacks }) => {
@@ -67,18 +70,18 @@ type ParsedQuery = {
67
70
  params: any
68
71
  } | {}
69
72
 
73
+ type SyncField = { id: IDType; keys: string[] }
70
74
  type Unsubscribable = { unsubscribe: () => void }
71
75
 
72
76
  class ArSyncContainerBase {
73
77
  data
74
78
  listeners: Unsubscribable[] = []
75
79
  networkSubscriber?: Unsubscribable
76
- parentModel
80
+ parentModel: ArSyncRecord | ArSyncCollection | null = null
77
81
  parentKey
78
82
  children: ArSyncContainerBase[] | { [key: string]: ArSyncContainerBase | null }
79
- sync_keys: string[]
80
83
  onConnectionChange?: (status: boolean) => void
81
- replaceData(_data, _sync_keys?) {}
84
+ replaceData(_data, _parentSyncKeys?) {}
82
85
  initForReload(request) {
83
86
  this.networkSubscriber = ArSyncStore.connectionManager.subscribeNetwork((state) => {
84
87
  if (!state) {
@@ -197,63 +200,52 @@ class ArSyncContainerBase {
197
200
  if (attrsonly) return attributes
198
201
  return { attributes, as: column, params }
199
202
  }
200
- static _load({ api, id, params, query }, root) {
203
+ static load({ api, id, params, query }: Request, root: ArSyncStore) {
201
204
  const parsedQuery = ArSyncRecord.parseQuery(query)
202
205
  const compactQueryAttributes = ArSyncRecord.compactQueryAttributes(parsedQuery)
203
206
  if (id != null) {
204
207
  return modelBatchRequest.fetch(api, compactQueryAttributes, id).then(data => {
205
208
  if (!data) throw { retry: false }
206
209
  const request = { api, id, query: compactQueryAttributes }
207
- return new ArSyncRecord(parsedQuery, data, request, root)
210
+ return new ArSyncRecord(parsedQuery, data, request, root, null, null)
208
211
  })
209
212
  } else {
210
213
  const request = { api, query: compactQueryAttributes, params }
211
214
  return ArSyncApi.syncFetch(request).then((response: any) => {
212
215
  if (!response) {
213
216
  throw { retry: false }
214
- } else if (response.collection && response.order) {
215
- return new ArSyncCollection(response.sync_keys, 'collection', parsedQuery, response, request, root)
217
+ } else if (response.collection && response.order && response._sync) {
218
+ return new ArSyncCollection(response._sync.keys, 'collection', parsedQuery, response, request, root, null, null)
216
219
  } else if (response instanceof Array) {
217
- return new ArSyncCollection([], '', parsedQuery, response, request, root)
220
+ return new ArSyncCollection([], '', parsedQuery, response, request, root, null, null)
218
221
  } else {
219
- return new ArSyncRecord(parsedQuery, response, request, root)
222
+ return new ArSyncRecord(parsedQuery, response, request, root, null, null)
220
223
  }
221
224
  })
222
225
  }
223
226
  }
224
- static load(apiParams, root) {
225
- if (!(apiParams instanceof Array)) return this._load(apiParams, root)
226
- return new Promise((resolve, _reject) => {
227
- const resultModels: any[] = []
228
- let countdown = apiParams.length
229
- apiParams.forEach((param, i) => {
230
- this._load(param, root).then(model => {
231
- resultModels[i] = model
232
- countdown --
233
- if (countdown === 0) resolve(resultModels)
234
- })
235
- })
236
- })
237
- }
238
227
  }
239
228
 
240
229
  type NotifyData = {
241
230
  action: 'add' | 'remove' | 'update'
242
- class_name: string
243
- id: number
231
+ class: string
232
+ id: IDType
244
233
  field?: string
245
234
  }
246
235
 
247
236
  class ArSyncRecord extends ArSyncContainerBase {
248
- id: number
249
- root
237
+ id: IDType
238
+ root: ArSyncStore
250
239
  query
251
240
  queryAttributes
252
241
  data
242
+ syncKeys: string[]
253
243
  children: { [key: string]: ArSyncContainerBase | null }
254
244
  paths: string[]
255
245
  reloadQueryCache
256
- constructor(query, data, request, root) {
246
+ rootRecord: boolean
247
+ fetching = new Set<string>()
248
+ constructor(query, data, request, root: ArSyncStore, parentModel: ArSyncRecord | ArSyncCollection | null, parentKey: string | number | null) {
257
249
  super()
258
250
  this.root = root
259
251
  if (request) this.initForReload(request)
@@ -261,48 +253,43 @@ class ArSyncRecord extends ArSyncContainerBase {
261
253
  this.queryAttributes = query.attributes || {}
262
254
  this.data = {}
263
255
  this.children = {}
256
+ this.rootRecord = !parentModel
257
+ this.id = data._sync.id
258
+ this.syncKeys = data._sync.keys
264
259
  this.replaceData(data)
260
+ this.parentModel = parentModel
261
+ this.parentKey = parentKey
265
262
  }
266
- setSyncKeys(sync_keys: string[] | undefined) {
267
- this.sync_keys = sync_keys ?? []
268
- }
269
- replaceData(data) {
270
- this.setSyncKeys(data.sync_keys)
263
+ replaceData(data: { _sync: SyncField }) {
264
+ this.id = data._sync.id
265
+ this.syncKeys = data._sync.keys
271
266
  this.unsubscribeAll()
272
- if (this.data.id !== data.id) {
273
- this.mark()
274
- this.data.id = data.id
275
- }
276
267
  this.paths = []
277
268
  for (const key in this.queryAttributes) {
278
269
  const subQuery = this.queryAttributes[key]
279
270
  const aliasName = subQuery.as || key
280
271
  const subData = data[aliasName]
281
272
  const child = this.children[aliasName]
282
- if (key === 'sync_keys') continue
283
- if (subData instanceof Array || (subData && subData.collection && subData.order)) {
273
+ if (key === '_sync') continue
274
+ if (subData instanceof Array || (subData && subData.collection && subData.order && subData._sync)) {
284
275
  if (child) {
285
- child.replaceData(subData, this.sync_keys)
276
+ child.replaceData(subData, this.syncKeys)
286
277
  } else {
287
- const collection = new ArSyncCollection(this.sync_keys, key, subQuery, subData, null, this.root)
278
+ const collection = new ArSyncCollection(this.syncKeys, key, subQuery, subData, null, this.root, this, aliasName)
288
279
  this.mark()
289
280
  this.children[aliasName] = collection
290
281
  this.data[aliasName] = collection.data
291
- collection.parentModel = this
292
- collection.parentKey = aliasName
293
282
  }
294
283
  } else {
295
284
  if (subQuery.attributes && Object.keys(subQuery.attributes).length > 0) this.paths.push(key)
296
- if (subData && subData.sync_keys) {
285
+ if (subData && subData._sync) {
297
286
  if (child) {
298
287
  child.replaceData(subData)
299
288
  } else {
300
- const model = new ArSyncRecord(subQuery, subData, null, this.root)
289
+ const model = new ArSyncRecord(subQuery, subData, null, this.root, this, aliasName)
301
290
  this.mark()
302
291
  this.children[aliasName] = model
303
292
  this.data[aliasName] = model.data
304
- model.parentModel = this
305
- model.parentKey = aliasName
306
293
  }
307
294
  } else {
308
295
  if(child) {
@@ -318,6 +305,7 @@ class ArSyncRecord extends ArSyncContainerBase {
318
305
  }
319
306
  if (this.queryAttributes['*']) {
320
307
  for (const key in data) {
308
+ if (key === '_sync') continue
321
309
  if (!this.queryAttributes[key] && this.data[key] !== data[key]) {
322
310
  this.mark()
323
311
  this.data[key] = data[key]
@@ -327,28 +315,34 @@ class ArSyncRecord extends ArSyncContainerBase {
327
315
  this.subscribeAll()
328
316
  }
329
317
  onNotify(notifyData: NotifyData, path?: string) {
330
- const { action, class_name: className, id } = notifyData
318
+ const { action, class: className, id } = notifyData
331
319
  const query = path && this.queryAttributes[path]
332
320
  const aliasName = (query && query.as) || path;
333
321
  if (action === 'remove') {
334
322
  const child = this.children[aliasName]
323
+ this.fetching.delete(`${aliasName}:${id}`) // To cancel consumeAdd
335
324
  if (child) child.release()
336
325
  this.children[aliasName] = null
337
326
  this.mark()
338
327
  this.data[aliasName] = null
339
328
  this.onChange([aliasName], null)
340
329
  } else if (action === 'add') {
341
- if (this.data[aliasName] && this.data[aliasName].id === id) return
330
+ const child = this.children[aliasName]
331
+ if (child instanceof ArSyncRecord && child.id === id) return
332
+ const fetchKey = `${aliasName}:${id}`
333
+ this.fetching.add(fetchKey)
342
334
  modelBatchRequest.fetch(className, ArSyncRecord.compactQueryAttributes(query), id).then(data => {
335
+ // Record already removed
336
+ if (!this.fetching.has(fetchKey)) return
337
+
338
+ this.fetching.delete(fetchKey)
343
339
  if (!data || !this.data) return
344
- const model = new ArSyncRecord(query, data, null, this.root)
340
+ const model = new ArSyncRecord(query, data, null, this.root, this, aliasName)
345
341
  const child = this.children[aliasName]
346
342
  if (child) child.release()
347
343
  this.children[aliasName] = model
348
344
  this.mark()
349
345
  this.data[aliasName] = model.data
350
- model.parentModel = this
351
- model.parentKey = aliasName
352
346
  this.onChange([aliasName], model.data)
353
347
  }).catch(e => {
354
348
  console.error(`failed to load ${className}:${id} ${e}`)
@@ -366,12 +360,16 @@ class ArSyncRecord extends ArSyncContainerBase {
366
360
  }
367
361
  subscribeAll() {
368
362
  const callback = data => this.onNotify(data)
369
- for (const key of this.sync_keys) {
363
+ for (const key of this.syncKeys) {
370
364
  this.subscribe(key, callback)
371
365
  }
372
366
  for (const path of this.paths) {
373
367
  const pathCallback = data => this.onNotify(data, path)
374
- for (const key of this.sync_keys) this.subscribe(key + path, pathCallback)
368
+ for (const key of this.syncKeys) this.subscribe(key + path, pathCallback)
369
+ }
370
+ if (this.rootRecord) {
371
+ const key = this.syncKeys[0]
372
+ if (key) this.subscribe(key + '_destroy', () => this.root.handleDestroy())
375
373
  }
376
374
  }
377
375
  patchQuery(key: string) {
@@ -383,7 +381,7 @@ class ArSyncRecord extends ArSyncContainerBase {
383
381
  let arrayQuery = [] as string[] | null
384
382
  const hashQuery = {}
385
383
  for (const key in this.queryAttributes) {
386
- if (key === 'sync_keys') continue
384
+ if (key === '_sync') continue
387
385
  const val = this.queryAttributes[key]
388
386
  if (!val || !val.attributes) {
389
387
  arrayQuery?.push(key)
@@ -397,6 +395,7 @@ class ArSyncRecord extends ArSyncContainerBase {
397
395
  }
398
396
  update(data) {
399
397
  for (const key in data) {
398
+ if (key === '_sync') continue
400
399
  const subQuery = this.queryAttributes[key]
401
400
  if (subQuery && subQuery.attributes && Object.keys(subQuery.attributes).length > 0) continue
402
401
  if (this.data[key] === data[key]) continue
@@ -413,22 +412,24 @@ class ArSyncRecord extends ArSyncContainerBase {
413
412
  if (!this.root || !this.root.immutable || !Object.isFrozen(this.data)) return
414
413
  this.data = { ...this.data }
415
414
  this.root.mark(this.data)
416
- if (this.parentModel) this.parentModel.markAndSet(this.parentKey, this.data)
415
+ if (this.parentModel && this.parentKey) (this.parentModel as { markAndSet(key: string | number, data: any): any }).markAndSet(this.parentKey, this.data)
417
416
  }
418
417
  }
419
418
 
420
419
  type Ordering = { first?: number; last?: number; orderBy: string; direction: 'asc' | 'desc' }
421
420
  class ArSyncCollection extends ArSyncContainerBase {
422
- root
421
+ root: ArSyncStore
423
422
  path: string
424
423
  ordering: Ordering = { orderBy: 'id', direction: 'asc' }
425
424
  query
426
425
  queryAttributes
427
426
  compactQueryAttributes
427
+ syncKeys: string[]
428
428
  data: any[]
429
429
  children: ArSyncRecord[]
430
430
  aliasOrderKey = 'id'
431
- constructor(sync_keys: string[], path: string, query, data: any[], request, root){
431
+ fetching = new Set<IDType>()
432
+ constructor(parentSyncKeys: string[], path: string, query, data: any[], request, root: ArSyncStore, parentModel: ArSyncRecord | null, parentKey: string | null){
432
433
  super()
433
434
  this.root = root
434
435
  this.path = path
@@ -441,7 +442,9 @@ class ArSyncCollection extends ArSyncContainerBase {
441
442
  }
442
443
  this.data = []
443
444
  this.children = []
444
- this.replaceData(data, sync_keys)
445
+ this.replaceData(data, parentSyncKeys)
446
+ this.parentModel = parentModel
447
+ this.parentKey = parentKey
445
448
  }
446
449
  setOrdering(ordering: { first?: unknown; last?: unknown; orderBy?: unknown; direction?: unknown }) {
447
450
  let direction: 'asc' | 'desc' = 'asc'
@@ -456,17 +459,17 @@ class ArSyncCollection extends ArSyncContainerBase {
456
459
  this.aliasOrderKey = (subQuery && subQuery.as) || orderBy
457
460
  this.ordering = { first, last, direction, orderBy }
458
461
  }
459
- setSyncKeys(sync_keys: string[]) {
460
- if (sync_keys) {
461
- this.sync_keys = sync_keys.map(key => key + this.path)
462
+ setSyncKeys(parentSyncKeys: string[] | undefined) {
463
+ if (parentSyncKeys) {
464
+ this.syncKeys = parentSyncKeys.map(key => key + this.path)
462
465
  } else {
463
- this.sync_keys = []
466
+ this.syncKeys = []
464
467
  }
465
468
  }
466
- replaceData(data: any[] | { collection: any[]; ordering: Ordering }, sync_keys: string[]) {
467
- this.setSyncKeys(sync_keys)
468
- const existings = new Map<number, ArSyncRecord>()
469
- for (const child of this.children) existings.set(child.data.id, child)
469
+ replaceData(data: any[] | { collection: any[]; ordering: Ordering }, parentSyncKeys: string[]) {
470
+ this.setSyncKeys(parentSyncKeys)
471
+ const existings = new Map<IDType, ArSyncRecord>()
472
+ for (const child of this.children) existings.set(child.id, child)
470
473
  let collection: any[]
471
474
  if (Array.isArray(data)) {
472
475
  collection = data
@@ -478,14 +481,12 @@ class ArSyncCollection extends ArSyncContainerBase {
478
481
  const newData: any[] = []
479
482
  for (const subData of collection) {
480
483
  let model: ArSyncRecord | undefined = undefined
481
- if (typeof(subData) === 'object' && subData && 'sync_keys' in subData) model = existings.get(subData.id)
484
+ if (typeof(subData) === 'object' && subData && '_sync' in subData) model = existings.get(subData._sync.id)
482
485
  let data = subData
483
486
  if (model) {
484
487
  model.replaceData(subData)
485
- } else if (subData.sync_keys) {
486
- model = new ArSyncRecord(this.query, subData, null, this.root)
487
- model.parentModel = this
488
- model.parentKey = subData.id
488
+ } else if (subData._sync) {
489
+ model = new ArSyncRecord(this.query, subData, null, this.root, this, subData._sync.id)
489
490
  }
490
491
  if (model) {
491
492
  newChildren.push(model)
@@ -495,7 +496,7 @@ class ArSyncCollection extends ArSyncContainerBase {
495
496
  }
496
497
  while (this.children.length) {
497
498
  const child = this.children.pop()!
498
- if (!existings.has(child.data.id)) child.release()
499
+ if (!existings.has(child.id)) child.release()
499
500
  }
500
501
  if (this.data.length || newChildren.length) this.mark()
501
502
  while (this.data.length) this.data.pop()
@@ -503,13 +504,13 @@ class ArSyncCollection extends ArSyncContainerBase {
503
504
  for (const el of newData) this.data.push(el)
504
505
  this.subscribeAll()
505
506
  }
506
- consumeAdd(className: string, id: number) {
507
+ consumeAdd(className: string, id: IDType) {
507
508
  const { first, last, direction } = this.ordering
508
509
  const limit = first || last
509
- if (this.data.findIndex(a => a.id === id) >= 0) return
510
- if (limit && limit <= this.data.length) {
511
- const lastItem = this.data[this.data.length - 1]
512
- const firstItem = this.data[0]
510
+ if (this.children.find(a => a.id === id)) return
511
+ if (limit && limit <= this.children.length) {
512
+ const lastItem = this.children[this.children.length - 1]
513
+ const firstItem = this.children[0]
513
514
  if (direction === 'asc') {
514
515
  if (first) {
515
516
  if (lastItem && lastItem.id < id) return
@@ -524,11 +525,14 @@ class ArSyncCollection extends ArSyncContainerBase {
524
525
  }
525
526
  }
526
527
  }
528
+ this.fetching.add(id)
527
529
  modelBatchRequest.fetch(className, this.compactQueryAttributes, id).then((data: any) => {
530
+ // Record already removed
531
+ if (!this.fetching.has(id)) return
532
+
533
+ this.fetching.delete(id)
528
534
  if (!data || !this.data) return
529
- const model = new ArSyncRecord(this.query, data, null, this.root)
530
- model.parentModel = this
531
- model.parentKey = id
535
+ const model = new ArSyncRecord(this.query, data, null, this.root, this, id)
532
536
  const overflow = limit && limit <= this.data.length
533
537
  let rmodel: ArSyncRecord | undefined
534
538
  this.mark()
@@ -583,8 +587,9 @@ class ArSyncCollection extends ArSyncContainerBase {
583
587
  this.data.sort((a, b) => a[orderKey] > b[orderKey] ? -1 : +1)
584
588
  }
585
589
  }
586
- consumeRemove(id: number) {
587
- const idx = this.data.findIndex(a => a.id === id)
590
+ consumeRemove(id: IDType) {
591
+ const idx = this.children.findIndex(a => a.id === id)
592
+ this.fetching.delete(id) // To cancel consumeAdd
588
593
  if (idx < 0) return
589
594
  this.mark()
590
595
  this.children[idx].release()
@@ -592,58 +597,64 @@ class ArSyncCollection extends ArSyncContainerBase {
592
597
  this.data.splice(idx, 1)
593
598
  this.onChange([id], null)
594
599
  }
595
- onNotify(notifyData) {
600
+ onNotify(notifyData: NotifyData) {
596
601
  if (notifyData.action === 'add') {
597
- this.consumeAdd(notifyData.class_name, notifyData.id)
602
+ this.consumeAdd(notifyData.class, notifyData.id)
598
603
  } else if (notifyData.action === 'remove') {
599
604
  this.consumeRemove(notifyData.id)
600
605
  }
601
606
  }
602
607
  subscribeAll() {
603
608
  const callback = data => this.onNotify(data)
604
- for (const key of this.sync_keys) this.subscribe(key, callback)
609
+ for (const key of this.syncKeys) this.subscribe(key, callback)
605
610
  }
606
611
  onChange(path: (string | number)[], data) {
607
612
  super.onChange(path, data)
608
613
  if (path[1] === this.aliasOrderKey) this.markAndSort()
609
614
  }
610
- markAndSet(id: number, data) {
615
+ markAndSet(id: IDType, data) {
611
616
  this.mark()
612
- const idx = this.data.findIndex(a => a.id === id)
617
+ const idx = this.children.findIndex(a => a.id === id)
613
618
  if (idx >= 0) this.data[idx] = data
614
619
  }
615
620
  mark() {
616
621
  if (!this.root || !this.root.immutable || !Object.isFrozen(this.data)) return
617
622
  this.data = [...this.data]
618
623
  this.root.mark(this.data)
619
- if (this.parentModel) this.parentModel.markAndSet(this.parentKey, this.data)
624
+ if (this.parentModel && this.parentKey) (this.parentModel as { markAndSet(key: string | number, data: any): any }).markAndSet(this.parentKey, this.data)
620
625
  }
621
626
  }
622
627
 
623
- export default class ArSyncStore {
628
+ export class ArSyncStore {
624
629
  immutable: boolean
625
630
  markedForFreezeObjects: any[]
626
631
  changes
627
632
  eventListeners
628
633
  markForRelease: true | undefined
629
634
  container
630
- request
631
- complete: boolean
635
+ request: Request
636
+ complete = false
632
637
  notfound?: boolean
638
+ destroyed = false
633
639
  data
634
640
  changesBufferTimer: number | undefined | null
635
641
  retryLoadTimer: number | undefined | null
636
642
  static connectionManager
637
- constructor(request, { immutable } = {} as { immutable?: boolean }) {
643
+ constructor(request: Request, { immutable } = {} as { immutable?: boolean }) {
638
644
  this.immutable = !!immutable
639
645
  this.markedForFreezeObjects = []
640
646
  this.changes = []
641
647
  this.eventListeners = { events: {}, serial: 0 }
642
648
  this.request = request
643
- this.complete = false
644
649
  this.data = null
645
650
  this.load(0)
646
651
  }
652
+ handleDestroy() {
653
+ this.release()
654
+ this.data = null
655
+ this.destroyed = true
656
+ this.trigger('destroy')
657
+ }
647
658
  load(retryCount: number) {
648
659
  ArSyncContainerBase.load(this.request, this).then((container: ArSyncContainerBase) => {
649
660
  if (this.markForRelease) {
data/src/core/hooks.ts CHANGED
@@ -21,11 +21,11 @@ function checkHooks() {
21
21
  if (!useState) throw 'uninitialized. needs `initializeHooks({ useState, useEffect, useMemo, useRef })`'
22
22
  }
23
23
 
24
- interface ModelStatus { complete: boolean; notfound?: boolean; connected: boolean }
24
+ interface ModelStatus { complete: boolean; notfound?: boolean; connected: boolean; destroyed: boolean }
25
25
  export type DataAndStatus<T> = [T | null, ModelStatus]
26
26
  export interface Request { api: string; params?: any; id?: number; query: any }
27
27
 
28
- const initialResult: DataAndStatus<any> = [null, { complete: false, notfound: undefined, connected: true }]
28
+ const initialResult: DataAndStatus<any> = [null, { complete: false, notfound: undefined, connected: true, destroyed: false }]
29
29
  export function useArSyncModel<T>(request: Request | null): DataAndStatus<T> {
30
30
  checkHooks()
31
31
  const [result, setResult] = useState<DataAndStatus<T>>(initialResult)
@@ -39,12 +39,12 @@ export function useArSyncModel<T>(request: Request | null): DataAndStatus<T> {
39
39
  }
40
40
  const model = new ArSyncModel<T>(request, { immutable: true })
41
41
  function update() {
42
- const { complete, notfound, connected, data } = model
42
+ const { complete, notfound, connected, destroyed, data } = model
43
43
  setResult(resultWas => {
44
44
  const [dataWas, statusWas] = resultWas
45
- const statusPersisted = statusWas.complete === complete && statusWas.notfound === notfound && statusWas.connected === connected
45
+ const statusPersisted = statusWas.complete === complete && statusWas.notfound === notfound && statusWas.connected === connected && statusWas.destroyed === destroyed
46
46
  if (dataWas === data && statusPersisted) return resultWas
47
- const status = statusPersisted ? statusWas : { complete, notfound, connected }
47
+ const status = statusPersisted ? statusWas : { complete, notfound, connected, destroyed }
48
48
  return [data, status]
49
49
  })
50
50
  }
@@ -55,6 +55,7 @@ export function useArSyncModel<T>(request: Request | null): DataAndStatus<T> {
55
55
  }
56
56
  model.subscribe('load', update)
57
57
  model.subscribe('change', update)
58
+ model.subscribe('destroy', update)
58
59
  model.subscribe('connection', update)
59
60
  return () => model.release()
60
61
  }, [requestString])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-16 00:00:00.000000000 Z
11
+ date: 2024-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: pry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: sqlite3
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +91,6 @@ files:
105
91
  - ".gitignore"
106
92
  - ".travis.yml"
107
93
  - Gemfile
108
- - Gemfile.lock
109
94
  - LICENSE.txt
110
95
  - README.md
111
96
  - Rakefile
@@ -129,7 +114,8 @@ files:
129
114
  - core/hooks.d.ts
130
115
  - core/hooks.js
131
116
  - gemfiles/Gemfile-rails-6
132
- - gemfiles/Gemfile-rails-7
117
+ - gemfiles/Gemfile-rails-7-0
118
+ - gemfiles/Gemfile-rails-7-1
133
119
  - index.d.ts
134
120
  - index.js
135
121
  - lib/ar_sync.rb
@@ -176,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
162
  - !ruby/object:Gem::Version
177
163
  version: '0'
178
164
  requirements: []
179
- rubygems_version: 3.3.3
165
+ rubygems_version: 3.5.9
180
166
  signing_key:
181
167
  specification_version: 4
182
168
  summary: ActiveRecord - JavaScript Sync
data/Gemfile.lock DELETED
@@ -1,54 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- ar_sync (1.1.1)
5
- activerecord
6
- ar_serializer
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- activemodel (7.0.2.3)
12
- activesupport (= 7.0.2.3)
13
- activerecord (7.0.2.3)
14
- activemodel (= 7.0.2.3)
15
- activesupport (= 7.0.2.3)
16
- activerecord-import (1.4.0)
17
- activerecord (>= 4.2)
18
- activesupport (7.0.2.3)
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
20
- i18n (>= 1.6, < 2)
21
- minitest (>= 5.1)
22
- tzinfo (~> 2.0)
23
- ar_serializer (1.2.0)
24
- activerecord
25
- top_n_loader
26
- coderay (1.1.3)
27
- concurrent-ruby (1.1.10)
28
- i18n (1.10.0)
29
- concurrent-ruby (~> 1.0)
30
- method_source (1.0.0)
31
- minitest (5.15.0)
32
- pry (0.14.1)
33
- coderay (~> 1.1)
34
- method_source (~> 1.0)
35
- rake (13.0.6)
36
- sqlite3 (1.4.2)
37
- top_n_loader (1.0.2)
38
- activerecord
39
- tzinfo (2.0.4)
40
- concurrent-ruby (~> 1.0)
41
-
42
- PLATFORMS
43
- ruby
44
-
45
- DEPENDENCIES
46
- activerecord-import
47
- ar_serializer
48
- ar_sync!
49
- pry
50
- rake
51
- sqlite3
52
-
53
- BUNDLED WITH
54
- 2.1.2