ar_sync 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +53 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +128 -0
  8. data/Rakefile +10 -0
  9. data/ar_sync.gemspec +28 -0
  10. data/bin/console +12 -0
  11. data/bin/setup +8 -0
  12. data/core/ActioncableAdapter.d.ts +10 -0
  13. data/core/ActioncableAdapter.js +29 -0
  14. data/core/ArSyncApi.d.ts +5 -0
  15. data/core/ArSyncApi.js +74 -0
  16. data/core/ArSyncModelBase.d.ts +71 -0
  17. data/core/ArSyncModelBase.js +110 -0
  18. data/core/ConnectionAdapter.d.ts +7 -0
  19. data/core/ConnectionAdapter.js +2 -0
  20. data/core/ConnectionManager.d.ts +19 -0
  21. data/core/ConnectionManager.js +75 -0
  22. data/core/DataType.d.ts +60 -0
  23. data/core/DataType.js +2 -0
  24. data/core/hooksBase.d.ts +29 -0
  25. data/core/hooksBase.js +80 -0
  26. data/graph/ArSyncModel.d.ts +10 -0
  27. data/graph/ArSyncModel.js +22 -0
  28. data/graph/ArSyncStore.d.ts +28 -0
  29. data/graph/ArSyncStore.js +593 -0
  30. data/graph/hooks.d.ts +3 -0
  31. data/graph/hooks.js +10 -0
  32. data/graph/index.d.ts +2 -0
  33. data/graph/index.js +4 -0
  34. data/lib/ar_sync.rb +25 -0
  35. data/lib/ar_sync/class_methods.rb +215 -0
  36. data/lib/ar_sync/collection.rb +83 -0
  37. data/lib/ar_sync/config.rb +18 -0
  38. data/lib/ar_sync/core.rb +138 -0
  39. data/lib/ar_sync/field.rb +96 -0
  40. data/lib/ar_sync/instance_methods.rb +130 -0
  41. data/lib/ar_sync/rails.rb +155 -0
  42. data/lib/ar_sync/type_script.rb +80 -0
  43. data/lib/ar_sync/version.rb +3 -0
  44. data/lib/generators/ar_sync/install/install_generator.rb +87 -0
  45. data/lib/generators/ar_sync/types/types_generator.rb +11 -0
  46. data/package-lock.json +1115 -0
  47. data/package.json +19 -0
  48. data/src/core/ActioncableAdapter.ts +30 -0
  49. data/src/core/ArSyncApi.ts +75 -0
  50. data/src/core/ArSyncModelBase.ts +126 -0
  51. data/src/core/ConnectionAdapter.ts +5 -0
  52. data/src/core/ConnectionManager.ts +69 -0
  53. data/src/core/DataType.ts +73 -0
  54. data/src/core/hooksBase.ts +86 -0
  55. data/src/graph/ArSyncModel.ts +21 -0
  56. data/src/graph/ArSyncStore.ts +567 -0
  57. data/src/graph/hooks.ts +7 -0
  58. data/src/graph/index.ts +2 -0
  59. data/src/tree/ArSyncModel.ts +145 -0
  60. data/src/tree/ArSyncStore.ts +323 -0
  61. data/src/tree/hooks.ts +7 -0
  62. data/src/tree/index.ts +2 -0
  63. data/tree/ArSyncModel.d.ts +39 -0
  64. data/tree/ArSyncModel.js +143 -0
  65. data/tree/ArSyncStore.d.ts +21 -0
  66. data/tree/ArSyncStore.js +365 -0
  67. data/tree/hooks.d.ts +3 -0
  68. data/tree/hooks.js +10 -0
  69. data/tree/index.d.ts +2 -0
  70. data/tree/index.js +4 -0
  71. data/tsconfig.json +15 -0
  72. data/vendor/assets/javascripts/ar_sync_actioncable_adapter.js.erb +7 -0
  73. data/vendor/assets/javascripts/ar_sync_graph.js.erb +17 -0
  74. data/vendor/assets/javascripts/ar_sync_tree.js.erb +17 -0
  75. metadata +187 -0
data/src/tree/hooks.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { useArSyncFetch } from '../core/hooksBase'
2
+ import { useArSyncModelWithClass, Request, DataAndStatus } from '../core/hooksBase'
3
+ import ArSyncModel from './ArSyncModel'
4
+
5
+ export function useArSyncModel<T>(request: Request | null): DataAndStatus<T> {
6
+ return useArSyncModelWithClass<T>(ArSyncModel, request)
7
+ }
data/src/tree/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ import ArSyncModel from './ArSyncModel'
2
+ export default ArSyncModel
@@ -0,0 +1,39 @@
1
+ import ArSyncModelBase from '../core/ArSyncModelBase';
2
+ import ConnectionAdapter from '../core/ConnectionAdapter';
3
+ declare class ArSyncRecord {
4
+ immutable: any;
5
+ request: any;
6
+ subscriptions: any;
7
+ store: any;
8
+ retryLoadTimer: any;
9
+ data: any;
10
+ bufferTimer: any;
11
+ bufferedPatches: any;
12
+ eventListeners: any;
13
+ networkSubscription: any;
14
+ complete: boolean;
15
+ notfound?: boolean;
16
+ static connectionManager: any;
17
+ constructor(request: any, option?: {
18
+ immutable?: boolean | undefined;
19
+ });
20
+ release(): void;
21
+ unsubscribeAll(): void;
22
+ load(callback: any, retryCount?: number): void;
23
+ retryLoad(callback: any, retryCount: any): void;
24
+ patchReceived(patch: any): void;
25
+ subscribe(event: any, callback: any): {
26
+ unsubscribe: () => void;
27
+ };
28
+ trigger(event: any, arg?: any): void;
29
+ initializeStore(keys: any, data: any, option: any): void;
30
+ }
31
+ export default class ArSyncModel<T> extends ArSyncModelBase<T> {
32
+ static setConnectionAdapter(adapter: ConnectionAdapter): void;
33
+ static createRefModel(request: any, option: any): ArSyncRecord;
34
+ refManagerClass(): typeof ArSyncModel;
35
+ connectionManager(): any;
36
+ static _cache: {};
37
+ static cacheTimeout: number;
38
+ }
39
+ export {};
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ArSyncStore_1 = require("./ArSyncStore");
4
+ const ArSyncApi_1 = require("../core/ArSyncApi");
5
+ const ConnectionManager_1 = require("../core/ConnectionManager");
6
+ const ArSyncModelBase_1 = require("../core/ArSyncModelBase");
7
+ class ArSyncRecord {
8
+ constructor(request, option = {}) {
9
+ this.immutable = option.immutable ? true : false;
10
+ this.request = request;
11
+ this.subscriptions = [];
12
+ this.store = null;
13
+ this.data = null;
14
+ this.complete = false;
15
+ this.bufferedPatches = [];
16
+ this.eventListeners = { events: {}, serial: 0 };
17
+ this.networkSubscription = ArSyncRecord.connectionManager.subscribeNetwork((status) => {
18
+ if (this.notfound) {
19
+ this.trigger('connection', status);
20
+ return;
21
+ }
22
+ if (status) {
23
+ this.load(() => {
24
+ this.trigger('connection', status);
25
+ this.trigger('change', { path: [], value: this.data });
26
+ });
27
+ }
28
+ else {
29
+ this.unsubscribeAll();
30
+ this.trigger('connection', false);
31
+ }
32
+ });
33
+ this.load(() => {
34
+ this.trigger('load');
35
+ this.trigger('change', { path: [], value: this.data });
36
+ });
37
+ }
38
+ release() {
39
+ this.unsubscribeAll();
40
+ this.networkSubscription.unsubscribe();
41
+ }
42
+ unsubscribeAll() {
43
+ if (this.retryLoadTimer)
44
+ clearTimeout(this.retryLoadTimer);
45
+ for (const s of this.subscriptions)
46
+ s.unsubscribe();
47
+ this.subscriptions = [];
48
+ }
49
+ load(callback, retryCount = 0) {
50
+ ArSyncApi_1.default.syncFetch(this.request).then(syncData => {
51
+ const { keys, data, limit, order } = syncData;
52
+ this.initializeStore(keys, data, { limit, order, immutable: this.immutable });
53
+ if (callback)
54
+ callback(true, this.data);
55
+ }).catch(e => {
56
+ console.error(e);
57
+ if (e.retry) {
58
+ this.retryLoad(callback, retryCount + 1);
59
+ }
60
+ else {
61
+ this.initializeStore(null, null, null);
62
+ if (callback)
63
+ callback(false, this.data);
64
+ }
65
+ });
66
+ }
67
+ retryLoad(callback, retryCount) {
68
+ const sleepSeconds = Math.min(Math.pow(2, retryCount), 30);
69
+ this.retryLoadTimer = setTimeout(() => {
70
+ this.retryLoadTimer = null;
71
+ this.load(callback, retryCount);
72
+ }, sleepSeconds * 1000);
73
+ }
74
+ patchReceived(patch) {
75
+ const buffer = this.bufferedPatches;
76
+ buffer.push(patch);
77
+ if (this.bufferTimer)
78
+ return;
79
+ this.bufferTimer = setTimeout(() => {
80
+ this.bufferTimer = null;
81
+ this.bufferedPatches;
82
+ const buf = this.bufferedPatches;
83
+ this.bufferedPatches = [];
84
+ const { changes, events } = this.store.batchUpdate(buf);
85
+ this.data = this.store.data;
86
+ changes.forEach(change => this.trigger('change', change));
87
+ events.forEach(event => {
88
+ this.trigger(event.type, event.data);
89
+ });
90
+ }, 16);
91
+ }
92
+ subscribe(event, callback) {
93
+ let listeners = this.eventListeners.events[event];
94
+ if (!listeners)
95
+ this.eventListeners.events[event] = listeners = {};
96
+ const id = this.eventListeners.serial++;
97
+ listeners[id] = callback;
98
+ return { unsubscribe: () => { delete listeners[id]; } };
99
+ }
100
+ trigger(event, arg) {
101
+ const listeners = this.eventListeners.events[event];
102
+ if (!listeners)
103
+ return;
104
+ for (const id in listeners)
105
+ listeners[id](arg);
106
+ }
107
+ initializeStore(keys, data, option) {
108
+ this.complete = true;
109
+ if (!keys) {
110
+ this.notfound = true;
111
+ return;
112
+ }
113
+ this.notfound = false;
114
+ const query = this.request.query;
115
+ if (this.store) {
116
+ this.store.replaceData(data);
117
+ }
118
+ else {
119
+ this.store = new ArSyncStore_1.default(query, data, option);
120
+ this.data = this.store.data;
121
+ }
122
+ this.subscriptions = keys.map(key => {
123
+ return ArSyncRecord.connectionManager.subscribe(key, patch => this.patchReceived(patch));
124
+ });
125
+ }
126
+ }
127
+ class ArSyncModel extends ArSyncModelBase_1.default {
128
+ static setConnectionAdapter(adapter) {
129
+ ArSyncRecord.connectionManager = new ConnectionManager_1.default(adapter);
130
+ }
131
+ static createRefModel(request, option) {
132
+ return new ArSyncRecord(request, option);
133
+ }
134
+ refManagerClass() {
135
+ return ArSyncModel;
136
+ }
137
+ connectionManager() {
138
+ return ArSyncRecord.connectionManager;
139
+ }
140
+ }
141
+ ArSyncModel._cache = {};
142
+ ArSyncModel.cacheTimeout = 10 * 1000;
143
+ exports.default = ArSyncModel;
@@ -0,0 +1,21 @@
1
+ export default class ArSyncStore {
2
+ data: any;
3
+ query: any;
4
+ immutable: any;
5
+ constructor(query: any, data: any, option?: {
6
+ immutable?: boolean | undefined;
7
+ });
8
+ replaceData(data: any): void;
9
+ batchUpdate(patches: any): {
10
+ changes: any;
11
+ events: never[];
12
+ };
13
+ update(patch: any): {
14
+ changes: any;
15
+ events: never[];
16
+ };
17
+ _slicePatch(patchData: any, query: any): {};
18
+ _applyPatch(data: any, accessKeys: any, actualPath: any, updator: any, query: any, patchData: any): void;
19
+ _update(patch: any, updator: any, events: any): void;
20
+ static parseQuery(query: any, attrsonly?: any): {};
21
+ }
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Updator {
4
+ constructor(immutable) {
5
+ this.changes = [];
6
+ this.markedForFreezeObjects = [];
7
+ this.immutable = immutable;
8
+ }
9
+ static createFrozenObject(obj) {
10
+ if (!obj)
11
+ return obj;
12
+ if (obj.constructor === Array) {
13
+ obj = obj.map(el => Updator.createFrozenObject(el));
14
+ }
15
+ else if (typeof obj === 'object') {
16
+ obj = Object.assign({}, obj);
17
+ for (const key in obj) {
18
+ obj[key] = Updator.createFrozenObject(obj[key]);
19
+ }
20
+ }
21
+ Object.freeze(obj);
22
+ return obj;
23
+ }
24
+ replaceData(data, newData) {
25
+ if (this.immutable)
26
+ return Updator.createFrozenObject(newData);
27
+ return this.recursivelyReplaceData(data, newData);
28
+ }
29
+ recursivelyReplaceData(data, newData) {
30
+ const replaceArray = (as, bs) => {
31
+ const aids = {};
32
+ for (const a of as) {
33
+ if (!a.id)
34
+ return false;
35
+ aids[a.id] = a;
36
+ }
37
+ const order = {};
38
+ bs.forEach((b, i) => {
39
+ if (!b.id)
40
+ return false;
41
+ if (aids[b.id]) {
42
+ replaceObject(aids[b.id], b);
43
+ }
44
+ else {
45
+ as.push(b);
46
+ }
47
+ order[b.id] = i + 1;
48
+ });
49
+ as.sort((a, b) => {
50
+ const oa = order[a.id] || Infinity;
51
+ const ob = order[b.id] || Infinity;
52
+ return oa > ob ? +1 : oa < ob ? -1 : 0;
53
+ });
54
+ while (as.length && !order[as[as.length - 1].id])
55
+ as.pop();
56
+ return true;
57
+ };
58
+ const replaceObject = (aobj, bobj) => {
59
+ const keys = {};
60
+ for (const key in aobj)
61
+ keys[key] = true;
62
+ for (const key in bobj)
63
+ keys[key] = true;
64
+ for (const key in keys) {
65
+ const a = aobj[key];
66
+ const b = bobj[key];
67
+ if ((a instanceof Array) && (b instanceof Array)) {
68
+ if (!replaceArray(a, b))
69
+ aobj[key] = b;
70
+ }
71
+ else if (a && b && (typeof a === 'object') && (typeof b === 'object') && !(a instanceof Array) && !(b instanceof Array)) {
72
+ replaceObject(a, b);
73
+ }
74
+ else if (a !== b) {
75
+ aobj[key] = b;
76
+ }
77
+ }
78
+ };
79
+ replaceObject(data, newData);
80
+ return data;
81
+ }
82
+ mark(obj) {
83
+ if (!this.immutable)
84
+ return obj;
85
+ if (!Object.isFrozen(this.data))
86
+ return obj;
87
+ const mobj = (obj.constructor === Array) ? [...obj] : Object.assign({}, obj);
88
+ this.markedForFreezeObjects.push(mobj);
89
+ return mobj;
90
+ }
91
+ trace(data, path) {
92
+ path.forEach(key => {
93
+ if (this.immutable)
94
+ data[key] = this.mark(data[key]);
95
+ data = data[key];
96
+ });
97
+ return data;
98
+ }
99
+ assign(el, path, column, value, orderParam) {
100
+ if (this.immutable)
101
+ value = Updator.createFrozenObject(value);
102
+ if (el.constructor === Array && !el[column]) {
103
+ this.changes.push({
104
+ path: path.concat([value.id]),
105
+ target: el,
106
+ id: value.id,
107
+ valueWas: null,
108
+ value
109
+ });
110
+ const limitReached = orderParam && orderParam.limit != null && el.length === orderParam.limit;
111
+ let removed;
112
+ if (orderParam && orderParam.order == 'desc') {
113
+ el.unshift(value);
114
+ if (limitReached)
115
+ removed = el.pop();
116
+ }
117
+ else {
118
+ el.push(value);
119
+ if (limitReached)
120
+ removed = el.pop();
121
+ }
122
+ if (removed)
123
+ this.changes.push({
124
+ path: path.concat([removed.id]),
125
+ target: el,
126
+ id: removed.id,
127
+ valueWas: removed,
128
+ value: null
129
+ });
130
+ }
131
+ else if (!this.valueEquals(el[column], value)) {
132
+ this.changes.push({
133
+ path: path.concat([column]),
134
+ target: el,
135
+ column: column,
136
+ valueWas: el[column],
137
+ value
138
+ });
139
+ el[column] = value;
140
+ }
141
+ }
142
+ valueEquals(a, b) {
143
+ if (a === b)
144
+ return true;
145
+ if (!a || !b)
146
+ return a == b;
147
+ if (typeof a !== 'object')
148
+ return false;
149
+ if (typeof b !== 'object')
150
+ return false;
151
+ const ja = JSON.stringify(a);
152
+ const jb = JSON.stringify(b);
153
+ return ja === jb;
154
+ }
155
+ add(tree, accessKeys, path, column, value, orderParam) {
156
+ const root = this.mark(tree);
157
+ const data = this.trace(root, accessKeys);
158
+ if (data)
159
+ this.assign(data, path, column, value, orderParam);
160
+ return root;
161
+ }
162
+ remove(tree, accessKeys, path, column) {
163
+ const root = this.mark(tree);
164
+ let data = this.trace(root, accessKeys);
165
+ if (!data)
166
+ return root;
167
+ if (data.constructor === Array) {
168
+ this.changes.push({
169
+ path: path.concat([data[column].id]),
170
+ target: data,
171
+ id: data[column].id,
172
+ valueWas: data[column],
173
+ value: null
174
+ });
175
+ data.splice(column, 1);
176
+ }
177
+ else if (data[column] !== null) {
178
+ this.changes.push({
179
+ path: path.concat([column]),
180
+ target: data,
181
+ column: column,
182
+ valueWas: data[column],
183
+ value: null
184
+ });
185
+ data[column] = null;
186
+ }
187
+ return root;
188
+ }
189
+ cleanup() {
190
+ this.markedForFreezeObjects.forEach(mobj => Object.freeze(mobj));
191
+ }
192
+ }
193
+ class ArSyncStore {
194
+ constructor(query, data, option = {}) {
195
+ this.data = option.immutable ? Updator.createFrozenObject(data) : data;
196
+ this.query = ArSyncStore.parseQuery(query);
197
+ this.immutable = option.immutable;
198
+ }
199
+ replaceData(data) {
200
+ this.data = new Updator(this.immutable).replaceData(this.data, data);
201
+ }
202
+ batchUpdate(patches) {
203
+ const events = [];
204
+ const updator = new Updator(this.immutable);
205
+ patches.forEach(patch => this._update(patch, updator, events));
206
+ updator.cleanup();
207
+ return { changes: updator.changes, events };
208
+ }
209
+ update(patch) {
210
+ return this.batchUpdate([patch]);
211
+ }
212
+ _slicePatch(patchData, query) {
213
+ const obj = {};
214
+ for (const key in patchData) {
215
+ if (key === 'id' || query.attributes['*']) {
216
+ obj[key] = patchData[key];
217
+ }
218
+ else {
219
+ const subq = query.attributes[key];
220
+ if (subq) {
221
+ obj[subq.column || key] = patchData[key];
222
+ }
223
+ }
224
+ }
225
+ return obj;
226
+ }
227
+ _applyPatch(data, accessKeys, actualPath, updator, query, patchData) {
228
+ for (const key in patchData) {
229
+ const subq = query.attributes[key];
230
+ const value = patchData[key];
231
+ if (subq || query.attributes['*']) {
232
+ const subcol = (subq && subq.column) || key;
233
+ if (data[subcol] !== value) {
234
+ this.data = updator.add(this.data, accessKeys, actualPath, subcol, value);
235
+ }
236
+ }
237
+ }
238
+ }
239
+ _update(patch, updator, events) {
240
+ const { action, path } = patch;
241
+ const patchData = patch.data;
242
+ let query = this.query;
243
+ let data = this.data;
244
+ const actualPath = [];
245
+ const accessKeys = [];
246
+ for (let i = 0; i < path.length - 1; i++) {
247
+ const nameOrId = path[i];
248
+ if (typeof (nameOrId) === 'number') {
249
+ const idx = data.findIndex(o => o.id === nameOrId);
250
+ if (idx < 0)
251
+ return;
252
+ actualPath.push(nameOrId);
253
+ accessKeys.push(idx);
254
+ data = data[idx];
255
+ }
256
+ else {
257
+ const { attributes } = query;
258
+ if (!attributes[nameOrId])
259
+ return;
260
+ const column = attributes[nameOrId].column || nameOrId;
261
+ query = attributes[nameOrId];
262
+ actualPath.push(column);
263
+ accessKeys.push(column);
264
+ data = data[column];
265
+ }
266
+ if (!data)
267
+ return;
268
+ }
269
+ const nameOrId = path[path.length - 1];
270
+ let id, idx, column, target = data;
271
+ if (typeof (nameOrId) === 'number') {
272
+ id = nameOrId;
273
+ idx = data.findIndex(o => o.id === id);
274
+ target = data[idx];
275
+ }
276
+ else if (nameOrId) {
277
+ const { attributes } = query;
278
+ if (!attributes[nameOrId])
279
+ return;
280
+ column = attributes[nameOrId].column || nameOrId;
281
+ query = attributes[nameOrId];
282
+ target = data[column];
283
+ }
284
+ if (action === 'create') {
285
+ const obj = this._slicePatch(patchData, query);
286
+ if (column) {
287
+ this.data = updator.add(this.data, accessKeys, actualPath, column, obj);
288
+ }
289
+ else if (!target) {
290
+ const ordering = Object.assign({}, patch.ordering);
291
+ const limitOverride = query.params && query.params.limit;
292
+ ordering.order = query.params && query.params.order || ordering.order;
293
+ if (ordering.limit == null || limitOverride != null && limitOverride < ordering.limit)
294
+ ordering.limit = limitOverride;
295
+ this.data = updator.add(this.data, accessKeys, actualPath, data.length, obj, ordering);
296
+ }
297
+ return;
298
+ }
299
+ if (action === 'destroy') {
300
+ if (column) {
301
+ this.data = updator.remove(this.data, accessKeys, actualPath, column);
302
+ }
303
+ else if (idx >= 0) {
304
+ this.data = updator.remove(this.data, accessKeys, actualPath, idx);
305
+ }
306
+ return;
307
+ }
308
+ if (!target)
309
+ return;
310
+ if (column) {
311
+ actualPath.push(column);
312
+ accessKeys.push(column);
313
+ }
314
+ else if (id) {
315
+ actualPath.push(id);
316
+ accessKeys.push(idx);
317
+ }
318
+ if (action === 'update') {
319
+ this._applyPatch(target, accessKeys, actualPath, updator, query, patchData);
320
+ }
321
+ else {
322
+ const eventData = { target, path: actualPath, data: patchData.data };
323
+ events.push({ type: patchData.type, data: eventData });
324
+ }
325
+ }
326
+ static parseQuery(query, attrsonly) {
327
+ const attributes = {};
328
+ let column = null;
329
+ let params = null;
330
+ if (query.constructor !== Array)
331
+ query = [query];
332
+ for (const arg of query) {
333
+ if (typeof (arg) === 'string') {
334
+ attributes[arg] = {};
335
+ }
336
+ else if (typeof (arg) === 'object') {
337
+ for (const key in arg) {
338
+ const value = arg[key];
339
+ if (attrsonly) {
340
+ attributes[key] = this.parseQuery(value);
341
+ continue;
342
+ }
343
+ if (key === 'attributes') {
344
+ const child = this.parseQuery(value, true);
345
+ for (const k in child)
346
+ attributes[k] = child[k];
347
+ }
348
+ else if (key === 'as') {
349
+ column = value;
350
+ }
351
+ else if (key === 'params') {
352
+ params = value;
353
+ }
354
+ else {
355
+ attributes[key] = this.parseQuery(value);
356
+ }
357
+ }
358
+ }
359
+ }
360
+ if (attrsonly)
361
+ return attributes;
362
+ return { attributes, column, params };
363
+ }
364
+ }
365
+ exports.default = ArSyncStore;