supastash 0.2.10 → 0.2.12
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/desktop/hooks/syncEngine.d.ts.map +1 -1
- package/dist/desktop/hooks/syncEngine.js +7 -2
- package/dist/desktop/index.d.ts +4 -2
- package/dist/desktop/index.d.ts.map +1 -1
- package/dist/desktop/index.js +1 -0
- package/dist/desktop/utils/sync/pullFromRemote/index.d.ts +2 -1
- package/dist/desktop/utils/sync/pullFromRemote/index.d.ts.map +1 -1
- package/dist/desktop/utils/sync/pullFromRemote/index.js +3 -2
- package/dist/desktop/utils/sync/pullFromRemote/pullFromRemoteBatch.d.ts +9 -0
- package/dist/desktop/utils/sync/pullFromRemote/pullFromRemoteBatch.d.ts.map +1 -0
- package/dist/desktop/utils/sync/pullFromRemote/pullFromRemoteBatch.js +202 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/native/hooks/syncEngine.d.ts.map +1 -1
- package/dist/native/hooks/syncEngine.js +7 -2
- package/dist/native/index.d.ts +2 -0
- package/dist/native/index.d.ts.map +1 -1
- package/dist/native/index.js +1 -0
- package/dist/native/utils/sync/pullFromRemote/index.d.ts +2 -1
- package/dist/native/utils/sync/pullFromRemote/index.d.ts.map +1 -1
- package/dist/native/utils/sync/pullFromRemote/index.js +7 -1
- package/dist/native/utils/sync/pullFromRemote/pullFromRemoteBatch.d.ts +9 -0
- package/dist/native/utils/sync/pullFromRemote/pullFromRemoteBatch.d.ts.map +1 -0
- package/dist/native/utils/sync/pullFromRemote/pullFromRemoteBatch.js +183 -0
- package/dist/shared/core/config/index.d.ts.map +1 -1
- package/dist/shared/core/config/index.js +2 -0
- package/dist/shared/hooks/supastashFilters/index.d.ts +9 -4
- package/dist/shared/hooks/supastashFilters/index.d.ts.map +1 -1
- package/dist/shared/hooks/supastashFilters/index.js +13 -5
- package/dist/shared/store/rpcTableFilters.d.ts +7 -0
- package/dist/shared/store/rpcTableFilters.d.ts.map +1 -0
- package/dist/shared/store/rpcTableFilters.js +5 -0
- package/dist/shared/types/rpcFilter.types.d.ts +23 -0
- package/dist/shared/types/supastashConfig.types.d.ts +38 -10
- package/dist/shared/utils/schema/createSyncStatus.d.ts.map +1 -1
- package/dist/shared/utils/schema/createSyncStatus.js +13 -6
- package/dist/shared/utils/sync/pullFromRemote/postgrestToRpc.d.ts +9 -0
- package/dist/shared/utils/sync/pullFromRemote/postgrestToRpc.d.ts.map +1 -0
- package/dist/shared/utils/sync/pullFromRemote/postgrestToRpc.js +50 -0
- package/dist/shared/utils/sync/pullFromRemote/updateFilter.d.ts +8 -5
- package/dist/shared/utils/sync/pullFromRemote/updateFilter.d.ts.map +1 -1
- package/dist/shared/utils/sync/pullFromRemote/updateFilter.js +11 -5
- package/dist/shared/utils/sync/pullFromRemote/updateRpcFilters.d.ts +12 -0
- package/dist/shared/utils/sync/pullFromRemote/updateRpcFilters.d.ts.map +1 -0
- package/dist/shared/utils/sync/pullFromRemote/updateRpcFilters.js +36 -0
- package/dist/shared/utils/sync/status/remoteSchema.d.ts +12 -0
- package/dist/shared/utils/sync/status/remoteSchema.d.ts.map +1 -1
- package/dist/shared/utils/sync/status/remoteSchema.js +46 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncEngine.d.ts","sourceRoot":"","sources":["../../../src/desktop/hooks/syncEngine.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCnE;
|
|
1
|
+
{"version":3,"file":"syncEngine.d.ts","sourceRoot":"","sources":["../../../src/desktop/hooks/syncEngine.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCnE;AA2DD;;;;;GAKG;AACH,wBAAgB,aAAa;;;EA2D5B;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD"}
|
|
@@ -7,8 +7,8 @@ import { isOnline } from "../../shared/utils/connection";
|
|
|
7
7
|
import log from "../../shared/utils/logs";
|
|
8
8
|
import { subscribeToAppVisibility } from "../adapters/appstate";
|
|
9
9
|
import { pullFromRemote as doPullFromRemote } from "../utils/sync/pullFromRemote";
|
|
10
|
+
import { pullFromRemoteBatch } from "../utils/sync/pullFromRemote/pullFromRemoteBatch";
|
|
10
11
|
import { updateLocalDb } from "../utils/sync/pullFromRemote/updateLocalDb";
|
|
11
|
-
import { pushLocalData as doPushLocalData } from "../utils/sync/pushLocal";
|
|
12
12
|
import { pushLocalDataToRemote } from "../utils/sync/pushLocal/sendUnsyncedToSupabase";
|
|
13
13
|
// -----------------------------
|
|
14
14
|
// Module-scoped state & tunables
|
|
@@ -85,7 +85,12 @@ async function pushLocalDataSafe() {
|
|
|
85
85
|
return;
|
|
86
86
|
isPushing = true;
|
|
87
87
|
try {
|
|
88
|
-
|
|
88
|
+
if (cfg.useBatchPullSync) {
|
|
89
|
+
await pullFromRemoteBatch();
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await doPullFromRemote();
|
|
93
|
+
}
|
|
89
94
|
lastPushAt = Date.now();
|
|
90
95
|
}
|
|
91
96
|
catch (e) {
|
package/dist/desktop/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { refreshScreen } from "../shared/utils/refreshScreenCalls";
|
|
|
9
9
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "../shared/utils/supastashMode";
|
|
10
10
|
export { getAllTables } from "../shared/utils/sync/getAllTables";
|
|
11
11
|
export { updateFilters } from "../shared/utils/sync/pullFromRemote/updateFilter";
|
|
12
|
+
export { updateRpcFilters } from "../shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
12
13
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "../shared/utils/sync/refreshTables";
|
|
13
14
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "../shared/utils/sync/registration/syncCalls";
|
|
14
15
|
export { defineLocalSchema } from "./core/schemaManager";
|
|
@@ -21,8 +22,9 @@ export { updateLocalDb, upsertChunkData, upsertData, } from "./utils/sync/pullFr
|
|
|
21
22
|
export { clearAllLocalDeleteLog, clearAllLocalSyncLog, clearLocalDeleteLog, clearLocalSyncLog, clearSyncLog, getLocalDeleteLog, getSyncLog, resetSyncLog, setLocalDeleteLog, setLocalSyncLog, setSyncLog, } from "./utils/sync/status/syncStatus";
|
|
22
23
|
export type { CrudMethods } from "../shared/types/query.types";
|
|
23
24
|
export type { RealtimeOptions, SupastashDataResult, SupastashFilter, } from "../shared/types/realtimeData.types";
|
|
24
|
-
export type { ExpoSQLiteClient, RNSqliteNitroClient, RNStorageSQLiteClient, SupastashConfig, SupastashHookReturn, SupastashSQLiteClientTypes, SupastashSQLiteDatabase, SupastashSQLiteExecutor, TauriSQLiteClient, } from "../shared/types/supastashConfig.types";
|
|
25
25
|
export type { LocalSchemaDefinition } from "../shared/types/schemaManager.types";
|
|
26
|
-
export type {
|
|
26
|
+
export type { ExpoSQLiteClient, RNSqliteNitroClient, RNStorageSQLiteClient, SupastashConfig, SupastashHookReturn, SupastashSQLiteClientTypes, SupastashSQLiteDatabase, SupastashSQLiteExecutor, TauriSQLiteClient, } from "../shared/types/supastashConfig.types";
|
|
27
27
|
export type { SupastashClient, SupastashTransactionClient, } from "../shared/utils/query/builder";
|
|
28
|
+
export type { SyncInfo } from "../shared/types/syncEngine.types";
|
|
29
|
+
export type { SyncCountResult } from "../shared/types/rpcFilter.types";
|
|
28
30
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/desktop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,GACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/desktop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sDAAsD,CAAC;AACxF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,GACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist/desktop/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { refreshScreen } from "../shared/utils/refreshScreenCalls";
|
|
|
9
9
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "../shared/utils/supastashMode";
|
|
10
10
|
export { getAllTables } from "../shared/utils/sync/getAllTables";
|
|
11
11
|
export { updateFilters } from "../shared/utils/sync/pullFromRemote/updateFilter";
|
|
12
|
+
export { updateRpcFilters } from "../shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
12
13
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "../shared/utils/sync/refreshTables";
|
|
13
14
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "../shared/utils/sync/registration/syncCalls";
|
|
14
15
|
export { defineLocalSchema } from "./core/schemaManager";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pulls the data from the remote database to the local database
|
|
2
|
+
* Pulls the data from the remote database to the local database (per-table path).
|
|
3
|
+
* For the batch RPC path, see pullFromRemoteBatch — routed via syncEngine.
|
|
3
4
|
*/
|
|
4
5
|
export declare function pullFromRemote(): Promise<void>;
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pullFromRemote/index.ts"],"names":[],"mappings":"AASA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pullFromRemote/index.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAsB,cAAc,kBAqEnC"}
|
|
@@ -5,9 +5,10 @@ import log from "../../../../shared/utils/logs";
|
|
|
5
5
|
import { getAllTables } from "../../../../shared/utils/sync/getAllTables";
|
|
6
6
|
import { runLimitedConcurrency } from "../../../../shared/utils/sync/pullFromRemote/runLimitedConcurrency";
|
|
7
7
|
import { SyncInfoUpdater } from "../../../../shared/utils/sync/queryStatus";
|
|
8
|
-
import { updateLocalDb } from "
|
|
8
|
+
import { updateLocalDb } from "./updateLocalDb";
|
|
9
9
|
/**
|
|
10
|
-
* Pulls the data from the remote database to the local database
|
|
10
|
+
* Pulls the data from the remote database to the local database (per-table path).
|
|
11
|
+
* For the batch RPC path, see pullFromRemoteBatch — routed via syncEngine.
|
|
11
12
|
*/
|
|
12
13
|
export async function pullFromRemote() {
|
|
13
14
|
let numberOfTables = 0;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch pull: fetches all tables in a single RPC call per round,
|
|
3
|
+
* looping until `remaining_tables` is empty.
|
|
4
|
+
*
|
|
5
|
+
* Requires `useBatchPullSync: true` in config and the
|
|
6
|
+
* `supastash_pull_sync` Postgres function to be deployed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pullFromRemoteBatch(): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=pullFromRemoteBatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pullFromRemoteBatch.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pullFromRemote/pullFromRemoteBatch.ts"],"names":[],"mappings":"AA+CA;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4MzD"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../../shared/core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../../shared/db/dbInitializer";
|
|
3
|
+
import { rpcTableFilters } from "../../../../shared/store/rpcTableFilters";
|
|
4
|
+
import { tableFilters } from "../../../../shared/store/tableFilters";
|
|
5
|
+
import log, { logError, logWarn } from "../../../../shared/utils/logs";
|
|
6
|
+
import { refreshScreen } from "../../../../shared/utils/refreshScreenCalls";
|
|
7
|
+
import { supabaseClientErr } from "../../../../shared/utils/supabaseClientErr";
|
|
8
|
+
import { getAllTables } from "../../../../shared/utils/sync/getAllTables";
|
|
9
|
+
import { getMaxSyncLookBack, logNoUpdates, returnMaxDate, } from "../../../../shared/utils/sync/pullFromRemote/helpers";
|
|
10
|
+
import { postgrestFiltersToRpc } from "../../../../shared/utils/sync/pullFromRemote/postgrestToRpc";
|
|
11
|
+
import { SyncInfoUpdater } from "../../../../shared/utils/sync/queryStatus";
|
|
12
|
+
import { prefetchRemoteTableSchemas } from "../../../../shared/utils/sync/status/remoteSchema";
|
|
13
|
+
import { selectSyncStatus } from "../status/repo";
|
|
14
|
+
import { setSupastashSyncStatus } from "../status/services";
|
|
15
|
+
import { upsertChunkData } from "./updateLocalDb";
|
|
16
|
+
const CHUNK_SIZE = 999;
|
|
17
|
+
function buildCursorFilter(tsCol, lastSyncedAt, lastPk) {
|
|
18
|
+
if (lastPk) {
|
|
19
|
+
return {
|
|
20
|
+
or: [
|
|
21
|
+
{ col: tsCol, op: "gt", val: lastSyncedAt },
|
|
22
|
+
{
|
|
23
|
+
and: [
|
|
24
|
+
{ col: tsCol, op: "eq", val: lastSyncedAt },
|
|
25
|
+
{ col: "id", op: "gt", val: lastPk },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { col: tsCol, op: "gte", val: lastSyncedAt };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Batch pull: fetches all tables in a single RPC call per round,
|
|
35
|
+
* looping until `remaining_tables` is empty.
|
|
36
|
+
*
|
|
37
|
+
* Requires `useBatchPullSync: true` in config and the
|
|
38
|
+
* `supastash_pull_sync` Postgres function to be deployed.
|
|
39
|
+
*/
|
|
40
|
+
export async function pullFromRemoteBatch() {
|
|
41
|
+
const cfg = getSupastashConfig();
|
|
42
|
+
const supabase = cfg.supabaseClient;
|
|
43
|
+
if (!supabase)
|
|
44
|
+
throw new Error(`No supabase client found: ${supabaseClientErr}`);
|
|
45
|
+
if (cfg.supastashMode === "ghost")
|
|
46
|
+
return;
|
|
47
|
+
const tables = await getAllTables();
|
|
48
|
+
if (!tables) {
|
|
49
|
+
log("[Supastash] Batch pull: no tables found");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const excludeTables = cfg.excludeTables?.pull ?? [];
|
|
53
|
+
const tablesToPull = tables.filter((t) => !excludeTables.includes(t));
|
|
54
|
+
if (!tablesToPull.length)
|
|
55
|
+
return;
|
|
56
|
+
const tsCol = cfg.replicationMode === "server-side" ? "arrived_at" : "updated_at";
|
|
57
|
+
const db = await getSupastashDb();
|
|
58
|
+
const completedTables = new Set();
|
|
59
|
+
SyncInfoUpdater.setInProgress({ action: "start", type: "pull" });
|
|
60
|
+
SyncInfoUpdater.setNumberOfTables({
|
|
61
|
+
amount: tablesToPull.length,
|
|
62
|
+
type: "pull",
|
|
63
|
+
});
|
|
64
|
+
// Warm schema cache for all tables in one call if enabled
|
|
65
|
+
if (cfg.useBatchSchemaFetch) {
|
|
66
|
+
await prefetchRemoteTableSchemas(tablesToPull);
|
|
67
|
+
}
|
|
68
|
+
let remainingTables = tablesToPull;
|
|
69
|
+
try {
|
|
70
|
+
while (remainingTables.length > 0) {
|
|
71
|
+
// ── Build per-table filters: base filters + cursor ──────────────────
|
|
72
|
+
const p_filters = {};
|
|
73
|
+
for (const table of remainingTables) {
|
|
74
|
+
const syncStatus = await selectSyncStatus(db, table, tableFilters.get(table) ?? []);
|
|
75
|
+
// Mirror pageThrough: cap the cursor to maxSyncLookbackDays so a
|
|
76
|
+
// first-time sync doesn't try to pull decades of data.
|
|
77
|
+
// fullSyncTables bypass the cap (getMaxSyncLookBack returns undefined).
|
|
78
|
+
const maxLookBack = getMaxSyncLookBack({ table });
|
|
79
|
+
const effectiveSince = maxLookBack &&
|
|
80
|
+
Date.parse(syncStatus.last_synced_at) < Date.parse(maxLookBack)
|
|
81
|
+
? maxLookBack
|
|
82
|
+
: syncStatus.last_synced_at;
|
|
83
|
+
const cursorFilter = buildCursorFilter(tsCol, effectiveSince, syncStatus.last_synced_at_pk);
|
|
84
|
+
// Merge explicit RPC filters + PostgREST filters auto-converted at query time
|
|
85
|
+
const rpcBase = rpcTableFilters.get(table) ?? [];
|
|
86
|
+
const converted = postgrestFiltersToRpc(tableFilters.get(table));
|
|
87
|
+
const baseFilters = [...rpcBase, ...converted];
|
|
88
|
+
p_filters[table] = [...baseFilters, cursorFilter];
|
|
89
|
+
}
|
|
90
|
+
// ── Single RPC call ─────────────────────────────────────────────────
|
|
91
|
+
const { data, error } = await supabase.rpc("supastash_pull_sync", {
|
|
92
|
+
p_tables: remainingTables,
|
|
93
|
+
p_filters,
|
|
94
|
+
p_ts_col: tsCol,
|
|
95
|
+
});
|
|
96
|
+
if (error)
|
|
97
|
+
throw error;
|
|
98
|
+
const result = data;
|
|
99
|
+
const nextRemaining = result.remaining_tables ?? [];
|
|
100
|
+
// ── Process each table ──────────────────────────────────────────────
|
|
101
|
+
for (const [table, rows] of Object.entries(result.tables ?? {})) {
|
|
102
|
+
SyncInfoUpdater.markLogStart({ type: "pull", table });
|
|
103
|
+
try {
|
|
104
|
+
if (!rows?.length) {
|
|
105
|
+
logNoUpdates(table);
|
|
106
|
+
SyncInfoUpdater.markLogSuccess({ type: "pull", table });
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const toDelete = [];
|
|
110
|
+
const toUpsert = [];
|
|
111
|
+
let prevMaxSyncedAt = null;
|
|
112
|
+
let prevMaxDeletedAt = null;
|
|
113
|
+
for (const row of rows) {
|
|
114
|
+
if (!row?.id) {
|
|
115
|
+
logWarn(`[Supastash] Batch: skipped row without id from "${table}"`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
prevMaxSyncedAt = returnMaxDate({
|
|
119
|
+
row,
|
|
120
|
+
prevMax: prevMaxSyncedAt,
|
|
121
|
+
col: tsCol,
|
|
122
|
+
});
|
|
123
|
+
prevMaxDeletedAt = returnMaxDate({
|
|
124
|
+
row,
|
|
125
|
+
prevMax: prevMaxDeletedAt,
|
|
126
|
+
col: "deleted_at",
|
|
127
|
+
});
|
|
128
|
+
if (row.deleted_at) {
|
|
129
|
+
toDelete.push(row.id);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
toUpsert.push(row);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
SyncInfoUpdater.setUnsyncedDataCount({
|
|
136
|
+
amount: toUpsert.length,
|
|
137
|
+
type: "pull",
|
|
138
|
+
table,
|
|
139
|
+
});
|
|
140
|
+
SyncInfoUpdater.setUnsyncedDeletedCount({
|
|
141
|
+
amount: toDelete.length,
|
|
142
|
+
type: "pull",
|
|
143
|
+
table,
|
|
144
|
+
});
|
|
145
|
+
// Delete soft-deleted rows
|
|
146
|
+
if (toDelete.length > 0) {
|
|
147
|
+
for (let i = 0; i < toDelete.length; i += CHUNK_SIZE) {
|
|
148
|
+
const slice = toDelete.slice(i, i + CHUNK_SIZE);
|
|
149
|
+
const placeholders = slice.map(() => "?").join(", ");
|
|
150
|
+
await db.runAsync(`DELETE FROM ${table} WHERE id IN (${placeholders})`, slice);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Upsert live rows
|
|
154
|
+
if (toUpsert.length > 0) {
|
|
155
|
+
await upsertChunkData({ table, records: toUpsert });
|
|
156
|
+
}
|
|
157
|
+
// Update sync cursor so the next round starts from the right place
|
|
158
|
+
if (prevMaxSyncedAt || prevMaxDeletedAt) {
|
|
159
|
+
await setSupastashSyncStatus(table, tableFilters.get(table) ?? [], {
|
|
160
|
+
lastSyncedAt: prevMaxSyncedAt?.value ?? undefined,
|
|
161
|
+
lastDeletedAt: prevMaxDeletedAt?.value ?? undefined,
|
|
162
|
+
lastSyncedAtPk: prevMaxSyncedAt?.pk ?? null,
|
|
163
|
+
filterNamespace: "global",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (toUpsert.length > 0 || toDelete.length > 0) {
|
|
167
|
+
refreshScreen(table);
|
|
168
|
+
}
|
|
169
|
+
log(`[Supastash] Batch received ${rows.length} rows for "${table}" ` +
|
|
170
|
+
`(u${toUpsert.length}/d${toDelete.length})`);
|
|
171
|
+
SyncInfoUpdater.markLogSuccess({ type: "pull", table });
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
SyncInfoUpdater.markLogError({
|
|
175
|
+
type: "pull",
|
|
176
|
+
table,
|
|
177
|
+
lastError: e,
|
|
178
|
+
errorCount: 1,
|
|
179
|
+
});
|
|
180
|
+
logError(`[Supastash] Batch pull failed for "${table}"`, e);
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
// Mark table as fully completed only once it leaves remaining_tables
|
|
184
|
+
if (!nextRemaining.includes(table)) {
|
|
185
|
+
completedTables.add(table);
|
|
186
|
+
SyncInfoUpdater.setTablesCompleted({
|
|
187
|
+
amount: completedTables.size,
|
|
188
|
+
type: "pull",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
remainingTables = nextRemaining;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
logError("[Supastash] Error in batch pull from remote", error);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
SyncInfoUpdater.reset({ type: "pull" });
|
|
201
|
+
}
|
|
202
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { refreshScreen } from "./shared/utils/refreshScreenCalls";
|
|
|
7
7
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "./shared/utils/supastashMode";
|
|
8
8
|
export { getAllTables } from "./shared/utils/sync/getAllTables";
|
|
9
9
|
export { updateFilters } from "./shared/utils/sync/pullFromRemote/updateFilter";
|
|
10
|
+
export { updateRpcFilters } from "./shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
10
11
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "./shared/utils/sync/refreshTables";
|
|
11
12
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "./shared/utils/sync/registration/syncCalls";
|
|
12
13
|
export { supastash } from "./shared/utils/query/builder";
|
|
@@ -15,5 +16,6 @@ export type { RealtimeOptions, SupastashDataResult, SupastashFilter, } from "./s
|
|
|
15
16
|
export type { LocalSchemaDefinition } from "./shared/types/schemaManager.types";
|
|
16
17
|
export type { ExpoSQLiteClient, RNSqliteNitroClient, RNStorageSQLiteClient, SupastashConfig, SupastashHookReturn, SupastashSQLiteClientTypes, SupastashSQLiteDatabase, SupastashSQLiteExecutor, TauriSQLiteClient, } from "./shared/types/supastashConfig.types";
|
|
17
18
|
export type { SyncInfo } from "./shared/types/syncEngine.types";
|
|
19
|
+
export type { SyncCountResult } from "./shared/types/rpcFilter.types";
|
|
18
20
|
export type { SupastashClient, SupastashTransactionClient, } from "./shared/utils/query/builder";
|
|
19
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAChF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,YAAY,EACV,eAAe,EACf,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qDAAqD,CAAC;AACvF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,YAAY,EACV,eAAe,EACf,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { refreshScreen } from "./shared/utils/refreshScreenCalls";
|
|
|
7
7
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "./shared/utils/supastashMode";
|
|
8
8
|
export { getAllTables } from "./shared/utils/sync/getAllTables";
|
|
9
9
|
export { updateFilters } from "./shared/utils/sync/pullFromRemote/updateFilter";
|
|
10
|
+
export { updateRpcFilters } from "./shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
10
11
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "./shared/utils/sync/refreshTables";
|
|
11
12
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "./shared/utils/sync/registration/syncCalls";
|
|
12
13
|
export { supastash } from "./shared/utils/query/builder";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncEngine.d.ts","sourceRoot":"","sources":["../../../src/native/hooks/syncEngine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"syncEngine.d.ts","sourceRoot":"","sources":["../../../src/native/hooks/syncEngine.ts"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCnE;AAyDD;;;;;GAKG;AACH,wBAAgB,aAAa;;;EA+D5B;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD"}
|
|
@@ -7,6 +7,7 @@ import { tableFilters } from "../../shared/store/tableFilters";
|
|
|
7
7
|
import { isOnline } from "../../shared/utils/connection";
|
|
8
8
|
import log from "../../shared/utils/logs";
|
|
9
9
|
import { pullFromRemote as doPullFromRemote } from "../utils/sync/pullFromRemote";
|
|
10
|
+
import { pullFromRemoteBatch } from "../utils/sync/pullFromRemote/pullFromRemoteBatch";
|
|
10
11
|
import { updateLocalDb } from "../utils/sync/pullFromRemote/updateLocalDb";
|
|
11
12
|
import { pushLocalData as doPushLocalData } from "../utils/sync/pushLocal";
|
|
12
13
|
import { pushLocalDataToRemote } from "../utils/sync/pushLocal/sendUnsyncedToSupabase";
|
|
@@ -103,7 +104,6 @@ async function pullFromRemoteSafe() {
|
|
|
103
104
|
return;
|
|
104
105
|
if (!(await isOnline()))
|
|
105
106
|
return;
|
|
106
|
-
// If in ghost mode, don't pull
|
|
107
107
|
const cfg = getSupastashConfig();
|
|
108
108
|
if (cfg.supastashMode === "ghost")
|
|
109
109
|
return;
|
|
@@ -111,7 +111,12 @@ async function pullFromRemoteSafe() {
|
|
|
111
111
|
return;
|
|
112
112
|
isPulling = true;
|
|
113
113
|
try {
|
|
114
|
-
|
|
114
|
+
if (cfg.useBatchPullSync) {
|
|
115
|
+
await pullFromRemoteBatch();
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
await doPullFromRemote();
|
|
119
|
+
}
|
|
115
120
|
lastPullAt = Date.now();
|
|
116
121
|
}
|
|
117
122
|
catch (e) {
|
package/dist/native/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { refreshScreen } from "../shared/utils/refreshScreenCalls";
|
|
|
9
9
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "../shared/utils/supastashMode";
|
|
10
10
|
export { getAllTables } from "../shared/utils/sync/getAllTables";
|
|
11
11
|
export { updateFilters } from "../shared/utils/sync/pullFromRemote/updateFilter";
|
|
12
|
+
export { updateRpcFilters } from "../shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
12
13
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "../shared/utils/sync/refreshTables";
|
|
13
14
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "../shared/utils/sync/registration/syncCalls";
|
|
14
15
|
export { defineLocalSchema } from "./core/schemaManager";
|
|
@@ -25,4 +26,5 @@ export type { LocalSchemaDefinition } from "../shared/types/schemaManager.types"
|
|
|
25
26
|
export type { ExpoSQLiteClient, RNSqliteNitroClient, RNStorageSQLiteClient, SupastashConfig, SupastashHookReturn, SupastashSQLiteClientTypes, SupastashSQLiteDatabase, SupastashSQLiteExecutor, TauriSQLiteClient, } from "../shared/types/supastashConfig.types";
|
|
26
27
|
export type { SupastashClient, SupastashTransactionClient, } from "../shared/utils/query/builder";
|
|
27
28
|
export type { SyncInfo } from "../shared/types/syncEngine.types";
|
|
29
|
+
export type { SyncCountResult } from "../shared/types/rpcFilter.types";
|
|
28
30
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,GACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sDAAsD,CAAC;AACxF,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,GACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist/native/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { refreshScreen } from "../shared/utils/refreshScreenCalls";
|
|
|
9
9
|
export { getSupastashRuntimeMode, reinitializeSupastash, } from "../shared/utils/supastashMode";
|
|
10
10
|
export { getAllTables } from "../shared/utils/sync/getAllTables";
|
|
11
11
|
export { updateFilters } from "../shared/utils/sync/pullFromRemote/updateFilter";
|
|
12
|
+
export { updateRpcFilters } from "../shared/utils/sync/pullFromRemote/updateRpcFilters";
|
|
12
13
|
export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "../shared/utils/sync/refreshTables";
|
|
13
14
|
export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "../shared/utils/sync/registration/syncCalls";
|
|
14
15
|
export { defineLocalSchema } from "./core/schemaManager";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pulls the data from the remote database to the local database
|
|
2
|
+
* Pulls the data from the remote database to the local database (per-table path).
|
|
3
|
+
* For the batch RPC path, see pullFromRemoteBatch — routed via syncEngine.
|
|
3
4
|
*/
|
|
4
5
|
export declare function pullFromRemote(): Promise<void>;
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pullFromRemote/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pullFromRemote/index.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAsB,cAAc,kBA0EnC"}
|
|
@@ -5,9 +5,11 @@ import log from "../../../../shared/utils/logs";
|
|
|
5
5
|
import { getAllTables } from "../../../../shared/utils/sync/getAllTables";
|
|
6
6
|
import { runLimitedConcurrency } from "../../../../shared/utils/sync/pullFromRemote/runLimitedConcurrency";
|
|
7
7
|
import { SyncInfoUpdater } from "../../../../shared/utils/sync/queryStatus";
|
|
8
|
+
import { prefetchRemoteTableSchemas } from "../../../../shared/utils/sync/status/remoteSchema";
|
|
8
9
|
import { updateLocalDb } from "./updateLocalDb";
|
|
9
10
|
/**
|
|
10
|
-
* Pulls the data from the remote database to the local database
|
|
11
|
+
* Pulls the data from the remote database to the local database (per-table path).
|
|
12
|
+
* For the batch RPC path, see pullFromRemoteBatch — routed via syncEngine.
|
|
11
13
|
*/
|
|
12
14
|
export async function pullFromRemote() {
|
|
13
15
|
let numberOfTables = 0;
|
|
@@ -21,6 +23,10 @@ export async function pullFromRemote() {
|
|
|
21
23
|
const excludeTables = getSupastashConfig()?.excludeTables?.pull || [];
|
|
22
24
|
const tablesToPull = tables.filter((table) => !excludeTables?.includes(table));
|
|
23
25
|
numberOfTables = tablesToPull.length;
|
|
26
|
+
// Warm schema cache for all tables in one call if enabled
|
|
27
|
+
if (getSupastashConfig().useBatchSchemaFetch) {
|
|
28
|
+
await prefetchRemoteTableSchemas(tablesToPull);
|
|
29
|
+
}
|
|
24
30
|
SyncInfoUpdater.setInProgress({
|
|
25
31
|
action: "start",
|
|
26
32
|
type: "pull",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch pull: fetches all tables in a single RPC call per round,
|
|
3
|
+
* looping until `remaining_tables` is empty.
|
|
4
|
+
*
|
|
5
|
+
* Requires `useBatchPullSync: true` in config and the
|
|
6
|
+
* `supastash_pull_sync` Postgres function to be deployed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pullFromRemoteBatch(): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=pullFromRemoteBatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pullFromRemoteBatch.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pullFromRemote/pullFromRemoteBatch.ts"],"names":[],"mappings":"AA4CA;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CA+KzD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../../shared/core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../../shared/db/dbInitializer";
|
|
3
|
+
import { rpcTableFilters } from "../../../../shared/store/rpcTableFilters";
|
|
4
|
+
import { tableFilters } from "../../../../shared/store/tableFilters";
|
|
5
|
+
import { postgrestFiltersToRpc } from "../../../../shared/utils/sync/pullFromRemote/postgrestToRpc";
|
|
6
|
+
import { getAllTables } from "../../../../shared/utils/sync/getAllTables";
|
|
7
|
+
import { getMaxSyncLookBack, logNoUpdates, returnMaxDate, } from "../../../../shared/utils/sync/pullFromRemote/helpers";
|
|
8
|
+
import { SyncInfoUpdater } from "../../../../shared/utils/sync/queryStatus";
|
|
9
|
+
import { refreshScreen } from "../../../../shared/utils/refreshScreenCalls";
|
|
10
|
+
import log, { logError, logWarn } from "../../../../shared/utils/logs";
|
|
11
|
+
import { supabaseClientErr } from "../../../../shared/utils/supabaseClientErr";
|
|
12
|
+
import { prefetchRemoteTableSchemas } from "../../../../shared/utils/sync/status/remoteSchema";
|
|
13
|
+
import { setSupastashSyncStatus } from "../status/services";
|
|
14
|
+
import { selectSyncStatus } from "../status/repo";
|
|
15
|
+
import { upsertChunkData } from "./updateLocalDb";
|
|
16
|
+
const CHUNK_SIZE = 999;
|
|
17
|
+
function buildCursorFilter(tsCol, lastSyncedAt, lastPk) {
|
|
18
|
+
if (lastPk) {
|
|
19
|
+
return {
|
|
20
|
+
or: [
|
|
21
|
+
{ col: tsCol, op: "gt", val: lastSyncedAt },
|
|
22
|
+
{
|
|
23
|
+
and: [
|
|
24
|
+
{ col: tsCol, op: "eq", val: lastSyncedAt },
|
|
25
|
+
{ col: "id", op: "gt", val: lastPk },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { col: tsCol, op: "gte", val: lastSyncedAt };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Batch pull: fetches all tables in a single RPC call per round,
|
|
35
|
+
* looping until `remaining_tables` is empty.
|
|
36
|
+
*
|
|
37
|
+
* Requires `useBatchPullSync: true` in config and the
|
|
38
|
+
* `supastash_pull_sync` Postgres function to be deployed.
|
|
39
|
+
*/
|
|
40
|
+
export async function pullFromRemoteBatch() {
|
|
41
|
+
const cfg = getSupastashConfig();
|
|
42
|
+
const supabase = cfg.supabaseClient;
|
|
43
|
+
if (!supabase)
|
|
44
|
+
throw new Error(`No supabase client found: ${supabaseClientErr}`);
|
|
45
|
+
if (cfg.supastashMode === "ghost")
|
|
46
|
+
return;
|
|
47
|
+
const tables = await getAllTables();
|
|
48
|
+
if (!tables) {
|
|
49
|
+
log("[Supastash] Batch pull: no tables found");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const excludeTables = cfg.excludeTables?.pull ?? [];
|
|
53
|
+
const tablesToPull = tables.filter((t) => !excludeTables.includes(t));
|
|
54
|
+
if (!tablesToPull.length)
|
|
55
|
+
return;
|
|
56
|
+
const tsCol = cfg.replicationMode === "server-side" ? "arrived_at" : "updated_at";
|
|
57
|
+
const db = await getSupastashDb();
|
|
58
|
+
const completedTables = new Set();
|
|
59
|
+
SyncInfoUpdater.setInProgress({ action: "start", type: "pull" });
|
|
60
|
+
SyncInfoUpdater.setNumberOfTables({ amount: tablesToPull.length, type: "pull" });
|
|
61
|
+
// Warm schema cache for all tables in one call if enabled
|
|
62
|
+
if (cfg.useBatchSchemaFetch) {
|
|
63
|
+
await prefetchRemoteTableSchemas(tablesToPull);
|
|
64
|
+
}
|
|
65
|
+
let remainingTables = tablesToPull;
|
|
66
|
+
try {
|
|
67
|
+
while (remainingTables.length > 0) {
|
|
68
|
+
// ── Build per-table filters: base filters + cursor ──────────────────
|
|
69
|
+
const p_filters = {};
|
|
70
|
+
for (const table of remainingTables) {
|
|
71
|
+
const syncStatus = await selectSyncStatus(db, table, tableFilters.get(table) ?? []);
|
|
72
|
+
// Mirror pageThrough: cap the cursor to maxSyncLookbackDays so a
|
|
73
|
+
// first-time sync doesn't try to pull decades of data.
|
|
74
|
+
// fullSyncTables bypass the cap (getMaxSyncLookBack returns undefined).
|
|
75
|
+
const maxLookBack = getMaxSyncLookBack({ table });
|
|
76
|
+
const effectiveSince = maxLookBack &&
|
|
77
|
+
Date.parse(syncStatus.last_synced_at) < Date.parse(maxLookBack)
|
|
78
|
+
? maxLookBack
|
|
79
|
+
: syncStatus.last_synced_at;
|
|
80
|
+
const cursorFilter = buildCursorFilter(tsCol, effectiveSince, syncStatus.last_synced_at_pk);
|
|
81
|
+
// Merge explicit RPC filters + PostgREST filters auto-converted at query time
|
|
82
|
+
const rpcBase = rpcTableFilters.get(table) ?? [];
|
|
83
|
+
const converted = postgrestFiltersToRpc(tableFilters.get(table));
|
|
84
|
+
const baseFilters = [...rpcBase, ...converted];
|
|
85
|
+
p_filters[table] = [...baseFilters, cursorFilter];
|
|
86
|
+
}
|
|
87
|
+
// ── Single RPC call ─────────────────────────────────────────────────
|
|
88
|
+
const { data, error } = await supabase.rpc("supastash_pull_sync", {
|
|
89
|
+
p_tables: remainingTables,
|
|
90
|
+
p_filters,
|
|
91
|
+
p_ts_col: tsCol,
|
|
92
|
+
});
|
|
93
|
+
if (error)
|
|
94
|
+
throw error;
|
|
95
|
+
const result = data;
|
|
96
|
+
const nextRemaining = result.remaining_tables ?? [];
|
|
97
|
+
// ── Process each table ──────────────────────────────────────────────
|
|
98
|
+
for (const [table, rows] of Object.entries(result.tables ?? {})) {
|
|
99
|
+
SyncInfoUpdater.markLogStart({ type: "pull", table });
|
|
100
|
+
try {
|
|
101
|
+
if (!rows?.length) {
|
|
102
|
+
logNoUpdates(table);
|
|
103
|
+
SyncInfoUpdater.markLogSuccess({ type: "pull", table });
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const toDelete = [];
|
|
107
|
+
const toUpsert = [];
|
|
108
|
+
let prevMaxSyncedAt = null;
|
|
109
|
+
let prevMaxDeletedAt = null;
|
|
110
|
+
for (const row of rows) {
|
|
111
|
+
if (!row?.id) {
|
|
112
|
+
logWarn(`[Supastash] Batch: skipped row without id from "${table}"`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
prevMaxSyncedAt = returnMaxDate({ row, prevMax: prevMaxSyncedAt, col: tsCol });
|
|
116
|
+
prevMaxDeletedAt = returnMaxDate({ row, prevMax: prevMaxDeletedAt, col: "deleted_at" });
|
|
117
|
+
if (row.deleted_at) {
|
|
118
|
+
toDelete.push(row.id);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
toUpsert.push(row);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
SyncInfoUpdater.setUnsyncedDataCount({ amount: toUpsert.length, type: "pull", table });
|
|
125
|
+
SyncInfoUpdater.setUnsyncedDeletedCount({ amount: toDelete.length, type: "pull", table });
|
|
126
|
+
// Delete soft-deleted rows
|
|
127
|
+
if (toDelete.length > 0) {
|
|
128
|
+
for (let i = 0; i < toDelete.length; i += CHUNK_SIZE) {
|
|
129
|
+
const slice = toDelete.slice(i, i + CHUNK_SIZE);
|
|
130
|
+
const placeholders = slice.map(() => "?").join(", ");
|
|
131
|
+
await db.runAsync(`DELETE FROM ${table} WHERE id IN (${placeholders})`, slice);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Upsert live rows
|
|
135
|
+
if (toUpsert.length > 0) {
|
|
136
|
+
await upsertChunkData({ table, records: toUpsert });
|
|
137
|
+
}
|
|
138
|
+
// Update sync cursor so the next round starts from the right place
|
|
139
|
+
if (prevMaxSyncedAt || prevMaxDeletedAt) {
|
|
140
|
+
await setSupastashSyncStatus(table, tableFilters.get(table) ?? [], {
|
|
141
|
+
lastSyncedAt: prevMaxSyncedAt?.value ?? undefined,
|
|
142
|
+
lastDeletedAt: prevMaxDeletedAt?.value ?? undefined,
|
|
143
|
+
lastSyncedAtPk: prevMaxSyncedAt?.pk ?? null,
|
|
144
|
+
filterNamespace: "global",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (toUpsert.length > 0 || toDelete.length > 0) {
|
|
148
|
+
refreshScreen(table);
|
|
149
|
+
}
|
|
150
|
+
log(`[Supastash] Batch received ${rows.length} rows for "${table}" ` +
|
|
151
|
+
`(u${toUpsert.length}/d${toDelete.length})`);
|
|
152
|
+
SyncInfoUpdater.markLogSuccess({ type: "pull", table });
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
SyncInfoUpdater.markLogError({
|
|
156
|
+
type: "pull",
|
|
157
|
+
table,
|
|
158
|
+
lastError: e,
|
|
159
|
+
errorCount: 1,
|
|
160
|
+
});
|
|
161
|
+
logError(`[Supastash] Batch pull failed for "${table}"`, e);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
// Mark table as fully completed only once it leaves remaining_tables
|
|
165
|
+
if (!nextRemaining.includes(table)) {
|
|
166
|
+
completedTables.add(table);
|
|
167
|
+
SyncInfoUpdater.setTablesCompleted({
|
|
168
|
+
amount: completedTables.size,
|
|
169
|
+
type: "pull",
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
remainingTables = nextRemaining;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
logError("[Supastash] Error in batch pull from remote", error);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
SyncInfoUpdater.reset({ type: "pull" });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AAqC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,0BAA0B,EACrE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,EAAE,CAAC,CAAA;CAAE,QAwCrD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,0BAA0B,KACjC,eAAe,CAAC,CAAC,CAAC,CAEtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,0BAA0B,EACpC,MAAM,EAAE;IACR,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;QAC9B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;KAC3B,CAAC;CACH,QAEA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SupastashFilter } from "../../types/realtimeData.types";
|
|
2
|
+
import { RpcTableFilters } from "../../types/rpcFilter.types";
|
|
2
3
|
/**
|
|
3
4
|
* useSupastashFilters
|
|
4
5
|
*
|
|
@@ -26,11 +27,15 @@ import { SupastashFilter } from "../../types/realtimeData.types";
|
|
|
26
27
|
* });
|
|
27
28
|
* ```
|
|
28
29
|
*
|
|
29
|
-
* @param {SupastashFilter} filters -
|
|
30
|
-
*
|
|
30
|
+
* @param {Record<string, SupastashFilter[]>} filters - Per-table filters applied to both the
|
|
31
|
+
* per-table pull path and (automatically converted) the batch RPC pull path.
|
|
32
|
+
* Covers eq, neq, gt, gte, lt, lte, in, is (null / not-null), and or-groups.
|
|
33
|
+
* @param {RpcTableFilters} rpcFilters - Optional supplemental RPC filter nodes for the batch
|
|
34
|
+
* pull path only. Only needed when you require `and` groups, which `SupastashFilter` doesn't
|
|
35
|
+
* support. These are merged with the auto-converted `filters` before the RPC call.
|
|
31
36
|
*
|
|
32
|
-
* @note This hook does not re-run unless the `filters` object reference changes.
|
|
37
|
+
* @note This hook does not re-run unless the `filters` or `rpcFilters` object reference changes.
|
|
33
38
|
* To force re-evaluation, pass a fresh object (not just mutated data).
|
|
34
39
|
*/
|
|
35
|
-
export declare function useSupastashFilters(filters?: Record<string, SupastashFilter[]
|
|
40
|
+
export declare function useSupastashFilters(filters?: Record<string, SupastashFilter[]>, rpcFilters?: RpcTableFilters): void;
|
|
36
41
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/hooks/supastashFilters/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/hooks/supastashFilters/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAO9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,EAC3C,UAAU,CAAC,EAAE,eAAe,QA6D7B"}
|
|
@@ -2,6 +2,7 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { filterTracker, tableFilters, tableFiltersUsed, } from "../../store/tableFilters";
|
|
3
3
|
import { logWarn } from "../../utils/logs";
|
|
4
4
|
import { ReusedHelpers } from "../../utils/reusedHelpers";
|
|
5
|
+
import { updateRpcFilters } from "../../utils/sync/pullFromRemote/updateRpcFilters";
|
|
5
6
|
import { warnOnMisMatch } from "../../utils/sync/pullFromRemote/validateFilters";
|
|
6
7
|
import { checkIfTableExist } from "../../utils/tableValidator";
|
|
7
8
|
/**
|
|
@@ -31,16 +32,23 @@ import { checkIfTableExist } from "../../utils/tableValidator";
|
|
|
31
32
|
* });
|
|
32
33
|
* ```
|
|
33
34
|
*
|
|
34
|
-
* @param {SupastashFilter} filters -
|
|
35
|
-
*
|
|
35
|
+
* @param {Record<string, SupastashFilter[]>} filters - Per-table filters applied to both the
|
|
36
|
+
* per-table pull path and (automatically converted) the batch RPC pull path.
|
|
37
|
+
* Covers eq, neq, gt, gte, lt, lte, in, is (null / not-null), and or-groups.
|
|
38
|
+
* @param {RpcTableFilters} rpcFilters - Optional supplemental RPC filter nodes for the batch
|
|
39
|
+
* pull path only. Only needed when you require `and` groups, which `SupastashFilter` doesn't
|
|
40
|
+
* support. These are merged with the auto-converted `filters` before the RPC call.
|
|
36
41
|
*
|
|
37
|
-
* @note This hook does not re-run unless the `filters` object reference changes.
|
|
42
|
+
* @note This hook does not re-run unless the `filters` or `rpcFilters` object reference changes.
|
|
38
43
|
* To force re-evaluation, pass a fresh object (not just mutated data).
|
|
39
44
|
*/
|
|
40
|
-
export function useSupastashFilters(filters) {
|
|
45
|
+
export function useSupastashFilters(filters, rpcFilters) {
|
|
41
46
|
useEffect(() => {
|
|
42
47
|
let cancelled = false;
|
|
43
48
|
async function run() {
|
|
49
|
+
if (rpcFilters) {
|
|
50
|
+
await updateRpcFilters(rpcFilters);
|
|
51
|
+
}
|
|
44
52
|
if (!filters)
|
|
45
53
|
return;
|
|
46
54
|
const incoming = Object.keys(filters);
|
|
@@ -82,5 +90,5 @@ export function useSupastashFilters(filters) {
|
|
|
82
90
|
return () => {
|
|
83
91
|
cancelled = true;
|
|
84
92
|
};
|
|
85
|
-
}, [filters]);
|
|
93
|
+
}, [filters, rpcFilters]);
|
|
86
94
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RpcFilterNode } from "../types/rpcFilter.types";
|
|
2
|
+
/**
|
|
3
|
+
* Stores per-table RPC filter nodes used by the batch pull sync path.
|
|
4
|
+
* Keyed by table name, value is the array of RpcFilterNode to apply.
|
|
5
|
+
*/
|
|
6
|
+
export declare const rpcTableFilters: Map<string, RpcFilterNode[]>;
|
|
7
|
+
//# sourceMappingURL=rpcTableFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpcTableFilters.d.ts","sourceRoot":"","sources":["../../../src/shared/store/rpcTableFilters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,eAAe,8BAAqC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type RpcFilterOp =
|
|
2
|
+
| "eq"
|
|
3
|
+
| "neq"
|
|
4
|
+
| "gt"
|
|
5
|
+
| "gte"
|
|
6
|
+
| "lt"
|
|
7
|
+
| "lte"
|
|
8
|
+
| "in"
|
|
9
|
+
| "is_null"
|
|
10
|
+
| "is_not_null";
|
|
11
|
+
|
|
12
|
+
export type RpcSimpleFilter = {
|
|
13
|
+
col: string;
|
|
14
|
+
op: RpcFilterOp;
|
|
15
|
+
val?: string | number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type RpcFilterNode =
|
|
19
|
+
| RpcSimpleFilter
|
|
20
|
+
| { or: RpcFilterNode[] }
|
|
21
|
+
| { and: RpcFilterNode[] };
|
|
22
|
+
|
|
23
|
+
export type RpcTableFilters = Record<string, RpcFilterNode[]>;
|
|
@@ -89,12 +89,12 @@ export type SupastashConfig<T extends SupastashSQLiteClientTypes> = {
|
|
|
89
89
|
sqliteClient: T extends "expo"
|
|
90
90
|
? ExpoSQLiteClient
|
|
91
91
|
: T extends "rn-storage"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
? RNStorageSQLiteClient
|
|
93
|
+
: T extends "rn-nitro"
|
|
94
|
+
? RNSqliteNitroClient
|
|
95
|
+
: T extends "tauri"
|
|
96
|
+
? TauriSQLiteClient
|
|
97
|
+
: null;
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
100
|
* Runtime platform.
|
|
@@ -319,6 +319,34 @@ export type SupastashConfig<T extends SupastashSQLiteClientTypes> = {
|
|
|
319
319
|
* Supastash docs: https://0xzekea.github.io/supastash/docs/sync-calls#%EF%B8%8F-pushrpcpath-custom-batch-sync-rpc
|
|
320
320
|
*/
|
|
321
321
|
pushRPCPath?: string;
|
|
322
|
+
/**
|
|
323
|
+
* When true, pull sync uses a single `supastash_pull_sync` RPC call to fetch
|
|
324
|
+
* all tables in one round trip instead of per-table queries.
|
|
325
|
+
*
|
|
326
|
+
* The RPC handles pagination internally via `remaining_tables` — Supastash
|
|
327
|
+
* will keep calling until all tables are fully synced.
|
|
328
|
+
*
|
|
329
|
+
* Use `updateRpcFilters` to set per-table filters for this mode.
|
|
330
|
+
*
|
|
331
|
+
* ⚠️ Requires the `supastash_pull_sync` Postgres function to be deployed
|
|
332
|
+
* and RLS to be enabled on every table you expose.
|
|
333
|
+
*
|
|
334
|
+
* @default false
|
|
335
|
+
*/
|
|
336
|
+
useBatchPullSync?: boolean;
|
|
337
|
+
/**
|
|
338
|
+
* When true, Supastash fetches column metadata for all tables in a single
|
|
339
|
+
* `get_table_schemas` RPC call at the start of each sync cycle instead of
|
|
340
|
+
* calling `get_table_schema` once per table on demand.
|
|
341
|
+
*
|
|
342
|
+
* Warms the in-memory and SQLite schema caches up front so every subsequent
|
|
343
|
+
* per-table lookup is served from cache with zero extra network calls.
|
|
344
|
+
*
|
|
345
|
+
* Requires the `get_table_schemas` Postgres function to be deployed.
|
|
346
|
+
*
|
|
347
|
+
* @default false
|
|
348
|
+
*/
|
|
349
|
+
useBatchSchemaFetch?: boolean;
|
|
322
350
|
/**
|
|
323
351
|
* Controls how Supastash operates at runtime.
|
|
324
352
|
*
|
|
@@ -443,7 +471,7 @@ export interface SupastashSQLiteExecutor {
|
|
|
443
471
|
*/
|
|
444
472
|
queryOne<T = any>(
|
|
445
473
|
sql: string,
|
|
446
|
-
params?: Record<string, any
|
|
474
|
+
params?: Record<string, any>,
|
|
447
475
|
): Promise<T | null>;
|
|
448
476
|
/**
|
|
449
477
|
* Executes a write or mutation statement.
|
|
@@ -500,14 +528,14 @@ export interface SupastashSQLiteDatabase extends SupastashSQLiteExecutor {
|
|
|
500
528
|
* @returns A Promise that resolves when the transaction is complete
|
|
501
529
|
*/
|
|
502
530
|
withTransaction(
|
|
503
|
-
fn: (tx: SupastashSQLiteExecutor) => Promise<void> | void
|
|
531
|
+
fn: (tx: SupastashSQLiteExecutor) => Promise<void> | void,
|
|
504
532
|
): Promise<void>;
|
|
505
533
|
}
|
|
506
534
|
|
|
507
535
|
export interface SupastashSQLiteAdapter<TClient = any> {
|
|
508
536
|
openDatabaseAsync(
|
|
509
537
|
name: string,
|
|
510
|
-
sqliteClient: TClient
|
|
538
|
+
sqliteClient: TClient,
|
|
511
539
|
): Promise<SupastashSQLiteDatabase>;
|
|
512
540
|
}
|
|
513
541
|
|
|
@@ -515,7 +543,7 @@ export interface ExpoSQLiteClient {
|
|
|
515
543
|
openDatabaseAsync: (
|
|
516
544
|
databaseName: string,
|
|
517
545
|
options?: SQLiteOpenOptions | undefined,
|
|
518
|
-
directory?: string | undefined
|
|
546
|
+
directory?: string | undefined,
|
|
519
547
|
) => Promise<ExpoSQLiteDatabase>;
|
|
520
548
|
}
|
|
521
549
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSyncStatus.d.ts","sourceRoot":"","sources":["../../../../src/shared/utils/schema/createSyncStatus.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,wBAAwB,kBAE7C;AAED,eAAO,MAAM,sBAAsB,0ZAUhC,CAAC;AAEJ,eAAO,MAAM,6BAA6B,6eAezC,CAAC;AAEF,eAAO,MAAM,wBAAwB,mFAEpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,2GAGhC,CAAC;AAEF,eAAO,MAAM,2BAA2B,yHAGvC,CAAC;AAIF;;;;GAIG;AACH,wBAAsB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"createSyncStatus.d.ts","sourceRoot":"","sources":["../../../../src/shared/utils/schema/createSyncStatus.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,wBAAwB,kBAE7C;AAED,eAAO,MAAM,sBAAsB,0ZAUhC,CAAC;AAEJ,eAAO,MAAM,6BAA6B,6eAezC,CAAC;AAEF,eAAO,MAAM,wBAAwB,mFAEpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,2GAGhC,CAAC;AAEF,eAAO,MAAM,2BAA2B,yHAGvC,CAAC;AAIF;;;;GAIG;AACH,wBAAsB,qBAAqB,kBAiC1C;AAED,wEAAwE;AACxE,wBAAgB,yBAAyB,SAExC"}
|
|
@@ -67,12 +67,19 @@ export async function createSyncStatusTable() {
|
|
|
67
67
|
await db.execAsync(SYNC_STATUS_TABLES_SQL);
|
|
68
68
|
await db.execAsync(INDEX_SYNC_MARKS_SQL);
|
|
69
69
|
}
|
|
70
|
-
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
// try {
|
|
71
|
+
// const columns = await db.getAllAsync<{ name: string }>(
|
|
72
|
+
// `SELECT name FROM pragma_table_info('supastash_sync_marks')`,
|
|
73
|
+
// );
|
|
74
|
+
// const hasColumn = columns.some(
|
|
75
|
+
// (column) => column.name === "last_synced_at_pk",
|
|
76
|
+
// );
|
|
77
|
+
// if (!hasColumn) {
|
|
78
|
+
// await db.execAsync(ADD_PK_TO_SYNC_MARKS_SQL);
|
|
79
|
+
// }
|
|
80
|
+
// } catch {
|
|
81
|
+
// // Ignore — column already exists
|
|
82
|
+
// }
|
|
76
83
|
})();
|
|
77
84
|
return syncStatusTablePromise;
|
|
78
85
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SupastashFilter } from "../../../types/realtimeData.types";
|
|
2
|
+
import { RpcFilterNode } from "../../../types/rpcFilter.types";
|
|
3
|
+
/**
|
|
4
|
+
* Converts PostgREST-style SupastashFilter[] to RpcFilterNode[].
|
|
5
|
+
* Supports simple filters and { or: [...] } groups.
|
|
6
|
+
* Returns an empty array for an empty/undefined input.
|
|
7
|
+
*/
|
|
8
|
+
export declare function postgrestFiltersToRpc(filters: SupastashFilter[] | undefined): RpcFilterNode[];
|
|
9
|
+
//# sourceMappingURL=postgrestToRpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgrestToRpc.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/pullFromRemote/postgrestToRpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAe,MAAM,gCAAgC,CAAC;AA+B5E;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,GACrC,aAAa,EAAE,CAgBjB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a single PostgREST Filter to an RpcFilterNode.
|
|
3
|
+
* Used so that tableFilters registered via useSupastashFilters are
|
|
4
|
+
* automatically applied in the batch pull RPC path.
|
|
5
|
+
*/
|
|
6
|
+
function convertFilter(f) {
|
|
7
|
+
const col = String(f.column);
|
|
8
|
+
if (f.operator === "is") {
|
|
9
|
+
return f.value === null
|
|
10
|
+
? { col, op: "is_null" }
|
|
11
|
+
: { col, op: "is_not_null" };
|
|
12
|
+
}
|
|
13
|
+
// For "in", the SQL compiler expects a comma-separated string
|
|
14
|
+
if (f.operator === "in") {
|
|
15
|
+
const val = Array.isArray(f.value)
|
|
16
|
+
? f.value.join(",")
|
|
17
|
+
: String(f.value ?? "");
|
|
18
|
+
return { col, op: "in", val };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
col,
|
|
22
|
+
op: f.operator,
|
|
23
|
+
val: f.value,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Converts PostgREST-style SupastashFilter[] to RpcFilterNode[].
|
|
28
|
+
* Supports simple filters and { or: [...] } groups.
|
|
29
|
+
* Returns an empty array for an empty/undefined input.
|
|
30
|
+
*/
|
|
31
|
+
export function postgrestFiltersToRpc(filters) {
|
|
32
|
+
if (!filters?.length)
|
|
33
|
+
return [];
|
|
34
|
+
const result = [];
|
|
35
|
+
for (const f of filters) {
|
|
36
|
+
if ("or" in f) {
|
|
37
|
+
const nodes = f.or
|
|
38
|
+
.map(convertFilter)
|
|
39
|
+
.filter((n) => n !== null);
|
|
40
|
+
if (nodes.length)
|
|
41
|
+
result.push({ or: nodes });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const node = convertFilter(f);
|
|
45
|
+
if (node)
|
|
46
|
+
result.push(node);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { SupastashFilter } from "../../../types/realtimeData.types";
|
|
2
|
+
import { RpcTableFilters } from "../../../types/rpcFilter.types";
|
|
2
3
|
/**
|
|
3
|
-
* Updates the filter for the given table
|
|
4
|
-
* Non-hook version of useSupastashFilters
|
|
4
|
+
* Updates the filter for the given table.
|
|
5
|
+
* Non-hook version of useSupastashFilters.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* @param filters - PostgREST filters for the standard pull path. Automatically converted
|
|
8
|
+
* and applied in the batch RPC pull path too.
|
|
9
|
+
* @param rpcFilters - Optional supplemental RPC filter nodes. Only needed for `and` groups
|
|
10
|
+
* or other constructs SupastashFilter can't express.
|
|
8
11
|
*/
|
|
9
|
-
export declare function updateFilters(filters: SupastashFilter): Promise<void>;
|
|
12
|
+
export declare function updateFilters(filters: SupastashFilter, rpcFilters?: RpcTableFilters): Promise<void>;
|
|
10
13
|
//# sourceMappingURL=updateFilter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateFilter.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/pullFromRemote/updateFilter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"updateFilter.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/pullFromRemote/updateFilter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAOjE;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,eAAe,EACxB,UAAU,CAAC,EAAE,eAAe,iBA6C7B"}
|
|
@@ -2,15 +2,21 @@ import { filterTracker, tableFilters, tableFiltersUsed, } from "../../../store/t
|
|
|
2
2
|
import { logWarn } from "../../logs";
|
|
3
3
|
import { ReusedHelpers } from "../../reusedHelpers";
|
|
4
4
|
import { checkIfTableExist } from "../../tableValidator";
|
|
5
|
+
import { updateRpcFilters } from "./updateRpcFilters";
|
|
5
6
|
import { warnOnMisMatch } from "./validateFilters";
|
|
6
7
|
/**
|
|
7
|
-
* Updates the filter for the given table
|
|
8
|
-
* Non-hook version of useSupastashFilters
|
|
8
|
+
* Updates the filter for the given table.
|
|
9
|
+
* Non-hook version of useSupastashFilters.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* @param filters - PostgREST filters for the standard pull path. Automatically converted
|
|
12
|
+
* and applied in the batch RPC pull path too.
|
|
13
|
+
* @param rpcFilters - Optional supplemental RPC filter nodes. Only needed for `and` groups
|
|
14
|
+
* or other constructs SupastashFilter can't express.
|
|
12
15
|
*/
|
|
13
|
-
export async function updateFilters(filters) {
|
|
16
|
+
export async function updateFilters(filters, rpcFilters) {
|
|
17
|
+
if (rpcFilters) {
|
|
18
|
+
await updateRpcFilters(rpcFilters);
|
|
19
|
+
}
|
|
14
20
|
const incoming = Object.keys(filters ?? {});
|
|
15
21
|
// Remove stale tables
|
|
16
22
|
for (const t of Array.from(tableFilters.keys())) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RpcTableFilters } from "../../../types/rpcFilter.types";
|
|
2
|
+
/**
|
|
3
|
+
* Registers explicit RPC filter nodes for the batch pull path (useBatchPullSync: true).
|
|
4
|
+
*
|
|
5
|
+
* Only needed for constructs SupastashFilter can't express (e.g. `and` groups).
|
|
6
|
+
* Filters registered via useSupastashFilters / updateFilters are automatically
|
|
7
|
+
* converted and applied in the batch path — no separate call needed for those.
|
|
8
|
+
*
|
|
9
|
+
* Called automatically by useSupastashFilters / updateFilters.
|
|
10
|
+
*/
|
|
11
|
+
export declare function updateRpcFilters(filters?: RpcTableFilters): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=updateRpcFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateRpcFilters.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/pullFromRemote/updateRpcFilters.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAIhF;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B/E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { rpcTableFilters } from "../../../store/rpcTableFilters";
|
|
2
|
+
import { logWarn } from "../../logs";
|
|
3
|
+
import { checkIfTableExist } from "../../tableValidator";
|
|
4
|
+
/**
|
|
5
|
+
* Registers explicit RPC filter nodes for the batch pull path (useBatchPullSync: true).
|
|
6
|
+
*
|
|
7
|
+
* Only needed for constructs SupastashFilter can't express (e.g. `and` groups).
|
|
8
|
+
* Filters registered via useSupastashFilters / updateFilters are automatically
|
|
9
|
+
* converted and applied in the batch path — no separate call needed for those.
|
|
10
|
+
*
|
|
11
|
+
* Called automatically by useSupastashFilters / updateFilters.
|
|
12
|
+
*/
|
|
13
|
+
export async function updateRpcFilters(filters) {
|
|
14
|
+
const incoming = Object.keys(filters ?? {});
|
|
15
|
+
// Remove stale tables no longer in the incoming set
|
|
16
|
+
for (const t of Array.from(rpcTableFilters.keys())) {
|
|
17
|
+
if (!incoming.includes(t)) {
|
|
18
|
+
rpcTableFilters.delete(t);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (!incoming.length)
|
|
22
|
+
return;
|
|
23
|
+
const existence = await Promise.all(incoming.map(async (t) => [t, await checkIfTableExist(t)]));
|
|
24
|
+
for (const [table, exists] of existence) {
|
|
25
|
+
if (!exists) {
|
|
26
|
+
logWarn(`[Supastash] Table '${table}' does not exist; skipping RPC filters`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const nodes = (filters[table] ?? []);
|
|
30
|
+
if (!nodes.length) {
|
|
31
|
+
rpcTableFilters.delete(table);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
rpcTableFilters.set(table, nodes.map((n) => ({ ...n })));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { TableSchema } from "../../../types/realtimeData.types";
|
|
2
2
|
export declare function appendSyncedAt(schema: TableSchema[]): TableSchema[];
|
|
3
|
+
/**
|
|
4
|
+
* Fetches column metadata for all supplied tables in a single RPC call
|
|
5
|
+
* and warms both the in-memory cache and the SQLite fallback store.
|
|
6
|
+
*
|
|
7
|
+
* Requires `useBatchSchemaFetch: true` in config and the
|
|
8
|
+
* `get_table_schemas` Postgres function to be deployed.
|
|
9
|
+
*
|
|
10
|
+
* Tables already in the memory cache are skipped.
|
|
11
|
+
* Validation errors for individual tables are logged and skipped —
|
|
12
|
+
* they will surface as normal errors when that table is first used.
|
|
13
|
+
*/
|
|
14
|
+
export declare function prefetchRemoteTableSchemas(tables: string[]): Promise<void>;
|
|
3
15
|
export declare function getRemoteTableSchema(table: string): Promise<TableSchema[] | null>;
|
|
4
16
|
//# sourceMappingURL=remoteSchema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remoteSchema.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/status/remoteSchema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AA4HhE,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,iBASnD;AAID,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAkD/B"}
|
|
1
|
+
{"version":3,"file":"remoteSchema.d.ts","sourceRoot":"","sources":["../../../../../src/shared/utils/sync/status/remoteSchema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AA4HhE,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,iBASnD;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAkD/B"}
|
|
@@ -98,6 +98,52 @@ export function appendSyncedAt(schema) {
|
|
|
98
98
|
];
|
|
99
99
|
}
|
|
100
100
|
const localSchemaCache = new Map();
|
|
101
|
+
/**
|
|
102
|
+
* Fetches column metadata for all supplied tables in a single RPC call
|
|
103
|
+
* and warms both the in-memory cache and the SQLite fallback store.
|
|
104
|
+
*
|
|
105
|
+
* Requires `useBatchSchemaFetch: true` in config and the
|
|
106
|
+
* `get_table_schemas` Postgres function to be deployed.
|
|
107
|
+
*
|
|
108
|
+
* Tables already in the memory cache are skipped.
|
|
109
|
+
* Validation errors for individual tables are logged and skipped —
|
|
110
|
+
* they will surface as normal errors when that table is first used.
|
|
111
|
+
*/
|
|
112
|
+
export async function prefetchRemoteTableSchemas(tables) {
|
|
113
|
+
const config = getSupastashConfig();
|
|
114
|
+
const supabase = config?.supabaseClient;
|
|
115
|
+
if (!supabase)
|
|
116
|
+
return;
|
|
117
|
+
const online = await isOnline();
|
|
118
|
+
if (!online)
|
|
119
|
+
return;
|
|
120
|
+
const toFetch = tables.filter((t) => !tableSchemaData.has(t));
|
|
121
|
+
if (!toFetch.length)
|
|
122
|
+
return;
|
|
123
|
+
const { data, error } = await supabase.rpc("get_table_schemas", {
|
|
124
|
+
p_tables: toFetch,
|
|
125
|
+
});
|
|
126
|
+
if (error || !data) {
|
|
127
|
+
if (error && !isNetworkError(error)) {
|
|
128
|
+
log(`[Supastash] Error batch-fetching table schemas: ${error.message}
|
|
129
|
+
You can find more information in the Supastash docs: ${SERVER_SIDE_DOCS_URL}`);
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
await ensureRemoteSchemaTableExists();
|
|
134
|
+
for (const [table, schema] of Object.entries(data)) {
|
|
135
|
+
if (!Array.isArray(schema))
|
|
136
|
+
continue;
|
|
137
|
+
try {
|
|
138
|
+
validatePayloadForTable(schema, table);
|
|
139
|
+
await upsertRemoteSchema(table, schema);
|
|
140
|
+
tableSchemaData.set(table, schema);
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
logWarn(`[Supastash] Schema validation failed for "${table}" during batch fetch: ${e?.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
101
147
|
export async function getRemoteTableSchema(table) {
|
|
102
148
|
const config = getSupastashConfig();
|
|
103
149
|
const supabase = config?.supabaseClient;
|