Skip to content

Commit 44cc2e6

Browse files
Improvements to the code examples (#143)
* Improvements to the code examples * Feedback from Hein
1 parent 65e9683 commit 44cc2e6

File tree

2 files changed

+142
-97
lines changed

2 files changed

+142
-97
lines changed

client-sdk-references/react-native-and-expo.mdx

Lines changed: 124 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ The types available are `text`, `integer` and `real`. These should map directly
7575

7676
**Example**:
7777

78-
```js
79-
// AppSchema.ts
78+
<Info>
79+
**Note**: No need to declare a primary key `id` column - as PowerSync will automatically create this.
80+
</Info>
81+
82+
```typescript powersync/AppSchema.ts
8083
import { column, Schema, Table } from '@powersync/react-native';
8184

8285
const lists = new Table({
@@ -111,10 +114,6 @@ export type TodoRecord = Database['todos'];
111114
export type ListRecord = Database['lists'];
112115
```
113116

114-
<Info>
115-
**Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this.
116-
</Info>
117-
118117
### 2\. Instantiate the PowerSync Database
119118

120119
Next, you need to instantiate the PowerSync database — this is the core managed database.
@@ -123,26 +122,52 @@ Its primary functions are to record all changes in the local database, whether o
123122

124123
**Example**:
125124

126-
```js
127-
import { PowerSyncDatabase } from '@powersync/react-native';
128-
import { Connector } from './Connector';
129-
import { AppSchema } from './Schema';
130-
131-
/**
132-
* Instantiate the local PowerSync database
133-
* This uses react-native-quick-sqlite to open a SQLite database file
134-
*/
135-
export const db = new PowerSyncDatabase({
136-
// The schema you defined in the previous step
137-
schema: AppSchema,
138-
database: {
139-
// Filename for the SQLite database — it's important to only instantiate one instance per file.
140-
dbFilename: 'powersync.db'
141-
// Optional. Directory where the database file is located.'
142-
// dbLocation: 'path/to/directory'
143-
}
144-
});
145-
```
125+
<Tabs>
126+
<Tab title="React Native Quick SQLite">
127+
For getting started and testing PowerSync use the [@journeyapps/react-native-quick-sqlite](https://github.com/powersync-ja/react-native-quick-sqlite) package.
128+
<Note>By default, this SDK requires @journeyapps/react-native-quick-sqlite as a peer dependency.</Note>
129+
130+
```typescript powersync/system.ts
131+
import { PowerSyncDatabase } from '@powersync/react-native';
132+
import { AppSchema } from './Schema';
133+
134+
export const powersync = new PowerSyncDatabase({
135+
// The schema you defined in the previous step
136+
schema: AppSchema,
137+
// For other options see,
138+
// https://powersync-ja.github.io/powersync-js/web-sdk/globals#powersyncopenfactoryoptions
139+
database: {
140+
// Filename for the SQLite database — it's important to only instantiate one instance per file.
141+
// For other database options see,
142+
// https://powersync-ja.github.io/powersync-js/web-sdk/globals#sqlopenoptions
143+
dbFilename: 'powersync.db'
144+
}
145+
});
146+
```
147+
</Tab>
148+
<Tab title="OP-SQLite">
149+
If you want to include encryption with SQLCipher use the [@powersync/op-sqlite](https://www.npmjs.com/package/@powersync/op-sqlite) package.
150+
<Note>If you've already installed `@journeyapps/react-native-quick-sqlite`, You will have to uninstall it and then install both `@powersync/op-sqlite` and it's peer dependency `@op-engineering/op-sqlite` to use this.</Note>
151+
152+
```typescript powersync/system.ts
153+
import { PowerSyncDatabase } from '@powersync/react-native';
154+
import { OPSqliteOpenFactory } from '@powersync/op-sqlite'; // Add this import
155+
import { AppSchema } from './Schema';
156+
157+
// Create the factory
158+
const opSqlite = new OPSqliteOpenFactory({
159+
dbFilename: 'powersync.db'
160+
});
161+
162+
export const powersync = new PowerSyncDatabase({
163+
// For other options see,
164+
schema: AppSchema,
165+
// Override the default database
166+
database: opSqlite
167+
});
168+
```
169+
</Tab>
170+
</Tabs>
146171

147172
<Note>
148173
**SDK versions lower than 1.8.0**
@@ -152,11 +177,13 @@ In SDK versions lower than 1.8.0, you will need to use the deprecated [RNQSPower
152177

153178
Once you've instantiated your PowerSync database, you will need to call the [connect()](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/AbstractPowerSyncDatabase#connect) method to activate it.
154179

155-
```js
180+
```typescript powersync/system.ts
181+
import { Connector } from './Connector';
182+
156183
export const setupPowerSync = async () => {
157184
// Uses the backend connector that will be created in the next section
158185
const connector = new Connector();
159-
db.connect(connector);
186+
powersync.connect(connector);
160187
};
161188
```
162189

@@ -177,46 +204,65 @@ Accordingly, the connector must implement two methods:
177204

178205
**Example**:
179206

180-
```js
181-
// lib/Connector.js
182-
import { UpdateType } from '@powersync/react-native';
183-
184-
/// Postgres Response codes that we cannot recover from by retrying.
185-
const FATAL_RESPONSE_CODES = [
186-
// Class 22 — Data Exception
187-
// Examples include data type mismatch.
188-
new RegExp('^22...$'),
189-
// Class 23 — Integrity Constraint Violation.
190-
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
191-
new RegExp('^23...$'),
192-
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
193-
new RegExp('^42501$')
194-
];
195-
196-
export class Connector {
197-
constructor() {
198-
// Setup a connection to your server for uploads
199-
this.serverConnectionClient = TODO;
200-
}
207+
```typescript powersync/Connector.ts
208+
import { PowerSyncBackendConnector, UpdateType } from "@powersync/react-native"
209+
210+
export class Connector implements PowerSyncBackendConnector {
211+
/**
212+
* Implement fetchCredentials to obtain a JWT from your authentication service.
213+
* See https://docs.powersync.com/installation/authentication-setup
214+
* If you're using Supabase or Firebase, you can re-use the JWT from those clients, see:
215+
* https://docs.powersync.com/installation/authentication-setup/supabase-auth
216+
* https://docs.powersync.com/installation/authentication-setup/firebase-auth
217+
*/
218+
async fetchCredentials() {
219+
return {
220+
// The PowerSync instance URL or self-hosted endpoint
221+
endpoint: 'https://xxxxxx.powersync.journeyapps.com',
222+
/**
223+
* To get started quickly, use a development token, see:
224+
* Authentication Setup https://docs.powersync.com/installation/authentication-setup/development-tokens) to get up and running quickly
225+
*/
226+
token: 'An authentication token'
227+
};
228+
}
201229

202-
async fetchCredentials() {
203-
// Implement fetchCredentials to obtain a JWT from your authentication service.
204-
// See https://docs.powersync.com/installation/authentication-setup
205-
// If you're using Supabase or Firebase, you can re-use the JWT from those clients, see
206-
// - https://docs.powersync.com/installation/authentication-setup/supabase-auth
207-
// - https://docs.powersync.com/installation/authentication-setup/firebase-auth
208-
return {
209-
endpoint: '[Your PowerSync instance URL or self-hosted endpoint]',
210-
// Use a development token (see Authentication Setup https://docs.powersync.com/installation/authentication-setup/development-tokens) to get up and running quickly
211-
token: 'An authentication token'
212-
};
230+
/**
231+
* Implement uploadData to send local changes to your backend service.
232+
* You can omit this method if you only want to sync data from the database to the client
233+
* See example implementation here:https://docs.powersync.com/client-sdk-references/react-native-and-expo#3-integrate-with-your-backend
234+
*/
235+
async uploadData(database: AbstractPowerSyncDatabase) {
236+
237+
/**
238+
* For batched crud transactions, use data.getCrudBatch(n);
239+
* https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/SqliteBucketStorage#getcrudbatch
240+
*/
241+
const transaction = await database.getNextCrudTransaction();
242+
243+
if (!transaction) {
244+
return;
213245
}
214246

215-
async uploadData(database) {
216-
// Implement uploadData to send local changes to your backend service.
217-
// You can omit this method if you only want to sync data from the database to the client
247+
for (const op of transaction.crud) {
248+
// The data that needs to be changed in the remote db
249+
const record = { ...op.opData, id: op.id };
250+
switch (op.op) {
251+
case UpdateType.PUT:
252+
// TODO: Instruct your backend API to CREATE a record
253+
break;
254+
case UpdateType.PATCH:
255+
// TODO: Instruct your backend API to PATCH a record
256+
break;
257+
case UpdateType.DELETE:
258+
//TODO: Instruct your backend API to DELETE a record
259+
break;
260+
}
261+
}
218262

219-
// See example implementation here:https://docs.powersync.com/client-sdk-references/react-native-and-expo#3-integrate-with-your-backend
263+
// Completes the transaction and moves onto the next one
264+
await transaction.complete();
265+
}
220266
}
221267
```
222268

@@ -236,17 +282,17 @@ The most commonly used CRUD functions to interact with your SQLite data are:
236282
The [get](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#get) method executes a read-only (SELECT) query and returns a single result. It throws an exception if no result is found. Use [getOptional](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#getoptional) to return a single optional result (returns `null` if no result is found).
237283

238284

239-
```js
240-
// TodoItemWidget.jsx
285+
```js TodoItemWidget.jsx
241286
import { Text } from 'react-native';
287+
import { powersync } from "../powersync/system";
242288

243289
export const TodoItemWidget = ({id}) => {
244290
const [todoItem, setTodoItem] = React.useState([]);
245291
const [error, setError] = React.useState([]);
246292

247293
React.useEffect(() => {
248294
// .get returns the first item of the result. Throws an exception if no result is found.
249-
PowerSync.get('SELECT * from todos WHERE id = ?', [id])
295+
powersync.get('SELECT * from todos WHERE id = ?', [id])
250296
.then(setTodoItem)
251297
.catch(ex => setError(ex.message))
252298
}, []);
@@ -259,15 +305,15 @@ export const TodoItemWidget = ({id}) => {
259305

260306
The [getAll](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#getall) method returns a set of rows from a table.
261307

262-
```js
263-
// ListsWidget.jsx
308+
```js ListsWidget.jsx
264309
import { FlatList, Text} from 'react-native';
310+
import { powersync } from "../powersync/system";
265311

266312
export const ListsWidget = () => {
267313
const [lists, setLists] = React.useState([]);
268314

269315
React.useEffect(() => {
270-
PowerSync.getAll('SELECT * from lists').then(setLists)
316+
powersync.getAll('SELECT * from lists').then(setLists)
271317
}, []);
272318

273319
return (<FlatList
@@ -281,9 +327,9 @@ export const ListsWidget = () => {
281327

282328
The [watch](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#watch) method executes a read query whenever a change to a dependent table is made. It can be used with an `AsyncGenerator`, or with a callback.
283329

284-
```js
285-
// ListsWidget.jsx
330+
```js ListsWidget.jsx
286331
import { FlatList, Text } from 'react-native';
332+
import { powersync } from "../powersync/system";
287333

288334
export const ListsWidget = () => {
289335
const [lists, setLists] = React.useState([]);
@@ -293,13 +339,13 @@ export const ListsWidget = () => {
293339

294340
// Option 1: Use with AsyncGenerator
295341
(async () => {
296-
for await(const update of PowerSync.watch('SELECT * from lists', [], {signal: abortController.signal})) {
342+
for await(const update of powersync.watch('SELECT * from lists', [], {signal: abortController.signal})) {
297343
setLists(update)
298344
}
299345
})();
300346

301347
// Option 2: Use a callback (available since version 1.3.3 of the SDK)
302-
PowerSync.watch('SELECT * from lists', [], { onResult: (result) => setLists(result) }, { signal: abortController.signal });
348+
powersync.watch('SELECT * from lists', [], { onResult: (result) => setLists(result) }, { signal: abortController.signal });
303349

304350
return () => {
305351
abortController.abort();
@@ -317,10 +363,9 @@ export const ListsWidget = () => {
317363

318364
The [execute](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#execute) method can be used for executing single SQLite write statements.
319365

320-
```js
321-
322-
// ListsWidget.jsx
366+
```js ListsWidget.jsx
323367
import { Alert, Button, FlatList, Text, View } from 'react-native';
368+
import { powersync } from "../powersync/system";
324369

325370
export const ListsWidget = () => {
326371
// Populate lists with one of methods listed above
@@ -336,7 +381,7 @@ export const ListsWidget = () => {
336381
title="Delete"
337382
onPress={async () => {
338383
try {
339-
await PowerSync.execute(`DELETE FROM lists WHERE id = ?`, [item.id])
384+
await powersync.execute(`DELETE FROM lists WHERE id = ?`, [item.id])
340385
// Watched queries should automatically reload after mutation
341386
} catch (ex) {
342387
Alert('Error', ex.message)
@@ -350,7 +395,7 @@ export const ListsWidget = () => {
350395
color="#841584"
351396
onPress={async () => {
352397
try {
353-
await PowerSync.execute('INSERT INTO lists (id, created_at, name, owner_id) VALUES (uuid(), datetime(), ?, ?) RETURNING *', [
398+
await powersync.execute('INSERT INTO lists (id, created_at, name, owner_id) VALUES (uuid(), datetime(), ?, ?) RETURNING *', [
354399
'A list name',
355400
"[The user's uuid]"
356401
])

migration-guides/mongodb-atlas.mdx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -190,20 +190,20 @@ Here is an example of a client-side schema for PowerSync using a simple `todos`
190190
val AppSchema: Schema = Schema(
191191
listOf(
192192
Table(
193-
name = "todos",
194-
columns = listOf(
195-
Column.text('list_id'),
196-
Column.text('created_at'),
197-
Column.text('completed_at'),
198-
Column.text('description'),
199-
Column.integer('completed'),
200-
Column.text('created_by'),
201-
Column.text('completed_by')
202-
),
203-
// Index to allow efficient lookup within a list
204-
indexes = listOf(
205-
Index("list", listOf(IndexedColumn.descending("list_id")))
206-
)
193+
name = "todos",
194+
columns = listOf(
195+
Column.text('list_id'),
196+
Column.text('created_at'),
197+
Column.text('completed_at'),
198+
Column.text('description'),
199+
Column.integer('completed'),
200+
Column.text('created_by'),
201+
Column.text('completed_by')
202+
),
203+
// Index to allow efficient lookup within a list
204+
indexes = listOf(
205+
Index("list", listOf(IndexedColumn.descending("list_id")))
206+
)
207207
)
208208
)
209209
)
@@ -255,7 +255,7 @@ Here is an example of a client-side schema for PowerSync using a simple `todos`
255255

256256
```typescript .NET (Coming soon)
257257
// Our .NET SDK is currently in a closed alpha release.
258-
258+
259259
```
260260

261261
</CodeGroup>
@@ -384,7 +384,7 @@ Now that we have our Sync Rules and client-side schema defined, we can instantia
384384

385385
```typescript .NET (Coming soon)
386386
// Our .NET SDK is currently in a closed alpha release.
387-
387+
388388
```
389389

390390
</CodeGroup>
@@ -440,7 +440,7 @@ Reading data in the application which uses PowerSync is very simple: we use SQLi
440440

441441
```typescript .NET (Coming soon)
442442
// Our .NET SDK is currently in a closed alpha release.
443-
443+
444444
```
445445

446446
</CodeGroup>
@@ -488,7 +488,7 @@ The same applies to writing data: `INSERT`, `UPDATE` and `DELETE` statements are
488488

489489
```typescript .NET (Coming soon)
490490
// Our .NET SDK is currently in a closed alpha release.
491-
491+
492492
```
493493

494494
</CodeGroup>

0 commit comments

Comments
 (0)