diff --git a/tutorials/client/sdks/web/next-js.mdx b/client-sdk-references/javascript-web/nextjs.mdx
similarity index 95%
rename from tutorials/client/sdks/web/next-js.mdx
rename to client-sdk-references/javascript-web/nextjs.mdx
index f4018f22..8f24e997 100644
--- a/tutorials/client/sdks/web/next-js.mdx
+++ b/client-sdk-references/javascript-web/nextjs.mdx
@@ -1,13 +1,11 @@
---
-title: "Next.js + PowerSync"
-description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality"
-keywords: ["next.js", "web"]
+title: "Next.js"
+description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality."
---
-## Introduction
-In this tutorial, we’ll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. In the following sections, we’ll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently.
+In this guide, we'll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. We'll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently.
-At present PowerSync will not work with SSR enabled with Next.js and in this guide we disable SSR across the entire app. However, it is possible to have other pages, which do not require authentication for example, to still be rendered server-side. This can be done by only using the DynamicSystemProvider (covered further down in the guide) for specific pages. This means you can still have full SSR on other page which do not require PowerSync.
+At present PowerSync will not work with SSR enabled with Next.js and in this guide we disable SSR across the entire app. However, it is possible to have other pages, which do not require authentication for example, to still be rendered server-side. This can be done by only using the DynamicSystemProvider (covered further down in the guide) for specific pages. This means you can still have full SSR on other pages which do not require PowerSync.
## Setup
@@ -41,7 +39,7 @@ Would you like to customize the import alias (`@/*` by default)? Yes
```
- Do not use Turbopack when setting up a new Next.js project as we’ll be updating the `next.config.ts` to use Webpack. This is done because we need to enable:
+ Do not use Turbopack when setting up a new Next.js project as we'll be updating the `next.config.ts` to use Webpack. This is done because we need to enable:
1. asyncWebAssembly
2. topLevelWait
diff --git a/docs.json b/docs.json
index 176829af..c92e2991 100644
--- a/docs.json
+++ b/docs.json
@@ -195,6 +195,10 @@
"usage/use-case-examples/prioritized-sync",
"usage/use-case-examples/query-json-in-sqlite",
"usage/use-case-examples/raw-tables",
+ "usage/use-case-examples/sequential-id-mapping",
+ "usage/use-case-examples/cascading-deletes",
+ "usage/use-case-examples/aws-s3-storage",
+ "usage/use-case-examples/pdf-attachments",
"usage/use-case-examples/custom-write-checkpoints"
]
},
@@ -222,7 +226,8 @@
"integration-guides/supabase-+-powersync/handling-attachments",
"integration-guides/supabase-+-powersync/realtime-streaming",
"integration-guides/supabase-+-powersync/rls-and-sync-rules",
- "integration-guides/supabase-+-powersync/local-development"
+ "integration-guides/supabase-+-powersync/local-development",
+ "integration-guides/supabase-+-powersync/connector-performance"
]
},
{
@@ -310,6 +315,7 @@
]
},
"client-sdk-references/javascript-web/javascript-spa-frameworks",
+ "client-sdk-references/javascript-web/nextjs",
"client-sdk-references/javascript-web/usage-examples",
"client-sdk-references/javascript-web/encryption",
"client-sdk-references/javascript-web/api-reference"
@@ -400,6 +406,7 @@
]
},
"self-hosting/enterprise",
+ "self-hosting/generate-dev-token",
{
"group": "Appendix",
"pages": [
@@ -411,59 +418,6 @@
}
]
},
- {
- "tab": "Tutorials",
- "groups": [
- {
- "group": " ",
- "pages": [
- "tutorials/overview"
- ]
- },
- {
- "group": "Client",
- "pages": [
- "tutorials/client/overview",
- {
- "group": "Client SDKs",
- "pages": [
- "tutorials/client/sdks/web/next-js"
- ]
- },
- {
- "group": "Attachments / Files",
- "pages": [
- "tutorials/client/attachments-and-files/overview",
- "tutorials/client/attachments-and-files/aws-s3-storage-adapter",
- "tutorials/client/attachments-and-files/pdf-attachment"
- ]
- },
- {
- "group": "Performance",
- "pages": [
- "tutorials/client/performance/overview",
- "tutorials/client/performance/supabase-connector-performance"
- ]
- },
- {
- "group": "Data Management",
- "pages": [
- "tutorials/client/data/overview",
- "tutorials/client/data/cascading-delete",
- "tutorials/client/data/sequential-id-mapping"
- ]
- }
- ]
- },
- {
- "group": "Self-Hosting",
- "pages": [
- "tutorials/self-host/overview",
- "tutorials/self-host/generate-dev-token"
- ]
- }
- ]
- },
{
"tab": "Resources",
"groups": [
@@ -700,6 +654,58 @@
{
"source": "/client-sdk-references/kotlin-multiplatform/libraries/room",
"destination": "/client-sdk-references/kotlin/libraries/room"
+ },
+ {
+ "source": "/tutorials/client/data/cascading-delete",
+ "destination": "/usage/use-case-examples/cascading-deletes"
+ },
+ {
+ "source": "/tutorials/client/data/sequential-id-mapping",
+ "destination": "/usage/use-case-examples/sequential-id-mapping"
+ },
+ {
+ "source": "/tutorials/overview",
+ "destination": "/usage/use-case-examples"
+ },
+ {
+ "source": "/tutorials/client/overview",
+ "destination": "/usage/use-case-examples"
+ },
+ {
+ "source": "/tutorials/client/sdks/web/next-js",
+ "destination": "/client-sdk-references/javascript-web/nextjs"
+ },
+ {
+ "source": "/tutorials/client/attachments-and-files/overview",
+ "destination": "/usage/use-case-examples/attachments-files"
+ },
+ {
+ "source": "/tutorials/client/attachments-and-files/aws-s3-storage-adapter",
+ "destination": "/usage/use-case-examples/aws-s3-storage"
+ },
+ {
+ "source": "/tutorials/client/attachments-and-files/pdf-attachment",
+ "destination": "/usage/use-case-examples/pdf-attachments"
+ },
+ {
+ "source": "/tutorials/client/performance/overview",
+ "destination": "/integration-guides/supabase-+-powersync/connector-performance"
+ },
+ {
+ "source": "/tutorials/client/performance/supabase-connector-performance",
+ "destination": "/integration-guides/supabase-+-powersync/connector-performance"
+ },
+ {
+ "source": "/tutorials/self-host/overview",
+ "destination": "/self-hosting/getting-started"
+ },
+ {
+ "source": "/tutorials/self-host/generate-dev-token",
+ "destination": "/self-hosting/generate-dev-token"
+ },
+ {
+ "source": "/tutorials/client/data/overview",
+ "destination": "/usage/use-case-examples"
}
],
"appearance": {
diff --git a/tutorials/client/performance/supabase-connector-performance.mdx b/integration-guides/supabase-+-powersync/connector-performance.mdx
similarity index 94%
rename from tutorials/client/performance/supabase-connector-performance.mdx
rename to integration-guides/supabase-+-powersync/connector-performance.mdx
index 373f2ec7..3c446d22 100644
--- a/tutorials/client/performance/supabase-connector-performance.mdx
+++ b/integration-guides/supabase-+-powersync/connector-performance.mdx
@@ -1,21 +1,19 @@
---
-title: "Improve Supabase Connector"
-description: "In this tutorial we will show you how to improve the performance of the Supabase Connector for the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist)."
+title: "Connector Performance"
+description: "Learn how to improve the performance of the Supabase Connector using batching strategies."
---
-# Background
-
The demos in the [powersync-js](https://github.com/powersync-ja/powersync-js/tree/main/demos) monorepo provide a minimal working example that illustrate the use of PowerSync with different frameworks.
-The demos are therefore not necessarily optimized for performance and can therefore be improved.
+The demos are therefore not necessarily optimized for performance and can be improved.
-This tutorial demonstrates how to improve the Supabase Connector's performance by implementing two batching strategies that reduce the number of database operations.
+This guide demonstrates how to improve the Supabase Connector's performance by implementing two batching strategies that reduce the number of database operations.
-# Batching Strategies
+## Batching Strategies
-The two batching strategies that will be implemented are:
+The two batching strategies are:
1. Sequential Merge Strategy, and
-2. Pre-sorted Batch Strategy
+2. Pre-sorted Batch Strategy
@@ -121,7 +119,7 @@ The two batching strategies that will be implemented are:
- `putOps`: For `PUT` operations, organized by table name
- `deleteOps`: For `DELETE` operations, organized by table name
- `patchOps`: For `PATCH` operations (partial updates)
-
+
- Loop through all operations, sort them into the three collections, and then process all operations in batches.
```typescript {8-11, 17-20, 23, 26-29, 32-53, 56, 72}
@@ -209,7 +207,7 @@ The two batching strategies that will be implemented are:
-# Differences
+## Differences
@@ -264,14 +262,14 @@ The two batching strategies that will be implemented are:
-# Use cases
+## Use cases
You need more granular control over batch sizes
You want more detailed operation logging
-
+
You need to handle mixed operation types more efficiently
**Best for**: Mixed operation types
@@ -282,7 +280,7 @@ The two batching strategies that will be implemented are:
You have a large number of similar operations.
-
+
You want to minimize the number of network requests.
@@ -292,4 +290,4 @@ The two batching strategies that will be implemented are:
**Trade-off**: Higher memory usage
-
\ No newline at end of file
+
diff --git a/tutorials/self-host/generate-dev-token.mdx b/self-hosting/generate-dev-token.mdx
similarity index 83%
rename from tutorials/self-host/generate-dev-token.mdx
rename to self-hosting/generate-dev-token.mdx
index 08a456b1..9ff8d138 100644
--- a/tutorials/self-host/generate-dev-token.mdx
+++ b/self-hosting/generate-dev-token.mdx
@@ -1,25 +1,23 @@
---
title: "Generate a Development Token"
-description: "In this tutorial we will show you how to generate a development token for the self-hosted [PowerSync Service](https://powersync.mintlify.app/architecture/powersync-service#powersync-service)."
+description: "Learn how to generate a development token for the self-hosted PowerSync Service."
---
-# Introduction
-
Development tokens are useful for:
-- getting started quickly without implementing full auth config
-- sanity checking your sync rules config (were they applied correctly)
-- temporarily impersonating a specific user to debug specific issues
+- Getting started quickly without implementing full auth config
+- Sanity checking your sync rules config (were they applied correctly)
+- Temporarily impersonating a specific user to debug specific issues
-# Use Case
+## Use Case
Development tokens can be used either with the
- [test-client](https://github.com/powersync-ja/powersync-service/tree/main/test-client), or
- [Sync Diagnostics Client](/resources/troubleshooting#sync-diagnostics-client)
-# Generate a Development Token
+## Generate a Development Token
Development tokens can be generated via either
- [PowerSync Cloud](/installation/authentication-setup/development-tokens/#PowerSync-Cloud-Dashboard), or
-- locally with a self-hosted setup (described in this tutorial)
+- Locally with a self-hosted setup (described below)
@@ -72,4 +70,3 @@ Development tokens can be generated via either
-
diff --git a/tutorials/client/attachments-and-files/overview.mdx b/tutorials/client/attachments-and-files/overview.mdx
deleted file mode 100644
index a820115a..00000000
--- a/tutorials/client/attachments-and-files/overview.mdx
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: "Overview"
-description: "A collection of tutorials exploring storage strategies."
----
-
-
-
-
-
diff --git a/tutorials/client/data/overview.mdx b/tutorials/client/data/overview.mdx
deleted file mode 100644
index 7b78d52a..00000000
--- a/tutorials/client/data/overview.mdx
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: "Overview"
-description: "A collection of tutorials showcasing various data management strategies and use cases."
----
-
-
-
-
-
diff --git a/tutorials/client/overview.mdx b/tutorials/client/overview.mdx
deleted file mode 100644
index 87947f5d..00000000
--- a/tutorials/client/overview.mdx
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: "Overview"
-description: "A collection of tutorials for client-side use cases."
----
-
-
-
-
-
-
-
diff --git a/tutorials/client/performance/overview.mdx b/tutorials/client/performance/overview.mdx
deleted file mode 100644
index 0def40e5..00000000
--- a/tutorials/client/performance/overview.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: "Overview"
-description: "A collection of tutorials exploring performance strategies."
----
-
-
-
-
diff --git a/tutorials/client/sdks/overview.mdx b/tutorials/client/sdks/overview.mdx
deleted file mode 100644
index cf56e918..00000000
--- a/tutorials/client/sdks/overview.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: "Client SDK Tutorials"
-description: "A collection of tutorials on how to use PowerSync in supported client SDKs."
----
-
-
-
-
diff --git a/tutorials/overview.mdx b/tutorials/overview.mdx
deleted file mode 100644
index ebe78666..00000000
--- a/tutorials/overview.mdx
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: "Tutorials"
-sidebarTitle: "Overview"
-description: "A collection of tutorials showcasing solutions to common use cases across the PowerSync stack."
----
-
-## Overview
-
-Here you can learn how to approach various use cases and solve specific challenges when integrating PowerSync in your project.
-
-
- We are constantly expanding our list of tutorials. If you'd like to see a solution to a use case that is not currently available, [let us know on Discord](https://discord.gg/powersync).
-
-
-Our tutorials are currently organized into the following categories:
-
-
-
-
-
-
-## Notable Community Tutorials
-
-* Building an Offline-First Chat App Using PowerSync and Supabase
- * Postgres (Supabase) + React Native + Expo + Tamagui
- * [https://bndkt.com/blog/2023/building-an-offline-first-chat-app-using-powersync-and-supabase](https://bndkt.com/blog/2023/building-an-offline-first-chat-app-using-powersync-and-supabase)
-* Building an Offline-First Mobile App with PowerSync
- * Postgres + Flutter + Nest.js + Prisma ORM + Firebase Auth
- * [https://blog.stackademic.com/building-an-offline-first-mobile-app-with-powersync-40674d8b7ea1](https://blog.stackademic.com/building-an-offline-first-mobile-app-with-powersync-40674d8b7ea1)
-* Implementing Local-First Architecture: A Guide to MongoDB Cluster and PowerSync Integration
- * MongoDB Atlas + Next.js
- * [https://blog.stackademic.com/implementing-local-first-architecture-a-guide-to-mongodb-cluster-and-powersync-integration-6b21fa8059a1](https://blog.stackademic.com/implementing-local-first-architecture-a-guide-to-mongodb-cluster-and-powersync-integration-6b21fa8059a1)
-
-## Additional Resources
-
-Haven't found what you're looking for?
-
-* Additional tutorial-style technical posts can be found on the [PowerSync Blog](https://www.powersync.com/blog). Popular pages include:
- * [Migrating a MongoDB Atlas Device Sync App to PowerSync](https://www.powersync.com/blog/migrating-a-mongodb-atlas-device-sync-app-to-powersync)
- * [PowerSync and Supabase: Just the Basics](https://www.powersync.com/blog/powersync-and-supabase-just-the-basics)
- * [Flutter Tutorial: building an offline-first chat app with Supabase and PowerSync](https://www.powersync.com/blog/flutter-tutorial-building-an-offline-first-chat-app-with-supabase-and-powersync)
-* See our [Use Case Examples](/usage/use-case-examples) for details about common use cases.
-* See [Demo Apps / Example Projects](/resources/demo-apps-example-projects) for working implementations of PowerSync.
diff --git a/tutorials/self-host/overview.mdx b/tutorials/self-host/overview.mdx
deleted file mode 100644
index 01cc8d86..00000000
--- a/tutorials/self-host/overview.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: "Overview"
-description: "A collection of tutorials related to self-hosting."
----
-
-
-
-
\ No newline at end of file
diff --git a/usage/use-case-examples.mdx b/usage/use-case-examples.mdx
index ca334d24..04f458d5 100644
--- a/usage/use-case-examples.mdx
+++ b/usage/use-case-examples.mdx
@@ -7,7 +7,9 @@ The following examples are available to help you get started with specific use c
+
+
@@ -17,17 +19,18 @@ The following examples are available to help you get started with specific use c
+
+
## Additional Resources
-A growing collection of demo apps and tutorials are also available, showcasing working example implementations and solutions to additional use cases:
+A growing collection of demo apps are available, showcasing working example implementations:
-
-
+
diff --git a/usage/use-case-examples/attachments-files.mdx b/usage/use-case-examples/attachments-files.mdx
index 6690dd48..ab3e315d 100644
--- a/usage/use-case-examples/attachments-files.mdx
+++ b/usage/use-case-examples/attachments-files.mdx
@@ -18,6 +18,6 @@ We currently have these helper packages available to manage attachments:
| **Kotlin** | [attachments](https://github.com/powersync-ja/powersync-kotlin/tree/main/core/src/commonMain/kotlin/com/powersync/attachments) | [To-Do List demo app](https://github.com/powersync-ja/powersync-kotlin/tree/main/demos/android-supabase-todolist) |
| **Swift** | [attachments](https://github.com/powersync-ja/powersync-swift/blob/main/Sources/PowerSync/attachments/README.md) | [To-Do List demo app](https://github.com/powersync-ja/powersync-swift/tree/main/Demos/PowerSyncExample) |
-The example implementations above use [Supabase Storage](https://supabase.com/docs/guides/storage) as storage provider.
+The example implementations above use [Supabase Storage](https://supabase.com/docs/guides/storage) as storage provider.
* For more information on the use of Supabase as the storage provider, refer to [Handling Attachments](/integration-guides/supabase-+-powersync/handling-attachments)
-* To learn how to adapt the implementations to use AWS S3 as the storage provider, see [this tutorial](/tutorials/client/attachments-and-files/aws-s3-storage-adapter)
+* To learn how to adapt the implementations to use AWS S3 as the storage provider, see [AWS S3 Storage](/usage/use-case-examples/aws-s3-storage)
diff --git a/tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx b/usage/use-case-examples/aws-s3-storage.mdx
similarity index 97%
rename from tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx
rename to usage/use-case-examples/aws-s3-storage.mdx
index 22bd8a0e..8cedd966 100644
--- a/tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx
+++ b/usage/use-case-examples/aws-s3-storage.mdx
@@ -1,35 +1,34 @@
---
-title: "Use AWS S3 for attachment storage"
-description: "In this tutorial, we will show you how to replace Supabase Storage with AWS S3 for handling attachments in the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist)."
-sidebarTitle: "AWS S3 Storage"
+title: "AWS S3 Storage"
+description: "Learn how to use AWS S3 instead of Supabase Storage for handling attachments with PowerSync."
---
-# Introduction
+This guide shows how to replace Supabase Storage with AWS S3 for handling attachments. The implementation is based on the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist).
The AWS credentials should never be exposed directly on the client - it could expose access to the entire S3 bucket to the user.
-For this tutorial we have therefore decided to use the following workflow:
+For this implementation we use the following workflow:
1. Client makes an API call to the app backend, using the client credentials (a [Supabase Edge Function](https://supabase.com/docs/guides/functions)).
2. The backend API has the S3 credentials. It signs a S3 upload/download URL, and returns that to the client.
3. The client uploads/downloads using the pre-signed S3 URL.
-The following updates to the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) are therefore required:
+The following updates to the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) are required:
1. Create Supabase Edge Functions, and
2. Update the demo app to use the AWS S3 storage adapter
- The following pre-requisites are required to complete this tutorial:
+ The following pre-requisites are required:
- Clone the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) repo
- Follow the instructions in the [README](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/README.md) and ensure that the app runs locally
- A running PowerSync Service (can be self-hosted)
-# Steps
+## Implementation Steps
- This tutorial assumes that you have an AWS account. If you do not have an AWS account, you can create one [here](https://aws.amazon.com/).
+ This guide assumes that you have an AWS account. If you do not have an AWS account, you can create one [here](https://aws.amazon.com/).
To enable attachment storage using AWS S3, set up an S3 bucket by following these steps:
@@ -73,9 +72,9 @@ The following updates to the [React Native To-Do List demo app](https://github.c
**Security Note**
- The filename specified in each edge function request can pose security risks, such as enabling a user to overwrite another user’s files by using the same filename.
+ The filename specified in each edge function request can pose security risks, such as enabling a user to overwrite another user's files by using the same filename.
To mitigate this, a common approach is to generate a random prefix or directory for each file.
- While it’s likely fine to omit this safeguard in the demo — since users can already read and delete any file — this should be addressed in a **production environment**.
+ While it's likely fine to omit this safeguard in the demo — since users can already read and delete any file — this should be addressed in a **production environment**.
Create the `s3-upload` Edge Function by running the following in your Supabase project:
@@ -510,7 +509,7 @@ The following updates to the [React Native To-Do List demo app](https://github.c
```
-
+
@@ -593,7 +592,7 @@ The following updates to the [React Native To-Do List demo app](https://github.c
export const useSystem = () => React.useContext(SystemContext);
```
-
+
Ensure that all references to`AppConfig.supabaseBucket` is replaced with the S3 bucket name in the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist).
@@ -605,7 +604,8 @@ The following updates to the [React Native To-Do List demo app](https://github.c
-## The complete client files used in this tutorial can be found below
+## Complete Client Files
+
```typescript AWSStorageAdapter.ts
import * as FileSystem from 'expo-file-system';
diff --git a/tutorials/client/data/cascading-delete.mdx b/usage/use-case-examples/cascading-deletes.mdx
similarity index 68%
rename from tutorials/client/data/cascading-delete.mdx
rename to usage/use-case-examples/cascading-deletes.mdx
index 409388b7..e65b1a90 100644
--- a/tutorials/client/data/cascading-delete.mdx
+++ b/usage/use-case-examples/cascading-deletes.mdx
@@ -1,13 +1,11 @@
---
-title: "Cascading Delete"
-description: "In this tutorial we will show you how to perform a cascading delete on the client."
-keywords: ["data", "cascade", "delete"]
+title: "Cascading Deletes"
+description: "Learn how to perform cascading deletes on the client when using PowerSync."
---
-# Introduction
-
Since PowerSync utilizes SQLite views instead of standard tables, SQLite features like constraints, foreign keys, or cascading deletes are not available.
-Currently, there is no direct support for cascading deletes on the client. However, you can achieve this by either:
+
+There is no direct support for cascading deletes on the client. However, you can achieve this by either:
1. Manually deleting all the relevant tables within a **single transaction**, OR
Every local mutation performed against SQLite via the PowerSync SDK will be returned in `uploadData`. So as long as you are using `.execute()` for the mutation,
@@ -15,11 +13,11 @@ Currently, there is no direct support for cascading deletes on the client. Howev
2. Implementing triggers (which is more complex)
- You create triggers on the [internal tables](https://docs.powersync.com/architecture/client-architecture#schema) (not the views defined by the client schema), similar to what is
- done [here](https://github.com/powersync-ja/powersync-js/blob/e77b1abfbed91988de1f4c707c24855cd66b2219/demos/react-supabase-todolist/src/app/utils/fts_setup.ts#L50)
+ You create triggers on the [internal tables](/architecture/client-architecture#schema) (not the views defined by the client schema), similar to what is
+ done [here](https://github.com/powersync-ja/powersync-js/blob/e77b1abfbed91988de1f4c707c24855cd66b2219/demos/react-supabase-todolist/src/app/utils/fts_setup.ts#L50).
-# Example
+## Example
The following example is taken from the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist).
It showcases how to delete a `list` and all its associated `todos` in a single transaction.
@@ -36,6 +34,6 @@ It showcases how to delete a `list` and all its associated `todos` in a single t
```
- An important thing to note is that the local SQLite database will always match the backend database, as long as the tables are in the publication, when online.
+ The local SQLite database will always match the backend database, as long as the tables are in the publication, when online.
For example, if you delete a record from the local `lists` table and Supabase cascade deletes a record from the `todo` table, PowerSync will also delete the local `todo` record when online.
-
\ No newline at end of file
+
diff --git a/tutorials/client/attachments-and-files/pdf-attachment.mdx b/usage/use-case-examples/pdf-attachments.mdx
similarity index 90%
rename from tutorials/client/attachments-and-files/pdf-attachment.mdx
rename to usage/use-case-examples/pdf-attachments.mdx
index 44dc1b7b..08956a62 100644
--- a/tutorials/client/attachments-and-files/pdf-attachment.mdx
+++ b/usage/use-case-examples/pdf-attachments.mdx
@@ -1,38 +1,35 @@
---
-title: "PDF attachments"
-description: "In this tutorial we will show you how to modify the [PhotoAttachmentQueue](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/library/powersync/PhotoAttachmentQueue.ts) for PDF attachments."
-keywords: ["pdf", "attachment", "storage"]
+title: "PDF Attachments"
+description: "Learn how to extend the attachment system to support PDF files with PowerSync."
---
+This guide shows how to modify the [PhotoAttachmentQueue](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/library/powersync/PhotoAttachmentQueue.ts) to support PDF attachments. The implementation is based on the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) which implements photo attachments (specifically a `jpeg`).
-# Introduction
+## Overview
-The current version of the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) implements a `PhotoAttachmentQueue` class which
-enables photo attachments (specifically a `jpeg`) to be synced. This tutorial will guide you on the changes needed to support PDF attachments.
-
-An overview of the required changes are:
+The required changes are:
1. Update the app schema by adding a `pdf_id` column to the todos table to link a pdf to a to-do item.
2. Add a `PdfAttachmentQueue` class
3. Initialize the `PdfAttachmentQueue` class
- The following pre-requisites are required to complete this tutorial:
+ The following pre-requisites are required:
- Clone the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) repo
- Follow the instructions in the [README](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/README.md) and ensure that the app runs locally
- A running PowerSync Service and Supabase (can be self-hosted)
- [Storage configuration in Supabase](/integration-guides/supabase-+-powersync/handling-attachments#configure-storage-in-supabase)
-# Steps
+## Implementation Steps
You can add a _nullable text_ `pdf_id` column to the to-do table via either the `Table Editor` or `SQL Editor` in Supabase.
-
- ## Table Editor
+
+ ### Table Editor
- ## SQL Editor
+ ### SQL Editor
- Navigate to the `SQL Editor` tab:
- Execute the following SQL:
@@ -176,7 +173,7 @@ An overview of the required changes are:
import { SupabaseStorageAdapter } from '../storage/SupabaseStorageAdapter';
import { type AttachmentRecord } from '@powersync/attachments';
-
+
import { KVStorage } from '../storage/KVStorage';
import { AppConfig } from '../supabase/AppConfig';
import { SupabaseConnector } from '../supabase/SupabaseConnector';
@@ -268,14 +265,14 @@ An overview of the required changes are:
-# Usage Example
+## Usage Example
The newly created `attachmentPdfQueue` can now be used in a component by using the `useSystem` hook created in [step-3](#step-3-initialize-the-pdfattachmentqueue-class) above
The code snippet below illustrates how a pdf could be saved when pressing a button. It uses a [DocumentPicker](https://www.npmjs.com/package/react-native-document-picker) UI component
to allow the user to select a pdf. When the button is pressed, `savePdf` is called.
-The `saveAttachment` method in the `PdfAttachmentQueue` class expects a base64 encoded string. We can therefore use
+The `saveAttachment` method in the `PdfAttachmentQueue` class expects a base64 encoded string. We can therefore use
[react-native-fs](https://www.npmjs.com/package/react-native-fs) to read the file and return the base64 encoded string which is passed to `saveAttachment`.
If your use-case generates a pdf file, ensure that you return a base64 encoded string.
@@ -288,27 +285,27 @@ import RNFS from 'react-native-fs';
// Within some component
-// useSystem is imported from system.ts
+// useSystem is imported from system.ts
const system = useSystem();
-const savePdf = async (id: string) => {
- if (system.attachmentPdfQueue) {
- const res = await DocumentPicker.pick({
- type: [DocumentPicker.types.pdf]
- });
-
+const savePdf = async (id: string) => {
+ if (system.attachmentPdfQueue) {
+ const res = await DocumentPicker.pick({
+ type: [DocumentPicker.types.pdf]
+ });
+
console.log(`Selected PDF: ${res[0].uri}`);
- const base64 = await RNFS.readFile(res[0].uri, 'base64');
- const { id: attachmentId } = await system.attachmentPdfQueue.saveAttachment(base64);
-
- await system.powersync.execute(`UPDATE ${TODO_TABLE} SET pdf_id = ? WHERE id = ?`, [attachmentId, id]);
- }
+ const base64 = await RNFS.readFile(res[0].uri, 'base64');
+ const { id: attachmentId } = await system.attachmentPdfQueue.saveAttachment(base64);
+
+ await system.powersync.execute(`UPDATE ${TODO_TABLE} SET pdf_id = ? WHERE id = ?`, [attachmentId, id]);
+ }
};
```
-# Notes
-Although this tutorial adds a new `pdf_id` column, the approach you should take strongly depends on your requirements.
+## Notes
+Although this guide adds a new `pdf_id` column, the approach you should take strongly depends on your requirements.
-An alternative approach could be to replace the `photo_id` with an `attachment_id` and have one `AttachmentQueue` class that handles all attachment types instead of having a class per attachment type.
\ No newline at end of file
+An alternative approach could be to replace the `photo_id` with an `attachment_id` and have one `AttachmentQueue` class that handles all attachment types instead of having a class per attachment type.
diff --git a/tutorials/client/data/sequential-id-mapping.mdx b/usage/use-case-examples/sequential-id-mapping.mdx
similarity index 95%
rename from tutorials/client/data/sequential-id-mapping.mdx
rename to usage/use-case-examples/sequential-id-mapping.mdx
index 19f018a0..983265c8 100644
--- a/tutorials/client/data/sequential-id-mapping.mdx
+++ b/usage/use-case-examples/sequential-id-mapping.mdx
@@ -1,11 +1,8 @@
---
-title: Sequential ID Mapping
-description: In this tutorial we will show you how to map a local UUID to a remote sequential (auto-incrementing) ID.
-sidebarTitle: Sequential ID Mapping
-keywords: ["data", "uuid", "map", "auto increment", "id", "sequential id"]
+title: "Sequential ID Mapping"
+description: "Learn how to map a local UUID to a remote sequential (auto-incrementing) ID when using PowerSync."
---
-# Introduction
When auto-incrementing / sequential IDs are used on the backend database, the ID can only be generated on the backend database, and not on the client while offline.
To handle this, you can use a secondary UUID on the client, then map it to a sequential ID when performing an update on the backend database.
This allows using a sequential primary key for each record, with a UUID as a secondary ID.
@@ -14,11 +11,11 @@ This allows using a sequential primary key for each record, with a UUID as a sec
This mapping must be performed wherever the UUIDs are referenced, including for every foreign key column.
-To illustrate this, we will use the [React To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-supabase-todolist) and modify it to use UUIDs
+The following example uses the [React To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-supabase-todolist) and modifies it to use UUIDs
on the client and map them to sequential IDs on the backend database (Supabase in this case).
-### Overview
-Before we get started, let's outline the changes we will have to make:
+## Overview
+
Update the `lists` and `todos` tables
@@ -46,7 +43,7 @@ Before we get started, let's outline the changes we will have to make:
-# Schema
+## Schema
In order to map the UUID to the integer ID, we need to update the
- `lists` table by adding a `uuid` column, which will be the secondary ID, and
@@ -87,7 +84,7 @@ In order to map the UUID to the integer ID, we need to update the
With the schema updated, we now need a method to synchronize and map the `list_id` and `list_uuid` in the `todos` table, with the `id` and `uuid` columns in the `lists` table.
We can achieve this by creating SQL triggers.
-# Create SQL Triggers
+## Create SQL Triggers
We need to create triggers that can look up the integer ID for the given UUID and vice versa.
These triggers will maintain consistency between `list_id` and `list_uuid` in the `todos` table by ensuring that they remain synchronized with the `id` and `uuid` columns in the `lists` table;
@@ -185,7 +182,7 @@ We will create the following two triggers that cover either scenario of updating
We now have triggers in place that will handle the mapping for our updated schema and
can move on to updating the Sync Rules to use the UUID column instead of the integer ID.
-# Update Sync Rules
+## Update Sync Rules
As sequential IDs can only be created on the backend database, we need to use UUIDs in the client. This can be done by updating both the `parameters` and `data` queries to use the new `uuid` columns.
The `parameters` query is updated by removing the `list_id` alias (this is removed to avoid any confusion between the `list_id` column in the `todos` table), and
@@ -204,7 +201,7 @@ bucket_definitions:
With the Sync Rules updated, we can now move on to updating the client to use UUIDs.
-# Update Client to Use UUIDs
+## Update Client to Use UUIDs
With our Sync Rules updated, we no longer have the `list_id` column in the `todos` table.
We start by updating `AppSchema.ts` and replacing `list_id` with `list_uuid` in the `todos` table.
@@ -341,4 +338,4 @@ export const SearchBarWidget: React.FC = () => {
}
};
}
-```
\ No newline at end of file
+```