Skip to content

Commit 9115c4e

Browse files
DominicGBauerDominicGBauer
andauthored
fix: add lib folder (#70)
Co-authored-by: DominicGBauer <[email protected]>
1 parent eec4d84 commit 9115c4e

File tree

8 files changed

+690
-0
lines changed

8 files changed

+690
-0
lines changed

demos/react-native-supabase-group-chat/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ web-build/
2121
*.tar.gz
2222
.tamagui
2323
ios/
24+
!lib
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const config = {
2+
brand1: "#a0f",
3+
brand2: "#00d5ff",
4+
supabaseUrl: process.env.EXPO_PUBLIC_SUPABASE_URL as string,
5+
supabaseAnonKey: process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY as string,
6+
powerSyncUrl: process.env.EXPO_PUBLIC_POWERSYNC_URL as string,
7+
};
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import {
2+
AbstractPowerSyncDatabase,
3+
CrudEntry,
4+
PowerSyncBackendConnector,
5+
UpdateType,
6+
} from "@journeyapps/powersync-sdk-react-native";
7+
import type { SupabaseClient } from "@supabase/supabase-js";
8+
9+
import { config } from "./config";
10+
import { supabase } from "./supabase";
11+
12+
/// Postgres Response codes that we cannot recover from by retrying.
13+
const FATAL_RESPONSE_CODES = [
14+
// Class 22 — Data Exception
15+
// Examples include data type mismatch.
16+
new RegExp("^22...$"),
17+
// Class 23 — Integrity Constraint Violation.
18+
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
19+
new RegExp("^23...$"),
20+
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
21+
new RegExp("^42501$"),
22+
];
23+
24+
export class Connector implements PowerSyncBackendConnector {
25+
supabaseClient: SupabaseClient;
26+
27+
constructor() {
28+
this.supabaseClient = supabase;
29+
}
30+
31+
async fetchCredentials() {
32+
const {
33+
data: { session },
34+
error,
35+
} = await this.supabaseClient.auth.getSession();
36+
37+
if (!session || error) {
38+
throw new Error(`Could not fetch Supabase credentials: ${error}`);
39+
}
40+
41+
console.debug("session expires at", session.expires_at);
42+
43+
return {
44+
client: this.supabaseClient,
45+
endpoint: config.powerSyncUrl,
46+
token: session.access_token ?? "",
47+
expiresAt: session.expires_at
48+
? new Date(session.expires_at * 1000)
49+
: undefined,
50+
userID: session.user.id,
51+
};
52+
}
53+
54+
async uploadData(database: AbstractPowerSyncDatabase): Promise<void> {
55+
const transaction = await database.getNextCrudTransaction();
56+
57+
if (!transaction) {
58+
return;
59+
}
60+
61+
let lastOp: CrudEntry | null = null;
62+
try {
63+
// Note: If transactional consistency is important, use database functions
64+
// or edge functions to process the entire transaction in a single call.
65+
for (let op of transaction.crud) {
66+
lastOp = op;
67+
const table = this.supabaseClient.from(op.table);
68+
switch (op.op) {
69+
case UpdateType.PUT:
70+
const record = { ...op.opData, id: op.id };
71+
const { error } = await table.upsert(record);
72+
73+
if (error) {
74+
throw new Error(
75+
`Could not upsert data to Supabase ${JSON.stringify(error)}`,
76+
);
77+
}
78+
break;
79+
case UpdateType.PATCH:
80+
await table.update(op.opData).eq("id", op.id);
81+
break;
82+
case UpdateType.DELETE:
83+
await table.delete().eq("id", op.id);
84+
break;
85+
}
86+
}
87+
88+
await transaction.complete();
89+
} catch (ex: any) {
90+
console.debug(ex);
91+
if (
92+
typeof ex.code == "string" &&
93+
FATAL_RESPONSE_CODES.some((regex) => regex.test(ex.code))
94+
) {
95+
/**
96+
* Instead of blocking the queue with these errors,
97+
* discard the (rest of the) transaction.
98+
*
99+
* Note that these errors typically indicate a bug in the application.
100+
* If protecting against data loss is important, save the failing records
101+
* elsewhere instead of discarding, and/or notify the user.
102+
*/
103+
console.error(`Data upload error - discarding ${lastOp}`, ex);
104+
await transaction.complete();
105+
} else {
106+
// Error may be retryable - e.g. network error or temporary server error.
107+
// Throwing an error here causes this call to be retried after a delay.
108+
throw ex;
109+
}
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)