supastash 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -0
- package/dist/core/config/index.d.ts +90 -0
- package/dist/core/config/index.d.ts.map +1 -0
- package/dist/core/config/index.js +111 -0
- package/dist/core/schemaManager/index.d.ts +19 -0
- package/dist/core/schemaManager/index.d.ts.map +1 -0
- package/dist/core/schemaManager/index.js +53 -0
- package/dist/db/adapters/expo_sqlite.d.ts +3 -0
- package/dist/db/adapters/expo_sqlite.d.ts.map +1 -0
- package/dist/db/adapters/expo_sqlite.js +21 -0
- package/dist/db/adapters/rn_nitro.d.ts +3 -0
- package/dist/db/adapters/rn_nitro.d.ts.map +1 -0
- package/dist/db/adapters/rn_nitro.js +22 -0
- package/dist/db/adapters/rn_sqlite_storage.d.ts +3 -0
- package/dist/db/adapters/rn_sqlite_storage.d.ts.map +1 -0
- package/dist/db/adapters/rn_sqlite_storage.js +22 -0
- package/dist/db/dbErrorMsg.d.ts +2 -0
- package/dist/db/dbErrorMsg.d.ts.map +1 -0
- package/dist/db/dbErrorMsg.js +28 -0
- package/dist/db/dbInitializer.d.ts +7 -0
- package/dist/db/dbInitializer.d.ts.map +1 -0
- package/dist/db/dbInitializer.js +33 -0
- package/dist/hooks/supastashData/addPayloadToUI.d.ts +2 -0
- package/dist/hooks/supastashData/addPayloadToUI.d.ts.map +1 -0
- package/dist/hooks/supastashData/addPayloadToUI.js +36 -0
- package/dist/hooks/supastashData/dataState.d.ts +8 -0
- package/dist/hooks/supastashData/dataState.d.ts.map +1 -0
- package/dist/hooks/supastashData/dataState.js +7 -0
- package/dist/hooks/supastashData/eventQueues.d.ts +5 -0
- package/dist/hooks/supastashData/eventQueues.d.ts.map +1 -0
- package/dist/hooks/supastashData/eventQueues.js +54 -0
- package/dist/hooks/supastashData/fetchCalls.d.ts +9 -0
- package/dist/hooks/supastashData/fetchCalls.d.ts.map +1 -0
- package/dist/hooks/supastashData/fetchCalls.js +63 -0
- package/dist/hooks/supastashData/index.d.ts +53 -0
- package/dist/hooks/supastashData/index.d.ts.map +1 -0
- package/dist/hooks/supastashData/index.js +95 -0
- package/dist/hooks/supastashData/realtimeSubscription.d.ts +5 -0
- package/dist/hooks/supastashData/realtimeSubscription.d.ts.map +1 -0
- package/dist/hooks/supastashData/realtimeSubscription.js +95 -0
- package/dist/hooks/supastashData/registerSub.d.ts +4 -0
- package/dist/hooks/supastashData/registerSub.d.ts.map +1 -0
- package/dist/hooks/supastashData/registerSub.js +20 -0
- package/dist/hooks/supastashLogic.d.ts +19 -0
- package/dist/hooks/supastashLogic.d.ts.map +1 -0
- package/dist/hooks/supastashLogic.js +67 -0
- package/dist/hooks/syncEngine/index.d.ts +9 -0
- package/dist/hooks/syncEngine/index.d.ts.map +1 -0
- package/dist/hooks/syncEngine/index.js +66 -0
- package/dist/hooks/syncEngine/pullFromRemote/index.d.ts +5 -0
- package/dist/hooks/syncEngine/pullFromRemote/index.d.ts.map +1 -0
- package/dist/hooks/syncEngine/pullFromRemote/index.js +28 -0
- package/dist/hooks/syncEngine/pushLocal/index.d.ts +5 -0
- package/dist/hooks/syncEngine/pushLocal/index.d.ts.map +1 -0
- package/dist/hooks/syncEngine/pushLocal/index.js +36 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/store/tableFilters.d.ts +3 -0
- package/dist/store/tableFilters.d.ts.map +1 -0
- package/dist/store/tableFilters.js +2 -0
- package/dist/types/expoSqlite.types.d.ts +57 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/query.types.d.ts +153 -0
- package/dist/types/realtimeData.types.d.ts +186 -0
- package/dist/types/rnNitroSqlite.types.d.ts +101 -0
- package/dist/types/rnSqliteStorage.types.d.ts +67 -0
- package/dist/types/schemaManager.types.d.ts +44 -0
- package/dist/types/supastashConfig.types.d.ts +72 -0
- package/dist/types/syncEngine.types.d.ts +12 -0
- package/dist/utils/connection.d.ts +2 -0
- package/dist/utils/connection.d.ts.map +1 -0
- package/dist/utils/connection.js +7 -0
- package/dist/utils/events/eventBus.d.ts +3 -0
- package/dist/utils/events/eventBus.d.ts.map +1 -0
- package/dist/utils/events/eventBus.js +4 -0
- package/dist/utils/fetchData/buildFilter.d.ts +7 -0
- package/dist/utils/fetchData/buildFilter.d.ts.map +1 -0
- package/dist/utils/fetchData/buildFilter.js +13 -0
- package/dist/utils/fetchData/createTable.d.ts +8 -0
- package/dist/utils/fetchData/createTable.d.ts.map +1 -0
- package/dist/utils/fetchData/createTable.js +48 -0
- package/dist/utils/fetchData/deleteData.d.ts +3 -0
- package/dist/utils/fetchData/deleteData.d.ts.map +1 -0
- package/dist/utils/fetchData/deleteData.js +25 -0
- package/dist/utils/fetchData/fetchLocalData.d.ts +9 -0
- package/dist/utils/fetchData/fetchLocalData.d.ts.map +1 -0
- package/dist/utils/fetchData/fetchLocalData.js +51 -0
- package/dist/utils/fetchData/getKeyType.d.ts +7 -0
- package/dist/utils/fetchData/getKeyType.d.ts.map +1 -0
- package/dist/utils/fetchData/getKeyType.js +25 -0
- package/dist/utils/fetchData/initialFetch.d.ts +3 -0
- package/dist/utils/fetchData/initialFetch.d.ts.map +1 -0
- package/dist/utils/fetchData/initialFetch.js +20 -0
- package/dist/utils/fetchData/realTimeCall.d.ts +5 -0
- package/dist/utils/fetchData/realTimeCall.d.ts.map +1 -0
- package/dist/utils/fetchData/realTimeCall.js +43 -0
- package/dist/utils/fetchData/realTimeManager.d.ts +40 -0
- package/dist/utils/fetchData/realTimeManager.d.ts.map +1 -0
- package/dist/utils/fetchData/realTimeManager.js +262 -0
- package/dist/utils/fetchData/receiveData.d.ts +3 -0
- package/dist/utils/fetchData/receiveData.d.ts.map +1 -0
- package/dist/utils/fetchData/receiveData.js +38 -0
- package/dist/utils/fetchData/setDataInBatches.d.ts +3 -0
- package/dist/utils/fetchData/setDataInBatches.d.ts.map +1 -0
- package/dist/utils/fetchData/setDataInBatches.js +20 -0
- package/dist/utils/fetchData/validatePayload.d.ts +7 -0
- package/dist/utils/fetchData/validatePayload.d.ts.map +1 -0
- package/dist/utils/fetchData/validatePayload.js +18 -0
- package/dist/utils/genUUID.d.ts +2 -0
- package/dist/utils/genUUID.d.ts.map +1 -0
- package/dist/utils/genUUID.js +7 -0
- package/dist/utils/getTableSchema.d.ts +8 -0
- package/dist/utils/getTableSchema.d.ts.map +1 -0
- package/dist/utils/getTableSchema.js +28 -0
- package/dist/utils/logs.d.ts +7 -0
- package/dist/utils/logs.d.ts.map +1 -0
- package/dist/utils/logs.js +15 -0
- package/dist/utils/query/builder/crud.d.ts +50 -0
- package/dist/utils/query/builder/crud.d.ts.map +1 -0
- package/dist/utils/query/builder/crud.js +83 -0
- package/dist/utils/query/builder/filters.d.ts +145 -0
- package/dist/utils/query/builder/filters.d.ts.map +1 -0
- package/dist/utils/query/builder/filters.js +223 -0
- package/dist/utils/query/builder/index.d.ts +45 -0
- package/dist/utils/query/builder/index.d.ts.map +1 -0
- package/dist/utils/query/builder/index.js +60 -0
- package/dist/utils/query/builder/mainQuery.d.ts +10 -0
- package/dist/utils/query/builder/mainQuery.d.ts.map +1 -0
- package/dist/utils/query/builder/mainQuery.js +63 -0
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts +15 -0
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts.map +1 -0
- package/dist/utils/query/helpers/localDb/getLocalMethod.js +24 -0
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts +34 -0
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts.map +1 -0
- package/dist/utils/query/helpers/localDb/localQueryBuilder.js +52 -0
- package/dist/utils/query/helpers/mainQueryHelpers.d.ts +12 -0
- package/dist/utils/query/helpers/mainQueryHelpers.d.ts.map +1 -0
- package/dist/utils/query/helpers/mainQueryHelpers.js +164 -0
- package/dist/utils/query/helpers/queryValidator.d.ts +7 -0
- package/dist/utils/query/helpers/queryValidator.d.ts.map +1 -0
- package/dist/utils/query/helpers/queryValidator.js +27 -0
- package/dist/utils/query/helpers/remoteDb/queryFilterBuilder.d.ts +12 -0
- package/dist/utils/query/helpers/remoteDb/queryFilterBuilder.d.ts.map +1 -0
- package/dist/utils/query/helpers/remoteDb/queryFilterBuilder.js +41 -0
- package/dist/utils/query/helpers/remoteDb/queryUtils.d.ts +8 -0
- package/dist/utils/query/helpers/remoteDb/queryUtils.d.ts.map +1 -0
- package/dist/utils/query/helpers/remoteDb/queryUtils.js +30 -0
- package/dist/utils/query/localDbQuery/delete.d.ts +16 -0
- package/dist/utils/query/localDbQuery/delete.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/delete.js +54 -0
- package/dist/utils/query/localDbQuery/index.d.ts +8 -0
- package/dist/utils/query/localDbQuery/index.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/index.js +15 -0
- package/dist/utils/query/localDbQuery/insert.d.ts +10 -0
- package/dist/utils/query/localDbQuery/insert.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/insert.js +64 -0
- package/dist/utils/query/localDbQuery/select.d.ts +13 -0
- package/dist/utils/query/localDbQuery/select.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/select.js +41 -0
- package/dist/utils/query/localDbQuery/update.d.ts +11 -0
- package/dist/utils/query/localDbQuery/update.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/update.js +56 -0
- package/dist/utils/query/localDbQuery/upsert.d.ts +9 -0
- package/dist/utils/query/localDbQuery/upsert.d.ts.map +1 -0
- package/dist/utils/query/localDbQuery/upsert.js +67 -0
- package/dist/utils/query/remoteQuery/supabaseQuery.d.ts +8 -0
- package/dist/utils/query/remoteQuery/supabaseQuery.d.ts.map +1 -0
- package/dist/utils/query/remoteQuery/supabaseQuery.js +124 -0
- package/dist/utils/schema/createSyncStatus.d.ts +9 -0
- package/dist/utils/schema/createSyncStatus.d.ts.map +1 -0
- package/dist/utils/schema/createSyncStatus.js +23 -0
- package/dist/utils/schema/wipeTables.d.ts +66 -0
- package/dist/utils/schema/wipeTables.d.ts.map +1 -0
- package/dist/utils/schema/wipeTables.js +124 -0
- package/dist/utils/serializer.d.ts +8 -0
- package/dist/utils/serializer.d.ts.map +1 -0
- package/dist/utils/serializer.js +32 -0
- package/dist/utils/supabaseClientErr.d.ts +2 -0
- package/dist/utils/supabaseClientErr.d.ts.map +1 -0
- package/dist/utils/supabaseClientErr.js +15 -0
- package/dist/utils/sync/getAllTables.d.ts +2 -0
- package/dist/utils/sync/getAllTables.d.ts.map +1 -0
- package/dist/utils/sync/getAllTables.js +7 -0
- package/dist/utils/sync/pullFromRemote/getLastDeletedInfo.d.ts +13 -0
- package/dist/utils/sync/pullFromRemote/getLastDeletedInfo.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/getLastDeletedInfo.js +29 -0
- package/dist/utils/sync/pullFromRemote/getLastPulledInfo.d.ts +13 -0
- package/dist/utils/sync/pullFromRemote/getLastPulledInfo.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/getLastPulledInfo.js +29 -0
- package/dist/utils/sync/pullFromRemote/pullData.d.ts +9 -0
- package/dist/utils/sync/pullFromRemote/pullData.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/pullData.js +71 -0
- package/dist/utils/sync/pullFromRemote/pullDeletedData.d.ts +12 -0
- package/dist/utils/sync/pullFromRemote/pullDeletedData.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/pullDeletedData.js +69 -0
- package/dist/utils/sync/pullFromRemote/stringifyFields.d.ts +2 -0
- package/dist/utils/sync/pullFromRemote/stringifyFields.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/stringifyFields.js +11 -0
- package/dist/utils/sync/pullFromRemote/updateLocalDb.d.ts +14 -0
- package/dist/utils/sync/pullFromRemote/updateLocalDb.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/updateLocalDb.js +128 -0
- package/dist/utils/sync/pushLocal/deleteChunks.d.ts +8 -0
- package/dist/utils/sync/pushLocal/deleteChunks.d.ts.map +1 -0
- package/dist/utils/sync/pushLocal/deleteChunks.js +51 -0
- package/dist/utils/sync/pushLocal/getAllUnsyncedData.d.ts +14 -0
- package/dist/utils/sync/pushLocal/getAllUnsyncedData.d.ts.map +1 -0
- package/dist/utils/sync/pushLocal/getAllUnsyncedData.js +70 -0
- package/dist/utils/sync/pushLocal/parseFields.d.ts +7 -0
- package/dist/utils/sync/pushLocal/parseFields.d.ts.map +1 -0
- package/dist/utils/sync/pushLocal/parseFields.js +24 -0
- package/dist/utils/sync/pushLocal/sendUnsyncedToSupabase.d.ts +6 -0
- package/dist/utils/sync/pushLocal/sendUnsyncedToSupabase.d.ts.map +1 -0
- package/dist/utils/sync/pushLocal/sendUnsyncedToSupabase.js +43 -0
- package/dist/utils/sync/pushLocal/uploadChunk.d.ts +8 -0
- package/dist/utils/sync/pushLocal/uploadChunk.d.ts.map +1 -0
- package/dist/utils/sync/pushLocal/uploadChunk.js +117 -0
- package/dist/utils/sync/refreshTables.d.ts +12 -0
- package/dist/utils/sync/refreshTables.d.ts.map +1 -0
- package/dist/utils/sync/refreshTables.js +40 -0
- package/dist/utils/syncStatus.d.ts +67 -0
- package/dist/utils/syncStatus.d.ts.map +1 -0
- package/dist/utils/syncStatus.js +97 -0
- package/dist/utils/syncUpdate.d.ts +7 -0
- package/dist/utils/syncUpdate.d.ts.map +1 -0
- package/dist/utils/syncUpdate.js +19 -0
- package/dist/utils/tableValidator.d.ts +12 -0
- package/dist/utils/tableValidator.d.ts.map +1 -0
- package/dist/utils/tableValidator.js +23 -0
- package/package.json +60 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
2
|
+
const DEFAULT_LAST_PULLED_AT = "2024-01-01T00:00:00Z";
|
|
3
|
+
const SYNC_STATUS_TABLE = "supastash_sync_status";
|
|
4
|
+
/**
|
|
5
|
+
* Gets the last synced timestamp for a given table
|
|
6
|
+
* @param table - The table to get the last synced timestamp for
|
|
7
|
+
* @returns The last synced timestamp
|
|
8
|
+
*/
|
|
9
|
+
export async function getLastPulledInfo(table) {
|
|
10
|
+
const db = await getSupastashDb();
|
|
11
|
+
// Add table name to supastash_sync_status if it doesn't exist
|
|
12
|
+
await db.runAsync(`INSERT OR IGNORE INTO supastash_sync_status (table_name, last_synced_at) VALUES (?, ?)`, [table, DEFAULT_LAST_PULLED_AT]);
|
|
13
|
+
// Get the latest sync timestamp for this table
|
|
14
|
+
const result = await db.getFirstAsync(`SELECT last_synced_at FROM ${SYNC_STATUS_TABLE} WHERE table_name = ?`, [table]);
|
|
15
|
+
const original = result?.last_synced_at || DEFAULT_LAST_PULLED_AT;
|
|
16
|
+
const timestamp = Date.parse(original);
|
|
17
|
+
const lastSyncedAt = new Date(timestamp + 1);
|
|
18
|
+
const lastSyncedAtISOString = lastSyncedAt.toISOString();
|
|
19
|
+
return lastSyncedAtISOString;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Updates the last synced timestamp for a given table
|
|
23
|
+
* @param table - The table to update the last synced timestamp for
|
|
24
|
+
* @param lastSyncedAt - The last synced timestamp
|
|
25
|
+
*/
|
|
26
|
+
export async function updateLastPulledInfo(table, lastSyncedAt) {
|
|
27
|
+
const db = await getSupastashDb();
|
|
28
|
+
await db.runAsync(`UPDATE ${SYNC_STATUS_TABLE} SET last_synced_at = ? WHERE table_name = ?`, [lastSyncedAt, table]);
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PayloadData } from "../../../types/query.types";
|
|
2
|
+
import { RealtimeFilter } from "../../../types/realtimeData.types";
|
|
3
|
+
/**
|
|
4
|
+
* Pulls data from the remote database for a given table
|
|
5
|
+
* @param table - The table to pull data from
|
|
6
|
+
* @returns The data from the table
|
|
7
|
+
*/
|
|
8
|
+
export declare function pullData(table: string, filter?: RealtimeFilter): Promise<PayloadData[] | null>;
|
|
9
|
+
//# sourceMappingURL=pullData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pullData.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/pullData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAoBnE;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAsE/B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import log from "../../logs";
|
|
3
|
+
import { supabaseClientErr } from "../../supabaseClientErr";
|
|
4
|
+
import { getLastPulledInfo, updateLastPulledInfo } from "./getLastPulledInfo";
|
|
5
|
+
const validOperators = new Set([
|
|
6
|
+
"eq",
|
|
7
|
+
"neq",
|
|
8
|
+
"gt",
|
|
9
|
+
"lt",
|
|
10
|
+
"gte",
|
|
11
|
+
"lte",
|
|
12
|
+
"like",
|
|
13
|
+
"ilike",
|
|
14
|
+
"is",
|
|
15
|
+
"in",
|
|
16
|
+
]);
|
|
17
|
+
let timesPushed = 0;
|
|
18
|
+
let lastPushed = 0;
|
|
19
|
+
/**
|
|
20
|
+
* Pulls data from the remote database for a given table
|
|
21
|
+
* @param table - The table to pull data from
|
|
22
|
+
* @returns The data from the table
|
|
23
|
+
*/
|
|
24
|
+
export async function pullData(table, filter) {
|
|
25
|
+
const lastSyncedAt = await getLastPulledInfo(table);
|
|
26
|
+
const supabase = getSupastashConfig().supabaseClient;
|
|
27
|
+
if (!supabase)
|
|
28
|
+
throw new Error(`No supabase client found: ${supabaseClientErr}`);
|
|
29
|
+
let filteredQuery = supabase
|
|
30
|
+
.from(table)
|
|
31
|
+
.select("*")
|
|
32
|
+
.gt("updated_at", lastSyncedAt)
|
|
33
|
+
.is("deleted_at", null)
|
|
34
|
+
.order("updated_at", { ascending: false, nullsFirst: false });
|
|
35
|
+
if (filter &&
|
|
36
|
+
(!filter.operator ||
|
|
37
|
+
!validOperators.has(filter.operator) ||
|
|
38
|
+
!filter.column ||
|
|
39
|
+
!filter.value)) {
|
|
40
|
+
throw new Error(`Invalid filter: ${JSON.stringify(filter)} for table ${table}`);
|
|
41
|
+
}
|
|
42
|
+
if (filter?.operator &&
|
|
43
|
+
validOperators.has(filter.operator) &&
|
|
44
|
+
filter.column &&
|
|
45
|
+
filter.value) {
|
|
46
|
+
filteredQuery = filteredQuery[filter.operator](filter.column, filter.value);
|
|
47
|
+
}
|
|
48
|
+
// Fetch records updated after the last sync
|
|
49
|
+
const { data, error } = await filteredQuery;
|
|
50
|
+
if (error) {
|
|
51
|
+
log(`[Supastash] Error fetching from ${table}:`, error.message);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (!data || data.length === 0) {
|
|
55
|
+
timesPushed++;
|
|
56
|
+
if (timesPushed >= 30) {
|
|
57
|
+
const timeSinceLastPush = Date.now() - lastPushed;
|
|
58
|
+
lastPushed = Date.now();
|
|
59
|
+
log(`[Supastash] No updates for ${table} at ${lastSyncedAt} (times pushed: ${timesPushed}) in the last ${timeSinceLastPush}ms`);
|
|
60
|
+
timesPushed = 0;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
log(`Received ${data.length} updates for ${table}`);
|
|
65
|
+
// Update the supastash_sync_status table with the lastest timestamp
|
|
66
|
+
const lastest = data.find((r) => r.updated_at)?.updated_at;
|
|
67
|
+
if (lastest) {
|
|
68
|
+
await updateLastPulledInfo(table, lastest);
|
|
69
|
+
}
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PayloadData } from "../../../types/query.types";
|
|
2
|
+
import { RealtimeFilter } from "../../../types/realtimeData.types";
|
|
3
|
+
/**
|
|
4
|
+
* Pulls deleted data from the remote database for a given table
|
|
5
|
+
* @param table - The table to pull deleted data from
|
|
6
|
+
* @returns The deleted data from the table as a map of id to record and the reordered data
|
|
7
|
+
*/
|
|
8
|
+
export declare function pullDeletedData(table: string, filter?: RealtimeFilter): Promise<{
|
|
9
|
+
deletedDataMap: Map<string, PayloadData>;
|
|
10
|
+
records: PayloadData[];
|
|
11
|
+
} | null>;
|
|
12
|
+
//# sourceMappingURL=pullDeletedData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pullDeletedData.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/pullDeletedData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAwBnE;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC;IACT,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzC,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,GAAG,IAAI,CAAC,CAqER"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import log from "../../logs";
|
|
3
|
+
import { supabaseClientErr } from "../../supabaseClientErr";
|
|
4
|
+
import { getLastDeletedInfo, updateLastDeletedInfo, } from "./getLastDeletedInfo";
|
|
5
|
+
const validOperators = new Set([
|
|
6
|
+
"eq",
|
|
7
|
+
"neq",
|
|
8
|
+
"gt",
|
|
9
|
+
"lt",
|
|
10
|
+
"gte",
|
|
11
|
+
"lte",
|
|
12
|
+
"like",
|
|
13
|
+
"ilike",
|
|
14
|
+
"is",
|
|
15
|
+
"in",
|
|
16
|
+
]);
|
|
17
|
+
let timesPushed = 0;
|
|
18
|
+
let lastPushed = 0;
|
|
19
|
+
/**
|
|
20
|
+
* Pulls deleted data from the remote database for a given table
|
|
21
|
+
* @param table - The table to pull deleted data from
|
|
22
|
+
* @returns The deleted data from the table as a map of id to record and the reordered data
|
|
23
|
+
*/
|
|
24
|
+
export async function pullDeletedData(table, filter) {
|
|
25
|
+
const lastDeletedAt = await getLastDeletedInfo(table);
|
|
26
|
+
const supabase = getSupastashConfig().supabaseClient;
|
|
27
|
+
if (!supabase)
|
|
28
|
+
throw new Error(`No supabase client found: ${supabaseClientErr}`);
|
|
29
|
+
let filteredQuery = supabase
|
|
30
|
+
.from(table)
|
|
31
|
+
.select("*")
|
|
32
|
+
.gt("deleted_at", lastDeletedAt)
|
|
33
|
+
.order("deleted_at", { ascending: false, nullsFirst: false });
|
|
34
|
+
if (filter &&
|
|
35
|
+
(!filter.operator ||
|
|
36
|
+
!validOperators.has(filter.operator) ||
|
|
37
|
+
!filter.column ||
|
|
38
|
+
!filter.value)) {
|
|
39
|
+
throw new Error(`Invalid filter: ${JSON.stringify(filter)} for table ${table}`);
|
|
40
|
+
}
|
|
41
|
+
if (filter?.operator &&
|
|
42
|
+
validOperators.has(filter.operator) &&
|
|
43
|
+
filter.column &&
|
|
44
|
+
filter.value) {
|
|
45
|
+
filteredQuery = filteredQuery[filter.operator](filter.column, filter.value);
|
|
46
|
+
}
|
|
47
|
+
// Fetch records deleted after the last sync
|
|
48
|
+
const { data, error } = await filteredQuery;
|
|
49
|
+
if (error) {
|
|
50
|
+
log(`[Supastash] Error fetching from ${table}:`, error.message);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!data || data.length === 0) {
|
|
54
|
+
timesPushed++;
|
|
55
|
+
if (timesPushed >= 30) {
|
|
56
|
+
const timeSinceLastPush = Date.now() - lastPushed;
|
|
57
|
+
lastPushed = Date.now();
|
|
58
|
+
log(`[Supastash] No deleted records for ${table} from ${lastDeletedAt} (times pushed: ${timesPushed}) in the last ${timeSinceLastPush}ms`);
|
|
59
|
+
timesPushed = 0;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
log(`Received ${data.length} deleted records for ${table}`);
|
|
64
|
+
// Update the supastash_deleted_status table with the lastest timestamp
|
|
65
|
+
const lastest = data.find((r) => r.deleted_at)?.deleted_at;
|
|
66
|
+
await updateLastDeletedInfo(table, lastest);
|
|
67
|
+
const deletedDataMap = new Map(data.map((d) => [d.id, d]));
|
|
68
|
+
return { deletedDataMap, records: data };
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stringifyFields.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/stringifyFields.ts"],"names":[],"mappings":"AAAA,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,GAAG,OAUjD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RealtimeFilter } from "../../../types/realtimeData.types";
|
|
2
|
+
/**
|
|
3
|
+
* Updates the local database with the remote changes
|
|
4
|
+
* @param table - The table to update
|
|
5
|
+
*/
|
|
6
|
+
export declare function updateLocalDb(table: string, filters?: RealtimeFilter, onReceiveData?: (payload: any) => Promise<void>): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Upserts a record into the local database
|
|
9
|
+
* @param table - The table to upsert the record into
|
|
10
|
+
* @param record - The record to upsert
|
|
11
|
+
* @param exists - Whether the record already exists in the database
|
|
12
|
+
*/
|
|
13
|
+
export declare function upsertData(table: string, record: any, doesExist?: boolean): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=updateLocalDb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateLocalDb.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/updateLocalDb.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAanE;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,EACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,iBAiDhD;AAID;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,GAAG,EACX,SAAS,CAAC,EAAE,OAAO,iBAkEpB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
3
|
+
import { isOnline } from "../../connection";
|
|
4
|
+
import { supastashEventBus } from "../../events/eventBus";
|
|
5
|
+
import { getTableSchema } from "../../getTableSchema";
|
|
6
|
+
import log from "../../logs";
|
|
7
|
+
import { updateLocalSyncedAt } from "../../syncUpdate";
|
|
8
|
+
import { pullData } from "./pullData";
|
|
9
|
+
import { pullDeletedData } from "./pullDeletedData";
|
|
10
|
+
import { stringifyComplexFields } from "./stringifyFields";
|
|
11
|
+
let isInSync = new Map();
|
|
12
|
+
const DEFAULT_DATE = "1970-01-01T00:00:00Z";
|
|
13
|
+
/**
|
|
14
|
+
* Updates the local database with the remote changes
|
|
15
|
+
* @param table - The table to update
|
|
16
|
+
*/
|
|
17
|
+
export async function updateLocalDb(table, filters, onReceiveData) {
|
|
18
|
+
if (isInSync.get(table))
|
|
19
|
+
return;
|
|
20
|
+
isInSync.set(table, true);
|
|
21
|
+
try {
|
|
22
|
+
if (!(await isOnline()))
|
|
23
|
+
return;
|
|
24
|
+
const db = await getSupastashDb();
|
|
25
|
+
const deletedData = await pullDeletedData(table, filters);
|
|
26
|
+
const data = await pullData(table, filters);
|
|
27
|
+
const dataToUpdate = data?.filter((d) => !deletedData?.deletedDataMap.has(d.id));
|
|
28
|
+
const changes = !!deletedData || !!dataToUpdate;
|
|
29
|
+
// Delete records that are no longer in the remote data
|
|
30
|
+
if (deletedData) {
|
|
31
|
+
for (const record of deletedData.records) {
|
|
32
|
+
await db.runAsync(`DELETE FROM ${table} WHERE id = ?`, [record.id]);
|
|
33
|
+
}
|
|
34
|
+
supastashEventBus.emit(`push:${table}`, deletedData.records, "delete");
|
|
35
|
+
}
|
|
36
|
+
// Update local database with remote changes
|
|
37
|
+
if (dataToUpdate) {
|
|
38
|
+
for (const record of dataToUpdate) {
|
|
39
|
+
const { doesExist, newer } = await checkIfRecordExistsAndIsNewer(table, record);
|
|
40
|
+
if (newer) {
|
|
41
|
+
if (onReceiveData) {
|
|
42
|
+
await onReceiveData(record);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await upsertData(table, record, doesExist);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (changes)
|
|
51
|
+
supastashEventBus.emit(`push:${table}`, dataToUpdate, "update");
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(`[Supastash] Error updating local db for ${table}`, error);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
isInSync.delete(table);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const warned = new Map();
|
|
61
|
+
/**
|
|
62
|
+
* Upserts a record into the local database
|
|
63
|
+
* @param table - The table to upsert the record into
|
|
64
|
+
* @param record - The record to upsert
|
|
65
|
+
* @param exists - Whether the record already exists in the database
|
|
66
|
+
*/
|
|
67
|
+
export async function upsertData(table, record, doesExist) {
|
|
68
|
+
if (!record?.id)
|
|
69
|
+
return;
|
|
70
|
+
let itemExists = !!doesExist;
|
|
71
|
+
if (doesExist === undefined) {
|
|
72
|
+
const { doesExist: exists } = await checkIfRecordExistsAndIsNewer(table, record);
|
|
73
|
+
itemExists = exists;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const db = await getSupastashDb();
|
|
77
|
+
const columns = await getTableSchema(table);
|
|
78
|
+
const recordToSave = {
|
|
79
|
+
...stringifyComplexFields(record),
|
|
80
|
+
synced_at: new Date().toISOString(),
|
|
81
|
+
};
|
|
82
|
+
if (__DEV__ && getSupastashConfig().debugMode) {
|
|
83
|
+
const unknownKeys = Object.keys(record).filter((key) => !columns.includes(key));
|
|
84
|
+
if (unknownKeys.length > 0 && !warned.get(table)) {
|
|
85
|
+
warned.set(table, true);
|
|
86
|
+
console.warn(`⚠️ [Supastash] ${table} record contains keys not in local schema: ${unknownKeys.join(", ")}. Data will still be stored`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Prep for upsert
|
|
90
|
+
const keys = columns;
|
|
91
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
92
|
+
const updateParts = keys
|
|
93
|
+
.filter((key) => key !== "id")
|
|
94
|
+
.map((key) => `${key} = ?`);
|
|
95
|
+
const updatePlaceholders = updateParts.join(", ");
|
|
96
|
+
const values = keys.map((key) => recordToSave[key]);
|
|
97
|
+
const updateValues = keys
|
|
98
|
+
.filter((key) => key !== "id")
|
|
99
|
+
.map((key) => recordToSave[key]);
|
|
100
|
+
if (itemExists) {
|
|
101
|
+
// Update existing record
|
|
102
|
+
await db.runAsync(`UPDATE ${table} SET ${updatePlaceholders} WHERE id = ?`, [...updateValues, record.id]);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Insert new record
|
|
106
|
+
await db.runAsync(`INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders})`, values);
|
|
107
|
+
}
|
|
108
|
+
await updateLocalSyncedAt(table, record.id);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error(`[Supastash] Error upserting data for ${table}`, error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function checkIfRecordExistsAndIsNewer(table, item) {
|
|
115
|
+
if (!item?.id)
|
|
116
|
+
return { doesExist: false, newer: false };
|
|
117
|
+
const db = await getSupastashDb();
|
|
118
|
+
const record = await db.getFirstAsync(`SELECT * FROM ${table} WHERE id = ?`, [
|
|
119
|
+
item.id,
|
|
120
|
+
]);
|
|
121
|
+
if (record &&
|
|
122
|
+
new Date(record.updated_at || DEFAULT_DATE) >=
|
|
123
|
+
new Date(item.updated_at || DEFAULT_DATE)) {
|
|
124
|
+
log(`Skipping ${table}:${record.id} - local is newer`);
|
|
125
|
+
return { doesExist: true, newer: false };
|
|
126
|
+
}
|
|
127
|
+
return { doesExist: !!record, newer: true };
|
|
128
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PayloadData } from "../../../types/query.types";
|
|
2
|
+
/**
|
|
3
|
+
* Deletes a chunk of data from the remote database
|
|
4
|
+
* @param table - The table to delete from
|
|
5
|
+
* @param unsyncedRecords - The unsynced records to delete
|
|
6
|
+
*/
|
|
7
|
+
export declare function deleteData(table: string, unsyncedRecords: PayloadData[]): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=deleteChunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deleteChunks.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pushLocal/deleteChunks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAqDzD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,WAAW,EAAE,iBAU/B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
3
|
+
import log from "../../logs";
|
|
4
|
+
import { parseStringifiedFields } from "./parseFields";
|
|
5
|
+
const CHUNK_SIZE = 500;
|
|
6
|
+
/**
|
|
7
|
+
* Permanently deletes a chunk of data from the local database
|
|
8
|
+
* @param table - The table to delete from
|
|
9
|
+
* @param chunk - The chunk of data to delete
|
|
10
|
+
*/
|
|
11
|
+
async function permanentlyDeleteChunkLocally(table, chunk) {
|
|
12
|
+
const db = await getSupastashDb();
|
|
13
|
+
for (const row of chunk) {
|
|
14
|
+
await db.runAsync(`DELETE FROM ${table} WHERE id = ${row.id}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Deletes a chunk of data from the remote database
|
|
19
|
+
* @param table - The table to delete from
|
|
20
|
+
* @param chunk - The chunk of data to delete
|
|
21
|
+
*/
|
|
22
|
+
async function deleteChunk(table, chunk) {
|
|
23
|
+
const config = getSupastashConfig();
|
|
24
|
+
const supabase = config.supabaseClient;
|
|
25
|
+
if (!supabase) {
|
|
26
|
+
throw new Error("No supabase client found");
|
|
27
|
+
}
|
|
28
|
+
let attempts = 0;
|
|
29
|
+
while (attempts < 3) {
|
|
30
|
+
const { error } = await supabase.from(table).upsert(chunk);
|
|
31
|
+
if (!error) {
|
|
32
|
+
await permanentlyDeleteChunkLocally(table, chunk);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
log(`Delete attempt ${attempts + 1} failed for a delete operation on table ${table}`, error);
|
|
36
|
+
await new Promise((res) => setTimeout(res, 1000 * Math.pow(2, attempts)));
|
|
37
|
+
attempts++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Deletes a chunk of data from the remote database
|
|
42
|
+
* @param table - The table to delete from
|
|
43
|
+
* @param unsyncedRecords - The unsynced records to delete
|
|
44
|
+
*/
|
|
45
|
+
export async function deleteData(table, unsyncedRecords) {
|
|
46
|
+
const cleanRecords = unsyncedRecords.map(({ synced_at, deleted_at, ...rest }) => parseStringifiedFields(rest));
|
|
47
|
+
for (let i = 0; i < cleanRecords.length; i += CHUNK_SIZE) {
|
|
48
|
+
const chunk = cleanRecords.slice(i, i + CHUNK_SIZE);
|
|
49
|
+
await deleteChunk(table, chunk);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PayloadData } from "../../../types/query.types";
|
|
2
|
+
/**
|
|
3
|
+
* Gets all unsynced data from a table
|
|
4
|
+
* @param table - The table to get the data from
|
|
5
|
+
* @returns The unsynced data
|
|
6
|
+
*/
|
|
7
|
+
export declare function getAllUnsyncedData(table: string): Promise<PayloadData[] | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Gets all deleted data from a table
|
|
10
|
+
* @param table - The table to get the data from
|
|
11
|
+
* @returns The deleted data
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAllDeletedData(table: string): Promise<PayloadData[] | null>;
|
|
14
|
+
//# sourceMappingURL=getAllUnsyncedData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAllUnsyncedData.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pushLocal/getAllUnsyncedData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AA+DzD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAe/B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAM/B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
3
|
+
import { getTableSchema } from "../../../utils/getTableSchema";
|
|
4
|
+
import log from "../../../utils/logs";
|
|
5
|
+
import { supabaseClientErr } from "../../supabaseClientErr";
|
|
6
|
+
const numberOfErrors = new Map();
|
|
7
|
+
const sharedKeysCache = new Map();
|
|
8
|
+
async function getRemoteKeys(table) {
|
|
9
|
+
const config = getSupastashConfig();
|
|
10
|
+
const supabase = config?.supabaseClient;
|
|
11
|
+
if (!supabase) {
|
|
12
|
+
throw new Error(`Supabase client not found, ${supabaseClientErr}`);
|
|
13
|
+
}
|
|
14
|
+
if (sharedKeysCache.has(table)) {
|
|
15
|
+
return sharedKeysCache.get(table);
|
|
16
|
+
}
|
|
17
|
+
if (numberOfErrors.get(table) && (numberOfErrors.get(table) || 0) > 3) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const { data, error } = await supabase.rpc("get_column_names", {
|
|
21
|
+
table_name: table,
|
|
22
|
+
});
|
|
23
|
+
if (error) {
|
|
24
|
+
log(`[Supastash] Error getting remote keys for table ${table} on public schema: ${error.message}`);
|
|
25
|
+
numberOfErrors.set(table, (numberOfErrors.get(table) || 0) + 1);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const keys = data?.map((item) => item.column_name);
|
|
29
|
+
const columns = await getTableSchema(table);
|
|
30
|
+
const sharedKeys = keys?.filter((key) => columns.includes(key));
|
|
31
|
+
const missingKeys = columns.filter((column) => !keys?.includes(column) && column !== "synced_at");
|
|
32
|
+
// Inform user of missing keys
|
|
33
|
+
if (missingKeys.length > 0) {
|
|
34
|
+
log(`[Supastash] Missing keys for table ${table} on public schema: ${missingKeys.join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
// Return shared keys if they exist
|
|
37
|
+
if (sharedKeys) {
|
|
38
|
+
sharedKeysCache.set(table, sharedKeys);
|
|
39
|
+
return sharedKeys;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Gets all unsynced data from a table
|
|
45
|
+
* @param table - The table to get the data from
|
|
46
|
+
* @returns The unsynced data
|
|
47
|
+
*/
|
|
48
|
+
export async function getAllUnsyncedData(table) {
|
|
49
|
+
const db = await getSupastashDb();
|
|
50
|
+
const remoteKeys = await getRemoteKeys(table);
|
|
51
|
+
if (!remoteKeys) {
|
|
52
|
+
const query = `SELECT * FROM ${table} WHERE synced_at IS NULL AND deleted_at IS NULL`;
|
|
53
|
+
const data = await db.getAllAsync(query);
|
|
54
|
+
return data ?? null;
|
|
55
|
+
}
|
|
56
|
+
const columns = remoteKeys.join(", ");
|
|
57
|
+
const query = `SELECT ${columns} FROM ${table} WHERE synced_at IS NULL AND deleted_at IS NULL`;
|
|
58
|
+
const data = await db.getAllAsync(query);
|
|
59
|
+
return data ?? null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gets all deleted data from a table
|
|
63
|
+
* @param table - The table to get the data from
|
|
64
|
+
* @returns The deleted data
|
|
65
|
+
*/
|
|
66
|
+
export async function getAllDeletedData(table) {
|
|
67
|
+
const db = await getSupastashDb();
|
|
68
|
+
const data = await db.getAllAsync(`SELECT deleted_at, id FROM ${table} WHERE deleted_at IS NOT NULL`);
|
|
69
|
+
return data ?? null;
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseFields.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pushLocal/parseFields.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,GAAG,OAgBjD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses stringified fields in a record
|
|
3
|
+
* @param record - The record to parse
|
|
4
|
+
* @returns The parsed record
|
|
5
|
+
*/
|
|
6
|
+
export function parseStringifiedFields(record) {
|
|
7
|
+
const parsed = {};
|
|
8
|
+
for (const key in record) {
|
|
9
|
+
const value = record[key];
|
|
10
|
+
if (typeof value === "string") {
|
|
11
|
+
try {
|
|
12
|
+
const maybeParsed = JSON.parse(value);
|
|
13
|
+
parsed[key] = maybeParsed;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
parsed[key] = value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
parsed[key] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sends unsynced data to the remote database for a given table
|
|
3
|
+
* @param table - The table to send the data to
|
|
4
|
+
*/
|
|
5
|
+
export declare function pushLocalDataToRemote(table: string, onPushToRemote?: (payload: any[]) => Promise<boolean>, noSync?: string[]): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=sendUnsyncedToSupabase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sendUnsyncedToSupabase.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pushLocal/sendUnsyncedToSupabase.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,EACrD,MAAM,CAAC,EAAE,MAAM,EAAE,iBAsClB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isOnline } from "../../connection";
|
|
2
|
+
import { supastashEventBus } from "../../events/eventBus";
|
|
3
|
+
import { deleteData } from "./deleteChunks";
|
|
4
|
+
import { getAllDeletedData, getAllUnsyncedData } from "./getAllUnsyncedData";
|
|
5
|
+
import { uploadData } from "./uploadChunk";
|
|
6
|
+
let isInSync = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Sends unsynced data to the remote database for a given table
|
|
9
|
+
* @param table - The table to send the data to
|
|
10
|
+
*/
|
|
11
|
+
export async function pushLocalDataToRemote(table, onPushToRemote, noSync) {
|
|
12
|
+
if (isInSync.get(table))
|
|
13
|
+
return;
|
|
14
|
+
isInSync.set(table, true);
|
|
15
|
+
try {
|
|
16
|
+
if (!(await isOnline()))
|
|
17
|
+
return;
|
|
18
|
+
const data = await getAllUnsyncedData(table);
|
|
19
|
+
const deletedData = await getAllDeletedData(table);
|
|
20
|
+
if ((!data || data.length === 0) &&
|
|
21
|
+
(!deletedData || deletedData.length === 0)) {
|
|
22
|
+
noSync?.push(table);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (data && data.length > 0) {
|
|
26
|
+
await uploadData(table, data, onPushToRemote);
|
|
27
|
+
supastashEventBus.emit(`push:${table}`, data, "insert");
|
|
28
|
+
}
|
|
29
|
+
const payloadForDeletedData = deletedData?.map((item) => ({
|
|
30
|
+
id: item.id,
|
|
31
|
+
deleted_at: item.deleted_at,
|
|
32
|
+
}));
|
|
33
|
+
if (payloadForDeletedData && payloadForDeletedData.length > 0) {
|
|
34
|
+
await deleteData(table, payloadForDeletedData);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`[Supastash] Error pushing local data to remote for ${table}`, error);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
isInSync.delete(table);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PayloadData } from "../../../types/query.types";
|
|
2
|
+
/**
|
|
3
|
+
* Uploads a chunk of data to the remote database
|
|
4
|
+
* @param table - The table to upload to
|
|
5
|
+
* @param unsyncedRecords - The unsynced records to upload
|
|
6
|
+
*/
|
|
7
|
+
export declare function uploadData(table: string, unsyncedRecords: PayloadData[], onPushToRemote?: (payload: any[]) => Promise<boolean>): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=uploadChunk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadChunk.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pushLocal/uploadChunk.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AA0IzD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,WAAW,EAAE,EAC9B,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,iBAUtD"}
|