Skip to content

Commit 0419d1a

Browse files
committed
drizzle-driver: rebase beta rewrite onto main
1 parent 3f8f3f6 commit 0419d1a

22 files changed

Lines changed: 928 additions & 276 deletions

.changeset/calm-rivers-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/drizzle-driver': minor
3+
---
4+
5+
Rewrite the Drizzle driver against the Drizzle v1 beta `relations` + `db.query` API and drop `0.x` compatibility from this release line.

demos/react-neon-tanstack-query-notes/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"class-variance-authority": "^0.7.1",
2929
"clsx": "^2.1.1",
3030
"drizzle-kit": "^0.31.7",
31-
"drizzle-orm": "^0.44.7",
31+
"drizzle-orm": "1.0.0-beta.19",
3232
"lucide-react": "^0.503.0",
3333
"moment": "^2.30.1",
3434
"react": "^19.2.0",

demos/react-neon-tanstack-query-notes/src/lib/powersync-schema.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { defineRelations } from 'drizzle-orm';
12
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
2-
import { relations } from 'drizzle-orm';
33

44
export const notes = sqliteTable('notes', {
55
id: text().primaryKey(),
@@ -17,10 +17,9 @@ export const paragraphs = sqliteTable('paragraphs', {
1717
created_at: text().notNull(),
1818
});
1919

20-
export const notesRelations = relations(notes, ({ many }) => ({
21-
paragraphs: many(paragraphs),
22-
}));
23-
2420
export const drizzleSchema = {
25-
notes, paragraphs, notesRelations
26-
};
21+
notes,
22+
paragraphs
23+
};
24+
25+
export const drizzleRelations = defineRelations(drizzleSchema);

demos/react-neon-tanstack-query-notes/src/lib/powersync.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
DrizzleAppSchema,
1616
} from "@powersync/drizzle-driver";
1717

18-
import { drizzleSchema } from "./powersync-schema";
18+
import { drizzleRelations, drizzleSchema } from "./powersync-schema";
1919

2020
/// Postgres Response codes that we cannot recover from by retrying.
2121
const FATAL_RESPONSE_CODES = [
@@ -205,7 +205,9 @@ export const powersync = new PowerSyncDatabase({
205205
},
206206
});
207207

208-
export const powersyncDrizzle = wrapPowerSyncWithDrizzle(powersync);
208+
export const powersyncDrizzle = wrapPowerSyncWithDrizzle(powersync, {
209+
relations: drizzleRelations,
210+
});
209211

210212
let isInitialized = false;
211213

packages/drizzle-driver/README.md

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This package (`@powersync/drizzle-driver`) brings the benefits of an ORM through
44

55
## Beta Release
66

7-
The `drizzle-driver` package is currently in an Beta release.
7+
This release line targets `drizzle-orm@1.0.0-beta` and the beta `relations` + `db.query` API.
88

99
## Getting Started
1010

@@ -13,7 +13,7 @@ Set up the PowerSync Database and wrap it with Drizzle.
1313
```js
1414
import { wrapPowerSyncWithDrizzle } from '@powersync/drizzle-driver';
1515
import { PowerSyncDatabase } from '@powersync/web';
16-
import { relations } from 'drizzle-orm';
16+
import { defineRelations } from 'drizzle-orm';
1717
import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
1818
import { AppSchema } from './schema';
1919

@@ -29,27 +29,25 @@ export const todos = sqliteTable('todos', {
2929
created_at: text('created_at')
3030
});
3131

32-
export const listsRelations = relations(lists, ({ one, many }) => ({
33-
todos: many(todos)
34-
}));
35-
36-
export const todosRelations = relations(todos, ({ one, many }) => ({
37-
list: one(lists, {
38-
fields: [todos.list_id],
39-
references: [lists.id]
40-
})
32+
export const relations = defineRelations({ lists, todos }, (r) => ({
33+
lists: {
34+
todos: r.many.todos({
35+
from: r.lists.id,
36+
to: r.todos.list_id
37+
})
38+
},
39+
todos: {
40+
list: r.one.lists({
41+
from: r.todos.list_id,
42+
to: r.lists.id,
43+
optional: false
44+
})
45+
}
4146
}));
4247

43-
export const drizzleSchema = {
44-
lists,
45-
todos,
46-
listsRelations,
47-
todosRelations
48-
};
49-
5048
// As an alternative to manually defining a PowerSync schema, generate the local PowerSync schema from the Drizzle schema with the `DrizzleAppSchema` constructor:
5149
// import { DrizzleAppSchema } from '@powersync/drizzle-driver';
52-
// export const AppSchema = new DrizzleAppSchema(drizzleSchema);
50+
// export const AppSchema = new DrizzleAppSchema({ lists, todos });
5351
//
5452
// This is optional, but recommended, since you will only need to maintain one schema on the client-side
5553
// Read on to learn more.
@@ -63,7 +61,17 @@ export const powerSyncDb = new PowerSyncDatabase({
6361

6462
// This is the DB you will use in queries
6563
export const db = wrapPowerSyncWithDrizzle(powerSyncDb, {
66-
schema: drizzleSchema
64+
relations
65+
});
66+
```
67+
68+
To make relational queries, use `db.query`:
69+
70+
```js
71+
const listsWithTodos = await db.query.lists.findMany({
72+
with: {
73+
todos: true
74+
}
6775
});
6876
```
6977

packages/drizzle-driver/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
},
4848
"peerDependencies": {
4949
"@powersync/common": "workspace:^1.52.0",
50-
"drizzle-orm": "<1.0.0"
50+
"drizzle-orm": ">=1.0.0-beta.19 <1.0.0"
5151
},
5252
"devDependencies": {
5353
"@journeyapps/wa-sqlite": "catalog:",
@@ -56,7 +56,7 @@
5656
"@rollup/plugin-node-resolve": "catalog:",
5757
"@rollup/plugin-typescript": "catalog:",
5858
"@types/node": "catalog:",
59-
"drizzle-orm": "catalog:",
59+
"drizzle-orm": "1.0.0-beta.19",
6060
"rollup": "catalog:",
6161
"rollup-plugin-dts": "catalog:",
6262
"vite": "catalog:"

packages/drizzle-driver/src/sqlite/PowerSyncSQLiteBaseSession.ts

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { QueryResult } from '@powersync/common';
1+
import type { AbstractPowerSyncDatabase, QueryResult } from '@powersync/common';
22
import type { WithCacheConfig } from 'drizzle-orm/cache/core/types';
33
import { entityKind } from 'drizzle-orm/entity';
44
import type { Logger } from 'drizzle-orm/logger';
55
import { NoopLogger } from 'drizzle-orm/logger';
6-
import type { RelationalSchemaConfig, TablesRelationalConfig } from 'drizzle-orm/relations';
6+
import type { AnyRelations, EmptyRelations } from 'drizzle-orm/relations';
77
import { type Query } from 'drizzle-orm/sql/sql';
88
import type { SQLiteAsyncDialect } from 'drizzle-orm/sqlite-core/dialect';
99
import type { SelectedFieldsOrdered } from 'drizzle-orm/sqlite-core/query-builders/select.types';
@@ -16,34 +16,45 @@ import {
1616
} from 'drizzle-orm/sqlite-core/session';
1717
import { PowerSyncSQLitePreparedQuery, type ContextProvider } from './PowerSyncSQLitePreparedQuery.js';
1818

19+
type ResultMapper = (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown;
20+
type RelationalResultMapper = (
21+
rows: Record<string, unknown>[],
22+
mapColumnValue?: (value: unknown) => unknown
23+
) => unknown;
24+
1925
export interface PowerSyncSQLiteSessionOptions {
2026
logger?: Logger;
27+
db: AbstractPowerSyncDatabase;
2128
}
2229

2330
export type PowerSyncSQLiteTransactionConfig = SQLiteTransactionConfig & {
2431
accessMode?: 'read only' | 'read write';
2532
};
2633

27-
export class PowerSyncSQLiteTransaction<
28-
TFullSchema extends Record<string, unknown>,
29-
TSchema extends TablesRelationalConfig
30-
> extends SQLiteTransaction<'async', QueryResult, TFullSchema, TSchema> {
34+
export class PowerSyncSQLiteTransaction<TRelations extends AnyRelations = EmptyRelations> extends SQLiteTransaction<
35+
'async',
36+
QueryResult,
37+
Record<string, never>,
38+
TRelations
39+
> {
3140
static readonly [entityKind]: string = 'PowerSyncSQLiteTransaction';
3241
}
3342

34-
export class PowerSyncSQLiteBaseSession<
35-
TFullSchema extends Record<string, unknown>,
36-
TSchema extends TablesRelationalConfig
37-
> extends SQLiteSession<'async', QueryResult, TFullSchema, TSchema> {
43+
export class PowerSyncSQLiteBaseSession<TRelations extends AnyRelations = EmptyRelations> extends SQLiteSession<
44+
'async',
45+
QueryResult,
46+
Record<string, never>,
47+
TRelations
48+
> {
3849
static readonly [entityKind]: string = 'PowerSyncSQLiteBaseSession';
3950

4051
protected logger: Logger;
4152

4253
constructor(
4354
protected contextProvider: ContextProvider,
4455
protected dialect: SQLiteAsyncDialect,
45-
protected schema: RelationalSchemaConfig<TSchema> | undefined,
46-
protected options: PowerSyncSQLiteSessionOptions = {}
56+
protected relations: TRelations,
57+
protected options: PowerSyncSQLiteSessionOptions
4758
) {
4859
super(dialect);
4960
this.logger = options.logger ?? new NoopLogger();
@@ -54,7 +65,7 @@ export class PowerSyncSQLiteBaseSession<
5465
fields: SelectedFieldsOrdered | undefined,
5566
executeMethod: SQLiteExecuteMethod,
5667
isResponseInArrayMode: boolean,
57-
customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown,
68+
customResultMapper?: ResultMapper,
5869
queryMetadata?: {
5970
type: 'select' | 'update' | 'delete' | 'insert';
6071
tables: string[];
@@ -69,14 +80,35 @@ export class PowerSyncSQLiteBaseSession<
6980
executeMethod,
7081
isResponseInArrayMode,
7182
customResultMapper,
72-
undefined, // cache not supported yet
83+
undefined,
7384
queryMetadata,
7485
cacheConfig
7586
);
7687
}
7788

89+
prepareRelationalQuery<T extends PreparedQueryConfigBase & { type: 'async' }>(
90+
query: Query,
91+
fields: SelectedFieldsOrdered | undefined,
92+
executeMethod: SQLiteExecuteMethod,
93+
customResultMapper: RelationalResultMapper
94+
): PowerSyncSQLitePreparedQuery<T> {
95+
return new PowerSyncSQLitePreparedQuery(
96+
this.contextProvider,
97+
query,
98+
this.logger,
99+
fields,
100+
executeMethod,
101+
false,
102+
customResultMapper,
103+
undefined,
104+
{ type: 'select', tables: [] },
105+
undefined,
106+
true
107+
);
108+
}
109+
78110
transaction<T>(
79-
_transaction: (tx: PowerSyncSQLiteTransaction<TFullSchema, TSchema>) => T,
111+
_transaction: (tx: PowerSyncSQLiteTransaction<TRelations>) => T,
80112
_config: PowerSyncSQLiteTransactionConfig = {}
81113
): T {
82114
throw new Error('Nested transactions are not supported');

0 commit comments

Comments
 (0)