Skip to content

Commit 20bb3a3

Browse files
author
Amine
committed
refactor: demos now use attachments functionality from the core libraries
1 parent de9130e commit 20bb3a3

File tree

14 files changed

+3223
-3325
lines changed

14 files changed

+3223
-3325
lines changed

demos/react-native-supabase-todolist/app/views/todos/edit/[id].tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { ATTACHMENT_TABLE, attachmentFromSql, AttachmentRecord } from '@powersync/attachments';
2-
import { usePowerSync, useQuery } from '@powersync/react-native';
1+
import { usePowerSync, useQuery, ATTACHMENT_TABLE, attachmentFromSql, AttachmentRecord } from '@powersync/react-native';
32
import { CameraCapturedPicture } from 'expo-camera';
43
import _ from 'lodash';
54
import * as React from 'react';

demos/react-native-supabase-todolist/library/powersync/AppSchema.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { AttachmentTable } from '@powersync/attachments';
2-
import { column, Schema, Table } from '@powersync/react-native';
1+
import { column, Schema, Table, AttachmentTable } from '@powersync/react-native';
32

43
export const LIST_TABLE = 'lists';
54
export const TODO_TABLE = 'todos';
@@ -27,9 +26,7 @@ const lists = new Table({
2726
export const AppSchema = new Schema({
2827
todos,
2928
lists,
30-
attachments: new AttachmentTable({
31-
viewName: 'attachments',
32-
}),
29+
attachments: new AttachmentTable(),
3330
});
3431

3532
export type Database = (typeof AppSchema)['types'];

demos/react-native-supabase-todolist/library/powersync/system.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import '@azure/core-asynciterator-polyfill';
22

3-
import { createBaseLogger, LogLevel, PowerSyncDatabase, SyncClientImplementation } from '@powersync/react-native';
4-
import React from 'react';
5-
6-
import {
3+
import { createBaseLogger, LogLevel, PowerSyncDatabase, SyncClientImplementation,
74
AttachmentQueue,
85
type AttachmentRecord,
96
ExpoFileSystemAdapter,
10-
type WatchedAttachmentItem
11-
} from '@powersync/attachments';
7+
type WatchedAttachmentItem } from '@powersync/react-native';
8+
import React from 'react';
129
import { configureFts } from '../fts/fts_setup';
1310
import { KVStorage } from '../storage/KVStorage';
1411
import { SupabaseRemoteStorageAdapter } from '../storage/SupabaseRemoteStorageAdapter';
@@ -95,7 +92,8 @@ export class System {
9592
onDeleteError: async (attachment: AttachmentRecord, error: Error) => {
9693
return true; // Retry deletes by default
9794
}
98-
}
95+
},
96+
logger,
9997
});
10098
}
10199
}

demos/react-native-supabase-todolist/library/storage/SupabaseRemoteStorageAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SupabaseClient } from '@supabase/supabase-js';
2-
import { AttachmentRecord, RemoteStorageAdapter } from '@powersync/attachments';
2+
import { AttachmentRecord, RemoteStorageAdapter } from '@powersync/react-native';
33

44
export interface SupabaseRemoteStorageAdapterOptions {
55
client: SupabaseClient;

demos/react-native-supabase-todolist/library/widgets/TodoItemWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ActivityIndicator, Alert, View, Modal, StyleSheet, Text } from 'react-n
44
import { ListItem, Button, Icon, Image } from '@rneui/themed';
55
import { CameraWidget } from './CameraWidget';
66
import { TodoRecord } from '../powersync/AppSchema';
7-
import { AttachmentRecord } from '@powersync/attachments';
7+
import { AttachmentRecord } from '@powersync/react-native';
88
import { AppConfig } from '../supabase/AppConfig';
99
import { SafeAreaProvider } from 'react-native-safe-area-context';
1010

demos/react-native-web-supabase-todolist/app/views/todos/edit/[id].tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ATTACHMENT_TABLE, AttachmentRecord } from '@powersync/attachments';
1+
import { ATTACHMENT_TABLE, AttachmentRecord } from '@powersync/react-native';
22
import { usePowerSync, useQuery } from '@powersync/react';
33
import { CameraCapturedPicture } from 'expo-camera';
44
import _ from 'lodash';
@@ -78,9 +78,16 @@ const TodoView: React.FC = () => {
7878

7979
const savePhoto = async (id: string, data: CameraCapturedPicture) => {
8080
// We are sure the base64 is not null, as we are using the base64 option in the CameraWidget
81-
const { id: photoId } = await system.attachmentQueue.savePhoto(data.base64!);
82-
83-
await system.powersync.execute(`UPDATE ${TODO_TABLE} SET photo_id = ? WHERE id = ?`, [photoId, id]);
81+
if (system.photoAttachmentQueue) {
82+
// We are sure the base64 is not null, as we are using the base64 option in the CameraWidget
83+
const { id: photoId } = await system.photoAttachmentQueue.saveFile({
84+
data: data.base64!,
85+
fileExtension: 'jpg',
86+
mediaType: 'image/jpeg'
87+
});
88+
89+
await system.powersync.execute(`UPDATE ${TODO_TABLE} SET photo_id = ? WHERE id = ?`, [photoId, id]);
90+
}
8491
};
8592

8693
const createNewTodo = async (description: string) => {

demos/react-native-web-supabase-todolist/library/powersync/AppSchema.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { AttachmentTable } from '@powersync/attachments';
2-
import { column, Schema, Table } from '@powersync/common';
1+
import { column, Schema, Table, AttachmentTable } from '@powersync/react-native';
32

43
export const LIST_TABLE = 'lists';
54
export const TODO_TABLE = 'todos';
@@ -27,9 +26,7 @@ const lists = new Table({
2726
export const AppSchema = new Schema({
2827
todos,
2928
lists,
30-
attachments: new AttachmentTable({
31-
name: 'attachments'
32-
})
29+
attachments: new AttachmentTable()
3330
});
3431

3532
export type Database = (typeof AppSchema)['types'];

demos/react-native-web-supabase-todolist/library/powersync/PhotoAttachmentQueue.ts

Lines changed: 0 additions & 50 deletions
This file was deleted.

demos/react-native-web-supabase-todolist/library/powersync/system.ts

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
11
import '@azure/core-asynciterator-polyfill';
22

33
import React from 'react';
4-
import { LogLevel, PowerSyncDatabase as PowerSyncDatabaseNative } from '@powersync/react-native';
5-
import { PowerSyncDatabase as PowerSyncDatabaseWeb, WASQLiteOpenFactory } from '@powersync/web';
6-
import { AbstractPowerSyncDatabase, createBaseLogger } from '@powersync/common';
7-
import { SupabaseStorageAdapter } from '../storage/SupabaseStorageAdapter';
8-
import { type AttachmentRecord } from '@powersync/attachments';
9-
import { KVStorage } from '../storage/KVStorage';
4+
import { AttachmentQueue, LogLevel, PowerSyncDatabase as PowerSyncDatabaseNative, AbstractPowerSyncDatabase, createBaseLogger, ExpoFileSystemAdapter, WatchedAttachmentItem } from '@powersync/react-native';
5+
import { PowerSyncDatabase as PowerSyncDatabaseWeb, WASQLiteOpenFactory, IndexDBFileSystemStorageAdapter } from '@powersync/web';
6+
import { type AttachmentRecord } from '@powersync/common';
7+
import { SupabaseRemoteStorageAdapter } from '../storage/SupabaseRemoteStorageAdapter';
8+
import { ExpoKVStorage, WebKVStorage } from '../storage/KVStorage';
109
import { AppConfig } from '../supabase/AppConfig';
1110
import { SupabaseConnector } from '../supabase/SupabaseConnector';
12-
import { AppSchema } from './AppSchema';
13-
import { PhotoAttachmentQueue } from './PhotoAttachmentQueue';
11+
import { AppSchema, TODO_TABLE } from './AppSchema';
12+
import { Platform } from 'react-native';
1413

1514
const logger = createBaseLogger();
1615
logger.useDefaults();
1716
logger.setLevel(LogLevel.DEBUG);
1817

1918
export class System {
20-
kvStorage: KVStorage;
21-
storage: SupabaseStorageAdapter;
19+
kvStorage: ExpoKVStorage | WebKVStorage;
2220
supabaseConnector: SupabaseConnector;
2321
powersync: AbstractPowerSyncDatabase;
24-
attachmentQueue: PhotoAttachmentQueue | undefined = undefined;
22+
photoAttachmentQueue: AttachmentQueue | undefined = undefined;
2523

2624
constructor() {
27-
this.kvStorage = new KVStorage();
28-
this.supabaseConnector = new SupabaseConnector(this);
29-
this.storage = this.supabaseConnector.storage;
25+
this.kvStorage = Platform.OS === 'web' ? new WebKVStorage() : new ExpoKVStorage();
26+
this.supabaseConnector = new SupabaseConnector({
27+
kvStorage: this.kvStorage,
28+
supabaseUrl: AppConfig.supabaseUrl,
29+
supabaseAnonKey: AppConfig.supabaseAnonKey
30+
});
3031
if (PowerSyncDatabaseNative) {
3132
this.powersync = new PowerSyncDatabaseNative({
3233
schema: AppSchema,
3334
database: {
3435
dbFilename: 'sqlite.db'
35-
}
36+
},
37+
logger,
3638
});
3739
} else {
3840
const factory = new WASQLiteOpenFactory({
@@ -69,23 +71,48 @@ export class System {
6971
// name: `shared-sync-${options?.dbFilename}`
7072
// });
7173
// }
72-
}
74+
},
75+
logger,
7376
});
7477
}
7578

7679
if (AppConfig.supabaseBucket) {
77-
this.attachmentQueue = new PhotoAttachmentQueue({
78-
powersync: this.powersync,
79-
storage: this.storage,
80-
// Use this to handle download errors where you can use the attachment
81-
// and/or the exception to decide if you want to retry the download
82-
onDownloadError: async (attachment: AttachmentRecord, exception: any) => {
83-
if (exception.toString() === 'StorageApiError: Object not found') {
84-
return { retry: false };
80+
const isWeb = Platform.OS === 'web';
81+
const localStorage = isWeb ? new IndexDBFileSystemStorageAdapter() : new ExpoFileSystemAdapter();
82+
const remoteStorage = new SupabaseRemoteStorageAdapter({
83+
client: this.supabaseConnector.client,
84+
bucket: AppConfig.supabaseBucket
85+
});
86+
this.photoAttachmentQueue = new AttachmentQueue({
87+
db: this.powersync,
88+
localStorage,
89+
remoteStorage,
90+
watchAttachments: (onUpdate) => {
91+
this.powersync.watch(`SELECT photo_id as id FROM ${TODO_TABLE} WHERE photo_id IS NOT NULL`, [], {
92+
onResult: (result) => {
93+
const attachments: WatchedAttachmentItem[] = (result.rows?._array ?? []).map((row: any) => ({
94+
id: row.id,
95+
fileExtension: 'jpg'
96+
}));
97+
onUpdate(attachments);
98+
}
99+
});
100+
},
101+
errorHandler: {
102+
onDownloadError: async (attachment: AttachmentRecord, error: Error) => {
103+
if (error.toString() === 'StorageApiError: Object not found') {
104+
return false; // Don't retry
105+
}
106+
return true; // Retry
107+
},
108+
onUploadError: async (attachment: AttachmentRecord, error: Error) => {
109+
return true; // Retry uploads by default
110+
},
111+
onDeleteError: async (attachment: AttachmentRecord, error: Error) => {
112+
return true; // Retry deletes by default
85113
}
86-
87-
return { retry: true };
88-
}
114+
},
115+
logger,
89116
});
90117
}
91118
}
@@ -94,8 +121,8 @@ export class System {
94121
await this.powersync.init();
95122
await this.powersync.connect(this.supabaseConnector);
96123

97-
if (this.attachmentQueue) {
98-
await this.attachmentQueue.init();
124+
if (this.photoAttachmentQueue) {
125+
await this.photoAttachmentQueue.startSync();
99126
}
100127
}
101128
}

demos/react-native-web-supabase-todolist/library/storage/KVStorage.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import * as ExpoStorage from 'expo-secure-store';
22
import AsyncStorage from '@react-native-async-storage/async-storage';
3-
import { Platform } from 'react-native';
43

5-
class ExpoKVStorage {
4+
export class ExpoKVStorage {
65
async getItem(key: string): Promise<string | null> {
76
try {
87
const session = await ExpoStorage.getItemAsync(key);
@@ -22,7 +21,7 @@ class ExpoKVStorage {
2221
}
2322
}
2423

25-
class WebKVStorage {
24+
export class WebKVStorage {
2625
async getItem(key: string): Promise<string | null> {
2726
try {
2827
const value = await AsyncStorage.getItem(key);
@@ -41,6 +40,3 @@ class WebKVStorage {
4140
await AsyncStorage.removeItem(key);
4241
}
4342
}
44-
45-
const isWeb = Platform.OS === 'web';
46-
export const KVStorage = isWeb ? WebKVStorage : ExpoKVStorage;

0 commit comments

Comments
 (0)