prostgles-client 4.0.357 → 4.0.359
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/SyncedTable/SyncedTable.d.ts +15 -46
- package/dist/SyncedTable/SyncedTable.d.ts.map +1 -1
- package/dist/SyncedTable/SyncedTable.js +59 -223
- package/dist/SyncedTable/createSync.d.ts +9 -0
- package/dist/SyncedTable/createSync.d.ts.map +1 -0
- package/dist/SyncedTable/createSync.js +190 -0
- package/dist/SyncedTable/createSyncDataStore.d.ts +19 -0
- package/dist/SyncedTable/createSyncDataStore.d.ts.map +1 -0
- package/dist/SyncedTable/createSyncDataStore.js +127 -0
- package/dist/SyncedTable/createSyncStateUtils.d.ts +25 -0
- package/dist/SyncedTable/createSyncStateUtils.d.ts.map +1 -0
- package/dist/SyncedTable/createSyncStateUtils.js +146 -0
- package/dist/SyncedTable/createSyncSubscriptionManager.d.ts +11 -0
- package/dist/SyncedTable/createSyncSubscriptionManager.d.ts.map +1 -0
- package/dist/SyncedTable/createSyncSubscriptionManager.js +230 -0
- package/dist/getDbHandler.d.ts.map +1 -1
- package/dist/getDbHandler.js +13 -26
- package/dist/getSyncHandler.d.ts +2 -2
- package/dist/getSyncHandler.d.ts.map +1 -1
- package/dist/getSyncHandler.js +31 -20
- package/dist/getSyncHandlerV2.d.ts +14 -0
- package/dist/getSyncHandlerV2.d.ts.map +1 -0
- package/dist/getSyncHandlerV2.js +41 -0
- package/dist/index.js +1 -1
- package/dist/index.no-sync.js +1 -1
- package/dist/prostgles.d.ts +13 -7
- package/dist/prostgles.d.ts.map +1 -1
- package/dist/prostgles.js +0 -1
- package/package.json +2 -2
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSync = void 0;
|
|
4
|
+
const prostgles_types_1 = require("prostgles-types");
|
|
5
|
+
const WAL_1 = require("prostgles-types/dist/WAL");
|
|
6
|
+
const createSyncDataStore_1 = require("./createSyncDataStore");
|
|
7
|
+
const createSyncStateUtils_1 = require("./createSyncStateUtils");
|
|
8
|
+
const createSyncSubscriptionManager_1 = require("./createSyncSubscriptionManager");
|
|
9
|
+
const SyncedTable_1 = require("./SyncedTable");
|
|
10
|
+
const createSync = async (socket, options) => {
|
|
11
|
+
var _a;
|
|
12
|
+
const stateUtils = (0, createSyncStateUtils_1.createSyncStateUtils)(socket, options);
|
|
13
|
+
const { state, onDebug, id_fields, synced_field, throttle, batch_size, columns, _syncInfo, _sync, filter, } = stateUtils;
|
|
14
|
+
const store = (0, createSyncDataStore_1.createSyncDataStore)({ ..._syncInfo, columns, filter });
|
|
15
|
+
const onError = (_a = options.onError) !== null && _a !== void 0 ? _a : function (err) {
|
|
16
|
+
console.error("Sync internal error: ", err);
|
|
17
|
+
};
|
|
18
|
+
const onSyncRequest = (syncBatchParams) => {
|
|
19
|
+
let clientSyncInfo = { c_lr: undefined, c_fr: undefined, c_count: 0 };
|
|
20
|
+
const batch = store.getBatch(syncBatchParams);
|
|
21
|
+
if (batch.length) {
|
|
22
|
+
clientSyncInfo = {
|
|
23
|
+
c_fr: store.getRowSyncObj(batch[0]),
|
|
24
|
+
c_lr: store.getRowSyncObj(batch[batch.length - 1]),
|
|
25
|
+
c_count: batch.length,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
onDebug({ command: "onUpdates", data: { syncBatchParams, batch, clientSyncInfo } });
|
|
29
|
+
return clientSyncInfo;
|
|
30
|
+
};
|
|
31
|
+
const onPullRequest = async (syncBatchParams) => {
|
|
32
|
+
// if(this.getDeleted().length){
|
|
33
|
+
// await this.syncDeleted();
|
|
34
|
+
// }
|
|
35
|
+
const data = store.getBatch(syncBatchParams);
|
|
36
|
+
await onDebug({ command: "onPullRequest", data: { syncBatchParams, data } });
|
|
37
|
+
return { data };
|
|
38
|
+
};
|
|
39
|
+
const onUpdates = async (onUpdatesParams) => {
|
|
40
|
+
await onDebug({ command: "onUpdates", data: { onUpdatesParams } });
|
|
41
|
+
if ("err" in onUpdatesParams && onUpdatesParams.err) {
|
|
42
|
+
onError(onUpdatesParams.err);
|
|
43
|
+
}
|
|
44
|
+
else if ("isSynced" in onUpdatesParams && onUpdatesParams.isSynced && !state.isSynced) {
|
|
45
|
+
state.isSynced = onUpdatesParams.isSynced;
|
|
46
|
+
const items = store.getItems().map((d) => ({ ...d }));
|
|
47
|
+
store.setItems([]);
|
|
48
|
+
const updateItems = items.map((d) => ({
|
|
49
|
+
idObj: store.getIdObj(d),
|
|
50
|
+
delta: { ...d },
|
|
51
|
+
}));
|
|
52
|
+
await upsert(updateItems, true);
|
|
53
|
+
}
|
|
54
|
+
else if ("data" in onUpdatesParams) {
|
|
55
|
+
/* Delta left empty so we can prepare it here */
|
|
56
|
+
const updateItems = onUpdatesParams.data.map((d) => {
|
|
57
|
+
return {
|
|
58
|
+
idObj: store.getIdObj(d),
|
|
59
|
+
delta: d,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
await upsert(updateItems, true);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.error("Unexpected onUpdates");
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
};
|
|
69
|
+
const opts = {
|
|
70
|
+
id_fields,
|
|
71
|
+
synced_field,
|
|
72
|
+
throttle,
|
|
73
|
+
};
|
|
74
|
+
const dbSync = await _sync({ onSyncRequest, onPullRequest, onUpdates });
|
|
75
|
+
/**
|
|
76
|
+
* Some syncs can be read only. Any changes are local
|
|
77
|
+
*/
|
|
78
|
+
const wal = new WAL_1.WAL({
|
|
79
|
+
...opts,
|
|
80
|
+
batch_size,
|
|
81
|
+
onSendStart: () => {
|
|
82
|
+
if (isWindowDefined) {
|
|
83
|
+
window.onbeforeunload = function confirmExit() {
|
|
84
|
+
return "Data may be lost. Are you sure?";
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
onSend: async (data, walData) => {
|
|
89
|
+
const _data = walData.map((d) => d.current);
|
|
90
|
+
if (!_data.length)
|
|
91
|
+
return [];
|
|
92
|
+
return dbSync.syncData(data);
|
|
93
|
+
},
|
|
94
|
+
onSendEnd: () => {
|
|
95
|
+
if (isWindowDefined)
|
|
96
|
+
window.onbeforeunload = null;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* Upserts data locally -> notify subs -> sends to server if required
|
|
101
|
+
* synced_field is populated if data is not from server
|
|
102
|
+
* @param items <{ idObj: object, delta: object }[]> Data items that changed
|
|
103
|
+
* @param from_server : <boolean> If false then updates will be sent to server
|
|
104
|
+
*/
|
|
105
|
+
const upsert = async (items, from_server = false) => {
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
107
|
+
if ((!items || !items.length) && !from_server)
|
|
108
|
+
throw "No data provided for upsert";
|
|
109
|
+
/* If data has been deleted then wait for it to sync with server before continuing */
|
|
110
|
+
// if(from_server && this.getDeleted().length){
|
|
111
|
+
// await this.syncDeleted();
|
|
112
|
+
// }
|
|
113
|
+
const results = [];
|
|
114
|
+
let status;
|
|
115
|
+
const walItems = [];
|
|
116
|
+
await Promise.all(items.map(async (item, i) => {
|
|
117
|
+
var _a;
|
|
118
|
+
// let d = { ...item.idObj, ...item.delta };
|
|
119
|
+
const idObj = { ...item.idObj };
|
|
120
|
+
let delta = { ...item.delta };
|
|
121
|
+
/* Convert undefined to null because:
|
|
122
|
+
1) JSON.stringify drops these keys
|
|
123
|
+
2) Postgres does not have undefined
|
|
124
|
+
*/
|
|
125
|
+
Object.keys(delta).map((k) => {
|
|
126
|
+
if (delta[k] === undefined)
|
|
127
|
+
delta[k] = null;
|
|
128
|
+
});
|
|
129
|
+
if (!from_server) {
|
|
130
|
+
store.checkItemCols({ ...item.delta, ...item.idObj });
|
|
131
|
+
}
|
|
132
|
+
const oldItem = store.getItem(idObj);
|
|
133
|
+
/* Calc delta if missing or if from server */
|
|
134
|
+
if ((from_server || (0, prostgles_types_1.isEmpty)(delta)) && !(0, prostgles_types_1.isEmpty)(oldItem)) {
|
|
135
|
+
delta = store.getDelta(oldItem || {}, delta);
|
|
136
|
+
}
|
|
137
|
+
/* Add synced if local update */
|
|
138
|
+
/** Will need to check client clock shift */
|
|
139
|
+
if (!from_server) {
|
|
140
|
+
delta[synced_field] = Date.now();
|
|
141
|
+
}
|
|
142
|
+
let newItem = { ...oldItem, ...delta, ...idObj };
|
|
143
|
+
if (oldItem && !from_server) {
|
|
144
|
+
/**
|
|
145
|
+
* Merge deep
|
|
146
|
+
*/
|
|
147
|
+
if ((_a = item.opts) === null || _a === void 0 ? void 0 : _a.deepMerge) {
|
|
148
|
+
newItem = (0, SyncedTable_1.mergeDeep)({ ...oldItem, ...idObj }, { ...delta });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/* Update existing -> Expecting delta */
|
|
152
|
+
if (oldItem) {
|
|
153
|
+
status = oldItem[synced_field] < newItem[synced_field] ? "updated" : "unchanged";
|
|
154
|
+
/* Insert new item */
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
status = "inserted";
|
|
158
|
+
}
|
|
159
|
+
store.setItem(newItem);
|
|
160
|
+
// if(!status) throw "changeInfo status missing"
|
|
161
|
+
const changeInfo = { idObj, delta, oldItem, newItem, status, from_server };
|
|
162
|
+
/* IF Local updates then Keep any existing oldItem to revert to the earliest working item */
|
|
163
|
+
if (!from_server) {
|
|
164
|
+
walItems.push({
|
|
165
|
+
initial: oldItem,
|
|
166
|
+
current: { ...newItem },
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (!(0, prostgles_types_1.isEmpty)(changeInfo.delta)) {
|
|
170
|
+
results.push(changeInfo);
|
|
171
|
+
}
|
|
172
|
+
/* TODO: Deletes from server */
|
|
173
|
+
// if(allow_deletes){
|
|
174
|
+
// items = this.getItems();
|
|
175
|
+
// }
|
|
176
|
+
return true;
|
|
177
|
+
})).catch((err) => {
|
|
178
|
+
console.error("SyncedTable failed upsert: ", err);
|
|
179
|
+
});
|
|
180
|
+
subscriptionManager.notifyWal.addData(results.map((d) => ({ initial: d.oldItem, current: d.newItem })));
|
|
181
|
+
/* Push to server */
|
|
182
|
+
if (!from_server && walItems.length) {
|
|
183
|
+
wal.addData(walItems);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const subscriptionManager = (0, createSyncSubscriptionManager_1.createSyncSubscriptionManager)({ id_fields, synced_field }, store, stateUtils, upsert);
|
|
187
|
+
return subscriptionManager;
|
|
188
|
+
};
|
|
189
|
+
exports.createSync = createSync;
|
|
190
|
+
const isWindowDefined = typeof window !== "undefined";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SyncInfo } from "lib/prostgles";
|
|
2
|
+
import { type AnyObject, type SyncBatchParams } from "prostgles-types";
|
|
3
|
+
import { type SyncedTableOptions } from "./SyncedTable";
|
|
4
|
+
export declare const createSyncDataStore: ({ id_fields, synced_field, filter, columns, }: Pick<SyncInfo, "id_fields" | "synced_field"> & Pick<SyncedTableOptions, "filter" | "columns">) => {
|
|
5
|
+
getItems: <T extends AnyObject = AnyObject>() => T[];
|
|
6
|
+
getBatch: ({ from_synced, to_synced, offset, limit }?: SyncBatchParams) => {
|
|
7
|
+
[x: string]: any;
|
|
8
|
+
}[];
|
|
9
|
+
getIdObj: (d: AnyObject) => AnyObject;
|
|
10
|
+
getRowSyncObj: (d: AnyObject) => AnyObject;
|
|
11
|
+
getDelta: (o: AnyObject, n: AnyObject) => AnyObject;
|
|
12
|
+
setItems: (_items: AnyObject[]) => void;
|
|
13
|
+
checkItemCols: (item: AnyObject) => void;
|
|
14
|
+
setItem: (_item: AnyObject, isFullData?: boolean, deleteItem?: boolean) => void;
|
|
15
|
+
getItem: <T = AnyObject>(idObj: Partial<T>) => T | undefined;
|
|
16
|
+
matchesIdObj: (a: AnyObject | undefined, b: AnyObject | undefined) => boolean;
|
|
17
|
+
matchesFilter: (item: AnyObject | undefined) => boolean;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=createSyncDataStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSyncDataStore.d.ts","sourceRoot":"","sources":["../../lib/SyncedTable/createSyncDataStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAML,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEpE,eAAO,MAAM,mBAAmB,GAAI,+CAKjC,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,cAAc,CAAC,GAC7C,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,SAAS,CAAC;eA2B5B,CAAC,SAAS,SAAS,mBAAiB,CAAC,EAAE;2DAyBZ,eAAe;;;kBA3CvC,SAAS;uBAOJ,SAAS;kBA0Fd,SAAS,KAAK,SAAS,KAAG,SAAS;uBA3B9B,SAAS,EAAE,KAAG,IAAI;0BAkBf,SAAS;qBA7Bd,SAAS;cAoBhB,CAAC,qBAAqB,OAAO,CAAC,CAAC,CAAC,KAAG,CAAC,GAAG,SAAS;sBA0CxC,SAAS,GAAG,SAAS,KAAK,SAAS,GAAG,SAAS;0BAN3C,SAAS,GAAG,SAAS;CAuBnD,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSyncDataStore = void 0;
|
|
4
|
+
const prostgles_types_1 = require("prostgles-types");
|
|
5
|
+
const SyncedTable_1 = require("./SyncedTable");
|
|
6
|
+
const createSyncDataStore = ({ id_fields, synced_field, filter, columns, }) => {
|
|
7
|
+
const itemsMap = new Map();
|
|
8
|
+
const idFieldsSorted = id_fields.sort();
|
|
9
|
+
const syncFieldSorted = [synced_field, ...id_fields].sort();
|
|
10
|
+
const getIdStr = (d) => {
|
|
11
|
+
return idFieldsSorted.map((key) => `${d[key] || ""}`).join(".");
|
|
12
|
+
};
|
|
13
|
+
const getIdObj = (d) => {
|
|
14
|
+
const res = {};
|
|
15
|
+
idFieldsSorted.map((key) => {
|
|
16
|
+
res[key] = d[key];
|
|
17
|
+
});
|
|
18
|
+
return res;
|
|
19
|
+
};
|
|
20
|
+
const getRowSyncObj = (d) => {
|
|
21
|
+
const res = {};
|
|
22
|
+
syncFieldSorted.map((key) => {
|
|
23
|
+
res[key] = d[key];
|
|
24
|
+
});
|
|
25
|
+
return res;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Returns the current data ordered by synced_field ASC and matching the main filter;
|
|
29
|
+
*/
|
|
30
|
+
const getItems = () => {
|
|
31
|
+
let items = [];
|
|
32
|
+
items = Array.from(itemsMap.values()).map((d) => ({ ...d }));
|
|
33
|
+
const syncFields = [synced_field, ...id_fields.sort()];
|
|
34
|
+
items = items
|
|
35
|
+
.filter((d) => {
|
|
36
|
+
return !filter || !(0, prostgles_types_1.getKeys)(filter).find((key) => d[key] !== filter[key]);
|
|
37
|
+
})
|
|
38
|
+
.sort((a, b) => syncFields
|
|
39
|
+
.map((key) => (a[key] < b[key] ? -1
|
|
40
|
+
: a[key] > b[key] ? 1
|
|
41
|
+
: 0))
|
|
42
|
+
.find((v) => v));
|
|
43
|
+
return (0, SyncedTable_1.quickClone)(items);
|
|
44
|
+
};
|
|
45
|
+
const getBatch = ({ from_synced, to_synced, offset, limit } = { offset: 0, limit: undefined }) => {
|
|
46
|
+
const items = getItems();
|
|
47
|
+
let res = items
|
|
48
|
+
.map((c) => ({ ...c }))
|
|
49
|
+
.filter((c) => (!Number.isFinite(from_synced) || +c[synced_field] >= +from_synced) &&
|
|
50
|
+
(!Number.isFinite(to_synced) || +c[synced_field] <= +to_synced));
|
|
51
|
+
if (offset || limit) {
|
|
52
|
+
res = res.splice(offset !== null && offset !== void 0 ? offset : 0, limit || res.length);
|
|
53
|
+
}
|
|
54
|
+
return res;
|
|
55
|
+
};
|
|
56
|
+
const setItem = (_item, isFullData = false, deleteItem = false) => {
|
|
57
|
+
var _a;
|
|
58
|
+
const item = (0, SyncedTable_1.quickClone)(_item);
|
|
59
|
+
const id = getIdStr(item);
|
|
60
|
+
if (deleteItem) {
|
|
61
|
+
itemsMap.delete(id);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const existing = (_a = itemsMap.get(id)) !== null && _a !== void 0 ? _a : {};
|
|
65
|
+
itemsMap.set(id, isFullData ? { ...item } : { ...existing, ...item });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const setItems = (_items) => {
|
|
69
|
+
const items = (0, SyncedTable_1.quickClone)(_items);
|
|
70
|
+
itemsMap.clear();
|
|
71
|
+
items.forEach((item) => {
|
|
72
|
+
const id = getIdStr(item);
|
|
73
|
+
itemsMap.set(id, { ...item });
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const getItem = (idObj) => {
|
|
77
|
+
const d = itemsMap.get(getIdStr(idObj));
|
|
78
|
+
return (0, SyncedTable_1.quickClone)(d);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Ensures that all object keys match valid column names
|
|
82
|
+
*/
|
|
83
|
+
const checkItemCols = (item) => {
|
|
84
|
+
if (columns.length) {
|
|
85
|
+
const badCols = Object.keys({ ...item }).filter((k) => !columns.find((c) => c.name === k));
|
|
86
|
+
if (badCols.length) {
|
|
87
|
+
throw `Unexpected columns in sync item update: ` + badCols.join(", ");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const getDelta = (o, n) => {
|
|
92
|
+
if ((0, prostgles_types_1.isEmpty)(o))
|
|
93
|
+
return { ...n };
|
|
94
|
+
return Object.fromEntries(Object.entries({ ...n })
|
|
95
|
+
.filter(([k]) => !id_fields.includes(k))
|
|
96
|
+
.map(([k, v]) => {
|
|
97
|
+
if (!(0, prostgles_types_1.isEqual)(v, o[k])) {
|
|
98
|
+
const vClone = (0, prostgles_types_1.isObject)(v) ? { ...v }
|
|
99
|
+
: Array.isArray(v) ? v.slice(0)
|
|
100
|
+
: v;
|
|
101
|
+
return [k, vClone];
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.filter(prostgles_types_1.isDefined));
|
|
105
|
+
};
|
|
106
|
+
const matchesFilter = (item) => {
|
|
107
|
+
return Boolean(item &&
|
|
108
|
+
(!filter || (0, prostgles_types_1.isEmpty)(filter) || !Object.keys(filter).find((k) => filter[k] !== item[k])));
|
|
109
|
+
};
|
|
110
|
+
const matchesIdObj = (a, b) => {
|
|
111
|
+
return Boolean(a && b && !id_fields.sort().find((k) => a[k] !== b[k]));
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
getItems,
|
|
115
|
+
getBatch,
|
|
116
|
+
getIdObj,
|
|
117
|
+
getRowSyncObj,
|
|
118
|
+
getDelta,
|
|
119
|
+
setItems,
|
|
120
|
+
checkItemCols,
|
|
121
|
+
setItem,
|
|
122
|
+
getItem,
|
|
123
|
+
matchesIdObj,
|
|
124
|
+
matchesFilter,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
exports.createSyncDataStore = createSyncDataStore;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type SyncDebugEvent, type SyncInfo } from "lib/prostgles";
|
|
2
|
+
import { type ClientSyncHandles } from "prostgles-types";
|
|
3
|
+
import type { Socket } from "socket.io-client";
|
|
4
|
+
import type { SyncedTableOptions } from "./SyncedTable";
|
|
5
|
+
export declare const createSyncStateUtils: (socket: Socket, options: Omit<SyncedTableOptions, "onReady">) => {
|
|
6
|
+
state: {
|
|
7
|
+
isSynced: boolean;
|
|
8
|
+
};
|
|
9
|
+
onDebug: (evt: Omit<SyncDebugEvent, "type" | "tableName" | "channelName" | "options">) => void | Promise<void> | undefined;
|
|
10
|
+
id_fields: string[];
|
|
11
|
+
synced_field: string;
|
|
12
|
+
throttle: number;
|
|
13
|
+
batch_size: number;
|
|
14
|
+
columns: import("prostgles-types").ValidatedColumnInfo[];
|
|
15
|
+
_syncInfo: import("prostgles-types").SyncTableInfo;
|
|
16
|
+
_sync: (handles: ClientSyncHandles) => Promise<{
|
|
17
|
+
sync_info: SyncInfo;
|
|
18
|
+
unsync: () => Promise<unknown>;
|
|
19
|
+
syncData: (data?: import("prostgles-types").AnyObject[], deleted?: import("prostgles-types").AnyObject[], cb?: (err?: any) => void) => void;
|
|
20
|
+
}>;
|
|
21
|
+
filter: import("prostgles-types").EqualityFilter<import("prostgles-types").AnyObject>;
|
|
22
|
+
select: import("prostgles-types").FieldFilter;
|
|
23
|
+
tableHandler: Partial<import("prostgles-types").TableHandler & import("lib/prostgles").TableHandlerClientMethods<import("prostgles-types").AnyObject, void>>;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=createSyncStateUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSyncStateUtils.d.ts","sourceRoot":"","sources":["../../lib/SyncedTable/createSyncStateUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAErE,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,EACd,SAAS,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC;;;;mBAKtB,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;;;;;;;qBAyB9D,iBAAiB;;;2HAkIi6B,CAAC;;;;;CADl9B,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSyncStateUtils = void 0;
|
|
4
|
+
const prostgles_types_1 = require("prostgles-types");
|
|
5
|
+
const createSyncStateUtils = (socket, options) => {
|
|
6
|
+
const state = { isSynced: false };
|
|
7
|
+
const { db, name, select = "*", filter = {}, columns } = options;
|
|
8
|
+
const channelName = (0, prostgles_types_1.getSyncChannelName)({ filter, select, tableName: name });
|
|
9
|
+
const onDebug = (evt) => {
|
|
10
|
+
var _a;
|
|
11
|
+
return (_a = options.onDebug) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
12
|
+
...evt,
|
|
13
|
+
type: "sync",
|
|
14
|
+
tableName: name,
|
|
15
|
+
channelName,
|
|
16
|
+
options,
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
onDebug({ command: "create", data: { name, filter, select } });
|
|
20
|
+
const tableHandler = db[name];
|
|
21
|
+
if (!tableHandler) {
|
|
22
|
+
throw `${name} table not found in db`;
|
|
23
|
+
}
|
|
24
|
+
const { _syncInfo } = tableHandler;
|
|
25
|
+
if (!_syncInfo) {
|
|
26
|
+
throw `${name} table does not support sync`;
|
|
27
|
+
}
|
|
28
|
+
const { id_fields, synced_field, throttle = 100, batch_size = 50 } = _syncInfo;
|
|
29
|
+
if (!id_fields.length || !synced_field) {
|
|
30
|
+
throw "id_fields/synced_field missing";
|
|
31
|
+
}
|
|
32
|
+
const _sync = async (handles) => {
|
|
33
|
+
const sync_info = await new Promise((resolve, reject) => {
|
|
34
|
+
socket.emit(prostgles_types_1.CHANNEL_PREFIX, {
|
|
35
|
+
tableName: name,
|
|
36
|
+
command: "sync",
|
|
37
|
+
param1: filter,
|
|
38
|
+
param2: { select },
|
|
39
|
+
}, (err, syncInfo) => {
|
|
40
|
+
if (err) {
|
|
41
|
+
console.error(err);
|
|
42
|
+
reject(err);
|
|
43
|
+
}
|
|
44
|
+
else if (syncInfo) {
|
|
45
|
+
const { id_fields, synced_field, channelName } = syncInfo;
|
|
46
|
+
socket.emit(channelName, { onSyncRequest: handles.onSyncRequest({}) }, (response) => {
|
|
47
|
+
console.log(response);
|
|
48
|
+
});
|
|
49
|
+
resolve({ id_fields, synced_field, channelName });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
const onCall = function (data, cb) {
|
|
54
|
+
/*
|
|
55
|
+
Client will:
|
|
56
|
+
1. Send last_synced on(onSyncRequest)
|
|
57
|
+
2. Send data >= server_synced on(onPullRequest)
|
|
58
|
+
3. Send data on CRUD emit(data.data)
|
|
59
|
+
4. Upsert data.data on(data.data)
|
|
60
|
+
*/
|
|
61
|
+
if (!data)
|
|
62
|
+
return;
|
|
63
|
+
const { onUpdates, onSyncRequest, onPullRequest } = handles;
|
|
64
|
+
// syncedTables.get(channelName)?.then((syncedTable) => {
|
|
65
|
+
// onDebug?.({
|
|
66
|
+
// type: "sync",
|
|
67
|
+
// command:
|
|
68
|
+
// data.data ? "onUpdates"
|
|
69
|
+
// : data.onSyncRequest ? "onSyncRequest"
|
|
70
|
+
// : "onPullRequest",
|
|
71
|
+
// tableName,
|
|
72
|
+
// channelName,
|
|
73
|
+
// data,
|
|
74
|
+
// options: { n filter, select },
|
|
75
|
+
// });
|
|
76
|
+
// });
|
|
77
|
+
if (data.data) {
|
|
78
|
+
Promise.resolve(onUpdates(data))
|
|
79
|
+
.then(() => {
|
|
80
|
+
cb({ ok: true });
|
|
81
|
+
})
|
|
82
|
+
.catch((err) => {
|
|
83
|
+
cb({ err });
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else if (data.onSyncRequest) {
|
|
87
|
+
Promise.resolve(onSyncRequest(data.onSyncRequest))
|
|
88
|
+
.then((res) => cb({ onSyncRequest: res }))
|
|
89
|
+
.catch((err) => {
|
|
90
|
+
cb({ err });
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else if (data.onPullRequest) {
|
|
94
|
+
Promise.resolve(onPullRequest(data.onPullRequest))
|
|
95
|
+
.then((result) => {
|
|
96
|
+
cb(result);
|
|
97
|
+
})
|
|
98
|
+
.catch((err) => {
|
|
99
|
+
cb({ err });
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log("unexpected response");
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
socket.on(channelName, onCall);
|
|
107
|
+
const syncData = function (data, deleted, cb) {
|
|
108
|
+
socket.emit(channelName, {
|
|
109
|
+
onSyncRequest: {
|
|
110
|
+
...handles.onSyncRequest({}),
|
|
111
|
+
...{ data },
|
|
112
|
+
...{ deleted },
|
|
113
|
+
},
|
|
114
|
+
}, !cb ? null : ((response) => {
|
|
115
|
+
cb(response);
|
|
116
|
+
}));
|
|
117
|
+
};
|
|
118
|
+
const unsync = () => {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
socket.emit(channelName + "unsync", {}, (err, res) => {
|
|
121
|
+
if (err)
|
|
122
|
+
reject(err);
|
|
123
|
+
else
|
|
124
|
+
resolve(res);
|
|
125
|
+
});
|
|
126
|
+
socket.removeListener(channelName, onCall);
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
return { sync_info, unsync, syncData };
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
state,
|
|
133
|
+
onDebug,
|
|
134
|
+
id_fields,
|
|
135
|
+
synced_field,
|
|
136
|
+
throttle,
|
|
137
|
+
batch_size,
|
|
138
|
+
columns,
|
|
139
|
+
_syncInfo,
|
|
140
|
+
_sync,
|
|
141
|
+
filter,
|
|
142
|
+
select,
|
|
143
|
+
tableHandler,
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
exports.createSyncStateUtils = createSyncStateUtils;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AnyObject, SyncConfig } from "prostgles-types";
|
|
2
|
+
import { WAL } from "prostgles-types/dist/WAL";
|
|
3
|
+
import type { createSyncDataStore } from "./createSyncDataStore";
|
|
4
|
+
import type { createSyncStateUtils } from "./createSyncStateUtils";
|
|
5
|
+
import type { ItemUpdate, MultiChangeListener, MultiSyncHandles, SingleChangeListener, SingleSyncHandles } from "./SyncedTable";
|
|
6
|
+
export declare const createSyncSubscriptionManager: ({ id_fields, synced_field }: Omit<SyncConfig, "channelName">, store: ReturnType<typeof createSyncDataStore>, stateUtils: ReturnType<typeof createSyncStateUtils>, upsert: (items: ItemUpdate[], from_server?: boolean) => Promise<void>) => {
|
|
7
|
+
sync: <T extends AnyObject = AnyObject>(onChange: MultiChangeListener<T>, handlesOnData?: boolean) => MultiSyncHandles<T>;
|
|
8
|
+
syncOne: <T extends AnyObject = AnyObject, Full extends boolean = false>(idObj: Partial<T>, onChange: SingleChangeListener<T, Full>, handlesOnData?: boolean) => SingleSyncHandles<T, Full>;
|
|
9
|
+
notifyWal: WAL;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=createSyncSubscriptionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSyncSubscriptionManager.d.ts","sourceRoot":"","sources":["../../lib/SyncedTable/createSyncSubscriptionManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAEV,UAAU,EAEV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAIlB,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,6BAA6B,GACxC,6BAA6B,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,EAC5D,OAAO,UAAU,CAAC,OAAO,mBAAmB,CAAC,EAC7C,YAAY,UAAU,CAAC,OAAO,oBAAoB,CAAC,EACnD,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,WAAW,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC;WAgKvD,CAAC,SAAS,SAAS,wBACrB,mBAAmB,CAAC,CAAC,CAAC,8BAE/B,gBAAgB,CAAC,CAAC,CAAC;cAsDL,CAAC,SAAS,SAAS,cAAc,IAAI,SAAS,OAAO,iBAC7D,OAAO,CAAC,CAAC,CAAC,YACP,oBAAoB,CAAC,CAAC,EAAE,IAAI,CAAC,8BAEtC,iBAAiB,CAAC,CAAC,EAAE,IAAI,CAAC;;CAuC9B,CAAC"}
|