From b1535716efea9f6f05be0de7a634bbc63b6b7f5c Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Thu, 14 Nov 2024 17:11:36 +0200 Subject: [PATCH 01/14] Added PowerSyncSQLiteDatabase type as part of exported members. --- .changeset/wild-melons-camp.md | 5 +++++ packages/drizzle-driver/src/index.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/wild-melons-camp.md diff --git a/.changeset/wild-melons-camp.md b/.changeset/wild-melons-camp.md new file mode 100644 index 00000000..6705ef79 --- /dev/null +++ b/.changeset/wild-melons-camp.md @@ -0,0 +1,5 @@ +--- +'@powersync/drizzle-driver': patch +--- + +Added PowerSyncSQLiteDatabase type as part of exported members. diff --git a/packages/drizzle-driver/src/index.ts b/packages/drizzle-driver/src/index.ts index f2eed732..6f5c1537 100644 --- a/packages/drizzle-driver/src/index.ts +++ b/packages/drizzle-driver/src/index.ts @@ -1,4 +1,4 @@ -import { wrapPowerSyncWithDrizzle } from './sqlite/db'; +import { wrapPowerSyncWithDrizzle, type PowerSyncSQLiteDatabase } from './sqlite/db'; import { toCompilableQuery } from './utils/compilableQuery'; -export { wrapPowerSyncWithDrizzle, toCompilableQuery }; +export { wrapPowerSyncWithDrizzle, toCompilableQuery, PowerSyncSQLiteDatabase }; From 01039ba52c3402fda83f0b0654b7ced8764ce73c Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Fri, 15 Nov 2024 13:54:34 +0200 Subject: [PATCH 02/14] Added mechanism to map Drizzle table to a PowerSync table. --- packages/drizzle-driver/README.md | 28 ++++++++++++++++- packages/drizzle-driver/package.json | 3 ++ packages/drizzle-driver/src/index.ts | 3 +- packages/drizzle-driver/src/utils/schema.ts | 35 +++++++++++++++++++++ pnpm-lock.yaml | 10 +++--- 5 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 packages/drizzle-driver/src/utils/schema.ts diff --git a/packages/drizzle-driver/README.md b/packages/drizzle-driver/README.md index 3523df9c..02ae457e 100644 --- a/packages/drizzle-driver/README.md +++ b/packages/drizzle-driver/README.md @@ -59,10 +59,36 @@ export const db = wrapPowerSyncWithDrizzle(powerSyncDb, { }); ``` +## Converting Drizzle Tables to PowerSync Tables + +The `toPowerSyncTable` function simplifies the process of integrating Drizzle with PowerSync. Define your Drizzle tables, convert each using `toPowerSyncTable`, and supply the converted table definitions into your PowerSync schema for a unified development experience. + +As the PowerSync table only supports `text`, `integer`, and `real`, the same limitation extends to the Drizzle table definitions. + +```js +import { toPowerSyncTable } from '@powersync/drizzle-driver'; +import { Schema } from '@powersync/web'; +import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +// Define a Drizzle table +const lists = sqliteTable('lists', { + id: text('id').primaryKey().notNull(), + created_at: text('created_at'), + name: text('name').notNull(), + owner_id: text('owner_id') +}); + +const psLists = toPowerSyncTable(lists); // converts the Drizzle table to a PowerSync table +// toPowerSyncTable(lists, { localOnly: true }); - th allows for PowerSync table configuration + +export const AppSchema = new Schema({ + lists: psLists // names the table `lists` in the PowerSync schema +}); +``` + ## Known limitations - The integration does not currently support nested transactions (also known as `savepoints`). -- The Drizzle schema needs to be created manually, and it should match the table definitions of your PowerSync schema. ### Compilable queries diff --git a/packages/drizzle-driver/package.json b/packages/drizzle-driver/package.json index fbd24bea..2fa45665 100644 --- a/packages/drizzle-driver/package.json +++ b/packages/drizzle-driver/package.json @@ -29,6 +29,9 @@ "@powersync/common": "workspace:^1.19.0", "drizzle-orm": "<1.0.0" }, + "dependencies": { + "@powersync/common": "workspace:*" + }, "devDependencies": { "@powersync/web": "workspace:*", "@journeyapps/wa-sqlite": "^0.4.1", diff --git a/packages/drizzle-driver/src/index.ts b/packages/drizzle-driver/src/index.ts index 6f5c1537..4845ca48 100644 --- a/packages/drizzle-driver/src/index.ts +++ b/packages/drizzle-driver/src/index.ts @@ -1,4 +1,5 @@ import { wrapPowerSyncWithDrizzle, type PowerSyncSQLiteDatabase } from './sqlite/db'; import { toCompilableQuery } from './utils/compilableQuery'; +import { toPowerSyncTable } from './utils/schema'; -export { wrapPowerSyncWithDrizzle, toCompilableQuery, PowerSyncSQLiteDatabase }; +export { wrapPowerSyncWithDrizzle, toCompilableQuery, toPowerSyncTable, PowerSyncSQLiteDatabase }; diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts new file mode 100644 index 00000000..cd3a37d5 --- /dev/null +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -0,0 +1,35 @@ +import { column, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; +import { + SQLiteInteger, + SQLiteReal, + SQLiteText, + type SQLiteTableWithColumns, + type TableConfig +} from 'drizzle-orm/sqlite-core'; + +export function toPowerSyncTable(table: SQLiteTableWithColumns, options?: TableV2Options) { + const columns: { [key: string]: BaseColumnType } = {}; + for (const [columnName, columnValue] of Object.entries(table)) { + // Skip the id column + if (columnName === 'id') { + continue; + } + + let mappedType: BaseColumnType; + switch (columnValue.columnType) { + case SQLiteText.name: + mappedType = column.text; + break; + case SQLiteInteger.name: + mappedType = column.integer; + break; + case SQLiteReal.name: + mappedType = column.real; + break; + default: + throw new Error(`Unsupported column type: ${columnValue.columnType}`); + } + columns[columnName] = mappedType; + } + return new Table(columns, options); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b54b5658..7e49df57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1598,7 +1598,7 @@ importers: packages/drizzle-driver: dependencies: '@powersync/common': - specifier: workspace:^1.19.0 + specifier: workspace:* version: link:../common devDependencies: '@journeyapps/wa-sqlite': @@ -19070,9 +19070,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/eslint-parser@7.25.8(@babel/core@7.24.5)(eslint@8.57.1)': + '@babel/eslint-parser@7.25.8(@babel/core@7.25.7)(eslint@8.57.1)': dependencies: - '@babel/core': 7.24.5 + '@babel/core': 7.25.7 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 eslint: 8.57.1 eslint-visitor-keys: 2.1.0 @@ -26872,7 +26872,7 @@ snapshots: '@react-native/eslint-config@0.73.2(eslint@8.57.1)(prettier@3.3.3)(typescript@5.5.4)': dependencies: '@babel/core': 7.24.5 - '@babel/eslint-parser': 7.25.8(@babel/core@7.24.5)(eslint@8.57.1) + '@babel/eslint-parser': 7.25.8(@babel/core@7.25.7)(eslint@8.57.1) '@react-native/eslint-plugin': 0.73.1 '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.5.4) @@ -33333,7 +33333,7 @@ snapshots: eslint-plugin-ft-flow@2.0.3(@babel/eslint-parser@7.25.8(@babel/core@7.24.5)(eslint@8.57.1))(eslint@8.57.1): dependencies: - '@babel/eslint-parser': 7.25.8(@babel/core@7.24.5)(eslint@8.57.1) + '@babel/eslint-parser': 7.25.8(@babel/core@7.25.7)(eslint@8.57.1) eslint: 8.57.1 lodash: 4.17.21 string-natural-compare: 3.0.1 From 34e8becc7e7d682ab4f016eda0ce035a3aafa481 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Fri, 15 Nov 2024 16:53:25 +0200 Subject: [PATCH 03/14] Transforming index options from Drizzle tables. Using getTableConfig instead of iterating keys. --- packages/drizzle-driver/src/utils/schema.ts | 36 ++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts index cd3a37d5..db642767 100644 --- a/packages/drizzle-driver/src/utils/schema.ts +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -1,5 +1,6 @@ -import { column, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; +import { column, IndexShorthand, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; import { + getTableConfig, SQLiteInteger, SQLiteReal, SQLiteText, @@ -7,16 +8,21 @@ import { type TableConfig } from 'drizzle-orm/sqlite-core'; -export function toPowerSyncTable(table: SQLiteTableWithColumns, options?: TableV2Options) { +export function toPowerSyncTable( + table: SQLiteTableWithColumns, + options?: Omit +) { + const { columns: drizzleColumns, indexes: drizzleIndexes } = getTableConfig(table); + const columns: { [key: string]: BaseColumnType } = {}; - for (const [columnName, columnValue] of Object.entries(table)) { + for (const drizzleColumn of drizzleColumns) { // Skip the id column - if (columnName === 'id') { + if (drizzleColumn.name === 'id') { continue; } let mappedType: BaseColumnType; - switch (columnValue.columnType) { + switch (drizzleColumn.columnType) { case SQLiteText.name: mappedType = column.text; break; @@ -27,9 +33,23 @@ export function toPowerSyncTable(table: SQLiteTableWithCo mappedType = column.real; break; default: - throw new Error(`Unsupported column type: ${columnValue.columnType}`); + throw new Error(`Unsupported column type: ${drizzleColumn.columnType}`); } - columns[columnName] = mappedType; + columns[drizzleColumn.name] = mappedType; + } + const indexes: IndexShorthand = {}; + + for (const index of drizzleIndexes) { + index.config; + if (!index.config.columns.length) { + continue; + } + const columns: string[] = []; + for (const indexColumn of index.config.columns) { + columns.push((indexColumn as { name: string }).name); + } + + indexes[index.config.name] = columns; } - return new Table(columns, options); + return new Table(columns, { ...options, indexes }); } From 1e0b18b259a5d33b0250ed39560318f65694bf03 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 20 Nov 2024 10:09:39 +0200 Subject: [PATCH 04/14] Added toPowerSyncSchema() --- packages/drizzle-driver/src/index.ts | 17 ++++++++-- packages/drizzle-driver/src/utils/schema.ts | 35 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/packages/drizzle-driver/src/index.ts b/packages/drizzle-driver/src/index.ts index 4845ca48..037bb5c6 100644 --- a/packages/drizzle-driver/src/index.ts +++ b/packages/drizzle-driver/src/index.ts @@ -1,5 +1,18 @@ import { wrapPowerSyncWithDrizzle, type PowerSyncSQLiteDatabase } from './sqlite/db'; import { toCompilableQuery } from './utils/compilableQuery'; -import { toPowerSyncTable } from './utils/schema'; +import { + toPowerSyncTable, + toPowerSyncSchema, + DrizzleTablePowerSyncOptions, + DrizzleTableWithPowerSyncOptions +} from './utils/schema'; -export { wrapPowerSyncWithDrizzle, toCompilableQuery, toPowerSyncTable, PowerSyncSQLiteDatabase }; +export { + wrapPowerSyncWithDrizzle, + toCompilableQuery, + toPowerSyncTable, + toPowerSyncSchema, + DrizzleTablePowerSyncOptions, + DrizzleTableWithPowerSyncOptions, + PowerSyncSQLiteDatabase +}; diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts index db642767..f9ee7164 100644 --- a/packages/drizzle-driver/src/utils/schema.ts +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -1,4 +1,5 @@ -import { column, IndexShorthand, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; +import { column, IndexShorthand, Schema, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; +import { isTable, Relations } from 'drizzle-orm'; import { getTableConfig, SQLiteInteger, @@ -53,3 +54,35 @@ export function toPowerSyncTable( } return new Table(columns, { ...options, indexes }); } + +export type DrizzleTablePowerSyncOptions = Omit; + +export type DrizzleTableWithPowerSyncOptions = { + tableDefinition: SQLiteTableWithColumns; + options?: DrizzleTablePowerSyncOptions | undefined; +}; + +export function toPowerSyncSchema( + schemaEntries: Record | Relations | DrizzleTableWithPowerSyncOptions> +) { + const tables: Record = {}; + for (const schemaEntry of Object.values(schemaEntries)) { + let maybeTable: SQLiteTableWithColumns | Relations | undefined = undefined; + let maybeOptions: DrizzleTablePowerSyncOptions | undefined = undefined; + + if (typeof schemaEntry === 'object' && 'tableDefinition' in schemaEntry) { + const tableWithOptions = schemaEntry as DrizzleTableWithPowerSyncOptions; + maybeTable = tableWithOptions.tableDefinition; + maybeOptions = tableWithOptions.options; + } else { + maybeTable = schemaEntry; + } + + if (isTable(maybeTable)) { + const { name } = getTableConfig(maybeTable); + tables[name] = toPowerSyncTable(maybeTable as SQLiteTableWithColumns, maybeOptions); + } + } + + return new Schema(tables); +} From 4b7c60f4f323922ad3a2e60199d03c7ba169d3d7 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 20 Nov 2024 14:27:11 +0200 Subject: [PATCH 05/14] Added working types to toPowerSyncTable and toPowerSyncSchema. --- packages/drizzle-driver/src/index.ts | 24 ++++++++---- packages/drizzle-driver/src/utils/schema.ts | 43 ++++++++++++++++----- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/packages/drizzle-driver/src/index.ts b/packages/drizzle-driver/src/index.ts index 037bb5c6..f808c057 100644 --- a/packages/drizzle-driver/src/index.ts +++ b/packages/drizzle-driver/src/index.ts @@ -1,18 +1,26 @@ import { wrapPowerSyncWithDrizzle, type PowerSyncSQLiteDatabase } from './sqlite/db'; import { toCompilableQuery } from './utils/compilableQuery'; import { - toPowerSyncTable, toPowerSyncSchema, - DrizzleTablePowerSyncOptions, - DrizzleTableWithPowerSyncOptions + toPowerSyncTable, + type DrizzleTablePowerSyncOptions, + type DrizzleTableWithPowerSyncOptions, + type Expand, + type ExtractPowerSyncColumns, + type TableName, + type TablesFromSchemaEntries } from './utils/schema'; export { - wrapPowerSyncWithDrizzle, - toCompilableQuery, - toPowerSyncTable, - toPowerSyncSchema, DrizzleTablePowerSyncOptions, DrizzleTableWithPowerSyncOptions, - PowerSyncSQLiteDatabase + Expand, + ExtractPowerSyncColumns, + PowerSyncSQLiteDatabase, + TableName, + TablesFromSchemaEntries, + toCompilableQuery, + toPowerSyncSchema, + toPowerSyncTable, + wrapPowerSyncWithDrizzle }; diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts index f9ee7164..c2986799 100644 --- a/packages/drizzle-driver/src/utils/schema.ts +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -1,5 +1,5 @@ import { column, IndexShorthand, Schema, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; -import { isTable, Relations } from 'drizzle-orm'; +import { InferSelectModel, isTable, Relations } from 'drizzle-orm'; import { getTableConfig, SQLiteInteger, @@ -9,10 +9,16 @@ import { type TableConfig } from 'drizzle-orm/sqlite-core'; -export function toPowerSyncTable( - table: SQLiteTableWithColumns, +export type ExtractPowerSyncColumns> = { + [K in keyof InferSelectModel as K extends 'id' ? never : K]: BaseColumnType[K]>; +}; + +export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; + +export function toPowerSyncTable>( + table: T, options?: Omit -) { +): Table>> { const { columns: drizzleColumns, indexes: drizzleIndexes } = getTableConfig(table); const columns: { [key: string]: BaseColumnType } = {}; @@ -52,7 +58,7 @@ export function toPowerSyncTable( indexes[index.config.name] = columns; } - return new Table(columns, { ...options, indexes }); + return new Table(columns, { ...options, indexes }) as Table>>; } export type DrizzleTablePowerSyncOptions = Omit; @@ -62,9 +68,28 @@ export type DrizzleTableWithPowerSyncOptions = { options?: DrizzleTablePowerSyncOptions | undefined; }; -export function toPowerSyncSchema( - schemaEntries: Record | Relations | DrizzleTableWithPowerSyncOptions> -) { +export type TableName = + T extends SQLiteTableWithColumns + ? T['_']['name'] + : T extends DrizzleTableWithPowerSyncOptions + ? T['tableDefinition']['_']['name'] + : never; + +export type TablesFromSchemaEntries = { + [K in keyof T as T[K] extends Relations + ? never + : T[K] extends SQLiteTableWithColumns | DrizzleTableWithPowerSyncOptions + ? TableName + : never]: T[K] extends SQLiteTableWithColumns + ? Table>> + : T[K] extends DrizzleTableWithPowerSyncOptions + ? Table>> + : never; +}; + +export function toPowerSyncSchema< + T extends Record | Relations | DrizzleTableWithPowerSyncOptions> +>(schemaEntries: T): Schema>> { const tables: Record = {}; for (const schemaEntry of Object.values(schemaEntries)) { let maybeTable: SQLiteTableWithColumns | Relations | undefined = undefined; @@ -84,5 +109,5 @@ export function toPowerSyncSchema( } } - return new Schema(tables); + return new Schema(tables) as Schema>>; } From 95fb832bd65378b2a50c7dae114c7c7fa57834a1 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 20 Nov 2024 17:10:50 +0200 Subject: [PATCH 06/14] Updated Readme. --- packages/drizzle-driver/README.md | 48 +++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/drizzle-driver/README.md b/packages/drizzle-driver/README.md index 02ae457e..987eb874 100644 --- a/packages/drizzle-driver/README.md +++ b/packages/drizzle-driver/README.md @@ -59,12 +59,54 @@ export const db = wrapPowerSyncWithDrizzle(powerSyncDb, { }); ``` -## Converting Drizzle Tables to PowerSync Tables +## Schema Conversion -The `toPowerSyncTable` function simplifies the process of integrating Drizzle with PowerSync. Define your Drizzle tables, convert each using `toPowerSyncTable`, and supply the converted table definitions into your PowerSync schema for a unified development experience. +The `toPowerSyncSchema` schema function simplifies the process of integrating Drizzle with PowerSync. Define your Drizzle tables and supply the schema to the `toPowerSyncSchema` function for a unified development experience. As the PowerSync table only supports `text`, `integer`, and `real`, the same limitation extends to the Drizzle table definitions. +```js +import { toPowerSyncSchema } from '@powersync/drizzle-driver'; +import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +// Define a Drizzle table +const lists = sqliteTable('lists', { + id: text('id').primaryKey().notNull(), + created_at: text('created_at'), + name: text('name').notNull(), + owner_id: text('owner_id') +}); + +export const drizzleSchema = { + lists +}; + +export const AppSchema = toPowerSyncSchema(drizzleSchema); +``` + +### Defining PowerSync Options + +The PowerSync table definition allows additional options supported by PowerSync's app schema beyond that which are supported by Drizzle. +They can be specified as follows. Note that these options exclude indexes as they can be specified in a Drizzle table. + +```js +import { toPowerSyncSchema } from '@powersync/drizzle-driver'; +// import { toPowerSyncSchema, type DrizzleTableWithPowerSyncOptions} from '@powersync/drizzle-driver'; for TypeScript + +const listsWithOptions = { tableDefinition: logs, options: { localOnly: true } }; +// const listsWithOptions: DrizzleTableWithPowerSyncOptions = { tableDefinition: logs, options: { localOnly: true } }; for TypeScript + +export const drizzleSchemaWithOptions = { + lists: listsWithOptions +}; + +export const AppSchema = toPowerSyncSchema(drizzleSchemaWithOptions); +``` + +### Converting a Single Table From Drizzle to Powersync + +Drizzle tables can also be converted on a table-by-table basis with `toPowerSyncTable`. + ```js import { toPowerSyncTable } from '@powersync/drizzle-driver'; import { Schema } from '@powersync/web'; @@ -79,7 +121,7 @@ const lists = sqliteTable('lists', { }); const psLists = toPowerSyncTable(lists); // converts the Drizzle table to a PowerSync table -// toPowerSyncTable(lists, { localOnly: true }); - th allows for PowerSync table configuration +// toPowerSyncTable(lists, { localOnly: true }); - allows for PowerSync table configuration export const AppSchema = new Schema({ lists: psLists // names the table `lists` in the PowerSync schema From 8c84bbfc3c005bbf730e059cdc8c6a23da642a81 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 20 Nov 2024 19:03:02 +0200 Subject: [PATCH 07/14] Added unit tests. --- .../tests/sqlite/schema.test.ts | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 packages/drizzle-driver/tests/sqlite/schema.test.ts diff --git a/packages/drizzle-driver/tests/sqlite/schema.test.ts b/packages/drizzle-driver/tests/sqlite/schema.test.ts new file mode 100644 index 00000000..b869287c --- /dev/null +++ b/packages/drizzle-driver/tests/sqlite/schema.test.ts @@ -0,0 +1,199 @@ +import { column, Schema, Table } from '@powersync/common'; +import { index, integer, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { describe, expect, it } from 'vitest'; +import { DrizzleTableWithPowerSyncOptions, toPowerSyncSchema, toPowerSyncTable } from '../../src/utils/schema'; + +describe('toPowerSyncTable', () => { + it('basic conversion', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + const convertedList = toPowerSyncTable(lists); + + const expectedLists = new Table({ + name: column.text, + owner_id: column.text, + counter: column.integer, + completion: column.real + }); + + expect(convertedList).toEqual(expectedLists); + }); + + it('conversion with index', () => { + const lists = sqliteTable( + 'lists', + { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id') + }, + (lists) => ({ + owner: index('owner').on(lists.owner_id) + }) + ); + const convertedList = toPowerSyncTable(lists); + + const expectedLists = new Table( + { + name: column.text, + owner_id: column.text + }, + { indexes: { owner: ['owner_id'] } } + ); + + expect(convertedList).toEqual(expectedLists); + }); + + it('conversion with options', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull() + }); + + const convertedList = toPowerSyncTable(lists, { localOnly: true, insertOnly: true, viewName: 'listsView' }); + + const expectedLists = new Table( + { + name: column.text + }, + { localOnly: true, insertOnly: true, viewName: 'listsView' } + ); + + expect(convertedList).toEqual(expectedLists); + }); +}); + +describe('toPowerSyncSchema', () => { + it('basic conversion', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + + const todos = sqliteTable('todos', { + id: text('id').primaryKey(), + list_id: text('list_id').references(() => lists.id), + description: text('description') + }); + + const drizzleSchema = { + lists, + todos + }; + const convertedSchema = toPowerSyncSchema(drizzleSchema); + + const expectedSchema = new Schema({ + lists: new Table({ + name: column.text, + owner_id: column.text, + counter: column.integer, + completion: column.real + }), + todos: new Table({ + list_id: column.text, + description: column.text + }) + }); + + expect(convertedSchema).toEqual(expectedSchema); + }); + + it('conversion with options', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + + const todos = sqliteTable('todos', { + id: text('id').primaryKey(), + list_id: text('list_id').references(() => lists.id), + description: text('description') + }); + + const drizzleSchemaWithOptions = { + lists: { + tableDefinition: lists, + options: { localOnly: true, insertOnly: true, viewName: 'listsView' } + } as DrizzleTableWithPowerSyncOptions, + todos + }; + + const convertedSchema = toPowerSyncSchema(drizzleSchemaWithOptions); + + const expectedSchema = new Schema({ + lists: new Table( + { + name: column.text, + owner_id: column.text, + counter: column.integer, + completion: column.real + }, + { localOnly: true, insertOnly: true, viewName: 'listsView' } + ), + todos: new Table({ + list_id: column.text, + description: column.text + }) + }); + + expect(convertedSchema).toEqual(expectedSchema); + }); + + it('conversion with index', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + + const todos = sqliteTable( + 'todos', + { + id: text('id').primaryKey(), + list_id: text('list_id').references(() => lists.id), + description: text('description') + }, + (todos) => ({ + list: index('list').on(todos.list_id) + }) + ); + + const drizzleSchemaWithOptions = { + lists, + todos + }; + + const convertedSchema = toPowerSyncSchema(drizzleSchemaWithOptions); + + const expectedSchema = new Schema({ + lists: new Table({ + name: column.text, + owner_id: column.text, + counter: column.integer, + completion: column.real + }), + todos: new Table( + { + list_id: column.text, + description: column.text + }, + { indexes: { list: ['list_id'] } } + ) + }); + + expect(convertedSchema).toEqual(expectedSchema); + }); +}); From 2cfd59267872847a76dc98b51258d83dad0de7de Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Wed, 20 Nov 2024 19:09:48 +0200 Subject: [PATCH 08/14] Added changeset. --- .changeset/tender-mugs-deliver.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tender-mugs-deliver.md diff --git a/.changeset/tender-mugs-deliver.md b/.changeset/tender-mugs-deliver.md new file mode 100644 index 00000000..d70203ee --- /dev/null +++ b/.changeset/tender-mugs-deliver.md @@ -0,0 +1,5 @@ +--- +'@powersync/drizzle-driver': minor +--- + +Added `toPowersyncTable` and `toPowerSyncSchema` helper functions to convert a Drizzle schema into a PowerSync app schema From b3882ac907f56bb50d5362e3bebef8b94239d118 Mon Sep 17 00:00:00 2001 From: benitav Date: Thu, 21 Nov 2024 10:12:14 +0200 Subject: [PATCH 09/14] Update readme for slightly improved flow --- packages/drizzle-driver/README.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/drizzle-driver/README.md b/packages/drizzle-driver/README.md index 987eb874..1ba9e722 100644 --- a/packages/drizzle-driver/README.md +++ b/packages/drizzle-driver/README.md @@ -54,16 +54,24 @@ export const powerSyncDb = new PowerSyncDatabase({ schema: appSchema }); +// This is the DB you will use in queries export const db = wrapPowerSyncWithDrizzle(powerSyncDb, { schema: drizzleSchema }); + +// Generate the local PowerSync schema from the Drizzle schema with `toPowerSyncSchema` +// Optional, but recommended, since you will only need to maintain one schema on the client-side +// Read on to learn more. +export const AppSchema = toPowerSyncSchema(drizzleSchema); ``` ## Schema Conversion -The `toPowerSyncSchema` schema function simplifies the process of integrating Drizzle with PowerSync. Define your Drizzle tables and supply the schema to the `toPowerSyncSchema` function for a unified development experience. +The `toPowerSyncSchema` function simplifies the process of integrating Drizzle with PowerSync. It infers the local [PowerSync schema](https://docs.powersync.com/installation/client-side-setup/define-your-schema) from your Drizzle schema definition, providing a unified development experience. + +As the PowerSync schema only supports SQLite types (`text`, `integer`, and `real`), the same limitation extends to the Drizzle table definitions. -As the PowerSync table only supports `text`, `integer`, and `real`, the same limitation extends to the Drizzle table definitions. +To use it, define your Drizzle tables and supply the schema to the `toPowerSyncSchema` function: ```js import { toPowerSyncSchema } from '@powersync/drizzle-driver'; @@ -81,6 +89,7 @@ export const drizzleSchema = { lists }; +// Infer the PowerSync schema from your Drizzle schema export const AppSchema = toPowerSyncSchema(drizzleSchema); ``` @@ -103,7 +112,7 @@ export const drizzleSchemaWithOptions = { export const AppSchema = toPowerSyncSchema(drizzleSchemaWithOptions); ``` -### Converting a Single Table From Drizzle to Powersync +### Converting a Single Table From Drizzle to PowerSync Drizzle tables can also be converted on a table-by-table basis with `toPowerSyncTable`. @@ -128,11 +137,7 @@ export const AppSchema = new Schema({ }); ``` -## Known limitations - -- The integration does not currently support nested transactions (also known as `savepoints`). - -### Compilable queries +## Compilable queries To use Drizzle queries in your hooks and composables, queries need to be converted using `toCompilableQuery`. @@ -144,3 +149,7 @@ const { data: listRecords, isLoading } = useQuery(toCompilableQuery(query)); ``` For more information on how to use Drizzle queries in PowerSync, see [here](https://docs.powersync.com/client-sdk-references/javascript-web/javascript-orm/drizzle#usage-examples). + +## Known limitations + +- The integration does not currently support nested transactions (also known as `savepoints`). From 31759b77b22cae5d152d56d5f789741a297cd309 Mon Sep 17 00:00:00 2001 From: benitav Date: Thu, 21 Nov 2024 10:26:09 +0200 Subject: [PATCH 10/14] Tweak --- packages/drizzle-driver/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/drizzle-driver/README.md b/packages/drizzle-driver/README.md index 1ba9e722..1e65f64f 100644 --- a/packages/drizzle-driver/README.md +++ b/packages/drizzle-driver/README.md @@ -15,7 +15,7 @@ import { wrapPowerSyncWithDrizzle } from '@powersync/drizzle-driver'; import { PowerSyncDatabase } from '@powersync/web'; import { relations } from 'drizzle-orm'; import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { appSchema } from './schema'; +import { AppSchema } from './schema'; export const lists = sqliteTable('lists', { id: text('id'), @@ -47,22 +47,24 @@ export const drizzleSchema = { todosRelations }; +// As an alternative to manually defining a PowerSync schema, generate the local PowerSync schema from the Drizzle schema with `toPowerSyncSchema`: +// import { toPowerSyncSchema } from '@powersync/drizzle-driver'; +// export const AppSchema = toPowerSyncSchema(drizzleSchema); +// +// This is optional, but recommended, since you will only need to maintain one schema on the client-side +// Read on to learn more. + export const powerSyncDb = new PowerSyncDatabase({ database: { dbFilename: 'test.sqlite' }, - schema: appSchema + schema: AppSchema }); // This is the DB you will use in queries export const db = wrapPowerSyncWithDrizzle(powerSyncDb, { schema: drizzleSchema }); - -// Generate the local PowerSync schema from the Drizzle schema with `toPowerSyncSchema` -// Optional, but recommended, since you will only need to maintain one schema on the client-side -// Read on to learn more. -export const AppSchema = toPowerSyncSchema(drizzleSchema); ``` ## Schema Conversion From e4eddd3dbdbdecd0e2f336691b6f18ae4f383288 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Mon, 2 Dec 2024 10:39:26 +0200 Subject: [PATCH 11/14] Removed `@powersync/common` dependency. --- packages/drizzle-driver/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/drizzle-driver/package.json b/packages/drizzle-driver/package.json index 31aa5a9b..756bee78 100644 --- a/packages/drizzle-driver/package.json +++ b/packages/drizzle-driver/package.json @@ -29,9 +29,6 @@ "@powersync/common": "workspace:^1.19.0", "drizzle-orm": "<1.0.0" }, - "dependencies": { - "@powersync/common": "workspace:*" - }, "devDependencies": { "@powersync/web": "workspace:*", "@journeyapps/wa-sqlite": "^0.4.1", From 1a1dca7fad3ddf7c20a2043b4906e52cea112e8d Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Mon, 2 Dec 2024 10:41:40 +0200 Subject: [PATCH 12/14] Updated lock file. --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3fad46c..a973c854 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1598,7 +1598,7 @@ importers: packages/drizzle-driver: dependencies: '@powersync/common': - specifier: workspace:* + specifier: workspace:^1.19.0 version: link:../common devDependencies: '@journeyapps/wa-sqlite': From e312705fd2ba7ea32adfaa6956040bd74d9c9012 Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Mon, 2 Dec 2024 12:01:17 +0200 Subject: [PATCH 13/14] Introduced DrizzleAppSchema constructor. --- packages/common/src/db/schema/Schema.ts | 2 +- packages/drizzle-driver/src/utils/schema.ts | 47 ++++++++++++++++++- .../tests/sqlite/schema.test.ts | 37 ++++++++++++++- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/packages/common/src/db/schema/Schema.ts b/packages/common/src/db/schema/Schema.ts index 82141e0e..0b72499a 100644 --- a/packages/common/src/db/schema/Schema.ts +++ b/packages/common/src/db/schema/Schema.ts @@ -2,7 +2,7 @@ import { RowType, Table } from './Table.js'; type SchemaType = Record>; -type SchemaTableType = { +export type SchemaTableType = { [K in keyof S]: RowType; }; diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts index c2986799..6a939f9f 100644 --- a/packages/drizzle-driver/src/utils/schema.ts +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -1,4 +1,12 @@ -import { column, IndexShorthand, Schema, Table, type BaseColumnType, type TableV2Options } from '@powersync/common'; +import { + column, + IndexShorthand, + Schema, + SchemaTableType, + Table, + type BaseColumnType, + type TableV2Options +} from '@powersync/common'; import { InferSelectModel, isTable, Relations } from 'drizzle-orm'; import { getTableConfig, @@ -111,3 +119,40 @@ export function toPowerSyncSchema< return new Schema(tables) as Schema>>; } + +export function toPowerSyncTables< + T extends Record | Relations | DrizzleTableWithPowerSyncOptions> +>(schemaEntries: T) { + const tables: Record = {}; + for (const schemaEntry of Object.values(schemaEntries)) { + let maybeTable: SQLiteTableWithColumns | Relations | undefined = undefined; + let maybeOptions: DrizzleTablePowerSyncOptions | undefined = undefined; + + if (typeof schemaEntry === 'object' && 'tableDefinition' in schemaEntry) { + const tableWithOptions = schemaEntry as DrizzleTableWithPowerSyncOptions; + maybeTable = tableWithOptions.tableDefinition; + maybeOptions = tableWithOptions.options; + } else { + maybeTable = schemaEntry; + } + + if (isTable(maybeTable)) { + const { name } = getTableConfig(maybeTable); + tables[name] = toPowerSyncTable(maybeTable as SQLiteTableWithColumns, maybeOptions); + } + } + + return tables; +} + +export class DrizzleAppSchema< + T extends Record | Relations | DrizzleTableWithPowerSyncOptions> +> extends Schema { + constructor(drizzleSchema: T) { + super(toPowerSyncTables(drizzleSchema)); + // This is just used for typing + this.types = {} as SchemaTableType>>; + } + + readonly types: SchemaTableType>>; +} diff --git a/packages/drizzle-driver/tests/sqlite/schema.test.ts b/packages/drizzle-driver/tests/sqlite/schema.test.ts index b869287c..fe31fc67 100644 --- a/packages/drizzle-driver/tests/sqlite/schema.test.ts +++ b/packages/drizzle-driver/tests/sqlite/schema.test.ts @@ -1,7 +1,12 @@ import { column, Schema, Table } from '@powersync/common'; import { index, integer, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import { describe, expect, it } from 'vitest'; -import { DrizzleTableWithPowerSyncOptions, toPowerSyncSchema, toPowerSyncTable } from '../../src/utils/schema'; +import { + DrizzleAppSchema, + DrizzleTableWithPowerSyncOptions, + toPowerSyncSchema, + toPowerSyncTable +} from '../../src/utils/schema'; describe('toPowerSyncTable', () => { it('basic conversion', () => { @@ -24,6 +29,36 @@ describe('toPowerSyncTable', () => { expect(convertedList).toEqual(expectedLists); }); + it('basic conversion class', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + const convertedList = new DrizzleAppSchema({ lists }); + + const a: (typeof convertedList)['types']['lists'] = { + name: 'd', + completion: 1, + counter: 0, + id: '1', + owner_id: null + }; + }); + + it('classed based types', () => { + const lists = sqliteTable('lists', { + id: text('id').primaryKey(), + name: text('name').notNull(), + owner_id: text('owner_id'), + counter: integer('counter'), + completion: real('completion') + }); + const drizzle = new DrizzleAppSchema({ lists }); + }); + it('conversion with index', () => { const lists = sqliteTable( 'lists', From 3238948b6a3865df4c4a1f94f022e01cb2829fca Mon Sep 17 00:00:00 2001 From: Christiaan Landman Date: Mon, 2 Dec 2024 12:04:42 +0200 Subject: [PATCH 14/14] Dropped `toPowerSyncSchema` in favour of `DrizzleAppSchema` constructor. --- .changeset/tender-mugs-deliver.md | 2 +- packages/drizzle-driver/README.md | 20 +++---- packages/drizzle-driver/src/index.ts | 4 +- packages/drizzle-driver/src/utils/schema.ts | 27 +--------- .../tests/sqlite/schema.test.ts | 52 ++++--------------- 5 files changed, 23 insertions(+), 82 deletions(-) diff --git a/.changeset/tender-mugs-deliver.md b/.changeset/tender-mugs-deliver.md index d70203ee..7327e5fd 100644 --- a/.changeset/tender-mugs-deliver.md +++ b/.changeset/tender-mugs-deliver.md @@ -2,4 +2,4 @@ '@powersync/drizzle-driver': minor --- -Added `toPowersyncTable` and `toPowerSyncSchema` helper functions to convert a Drizzle schema into a PowerSync app schema +Added helper `toPowersyncTable` function and `DrizzleAppSchema` constructor to convert a Drizzle schema into a PowerSync app schema. diff --git a/packages/drizzle-driver/README.md b/packages/drizzle-driver/README.md index 1e65f64f..e27cddcf 100644 --- a/packages/drizzle-driver/README.md +++ b/packages/drizzle-driver/README.md @@ -47,9 +47,9 @@ export const drizzleSchema = { todosRelations }; -// As an alternative to manually defining a PowerSync schema, generate the local PowerSync schema from the Drizzle schema with `toPowerSyncSchema`: -// import { toPowerSyncSchema } from '@powersync/drizzle-driver'; -// export const AppSchema = toPowerSyncSchema(drizzleSchema); +// As an alternative to manually defining a PowerSync schema, generate the local PowerSync schema from the Drizzle schema with the `DrizzleAppSchema` constructor: +// import { DrizzleAppSchema } from '@powersync/drizzle-driver'; +// export const AppSchema = new DrizzleAppSchema(drizzleSchema); // // This is optional, but recommended, since you will only need to maintain one schema on the client-side // Read on to learn more. @@ -69,14 +69,14 @@ export const db = wrapPowerSyncWithDrizzle(powerSyncDb, { ## Schema Conversion -The `toPowerSyncSchema` function simplifies the process of integrating Drizzle with PowerSync. It infers the local [PowerSync schema](https://docs.powersync.com/installation/client-side-setup/define-your-schema) from your Drizzle schema definition, providing a unified development experience. +The `DrizzleAppSchema` constructor simplifies the process of integrating Drizzle with PowerSync. It infers the local [PowerSync schema](https://docs.powersync.com/installation/client-side-setup/define-your-schema) from your Drizzle schema definition, providing a unified development experience. As the PowerSync schema only supports SQLite types (`text`, `integer`, and `real`), the same limitation extends to the Drizzle table definitions. -To use it, define your Drizzle tables and supply the schema to the `toPowerSyncSchema` function: +To use it, define your Drizzle tables and supply the schema to the `DrizzleAppSchema` function: ```js -import { toPowerSyncSchema } from '@powersync/drizzle-driver'; +import { DrizzleAppSchema } from '@powersync/drizzle-driver'; import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; // Define a Drizzle table @@ -92,7 +92,7 @@ export const drizzleSchema = { }; // Infer the PowerSync schema from your Drizzle schema -export const AppSchema = toPowerSyncSchema(drizzleSchema); +export const AppSchema = new DrizzleAppSchema(drizzleSchema); ``` ### Defining PowerSync Options @@ -101,8 +101,8 @@ The PowerSync table definition allows additional options supported by PowerSync' They can be specified as follows. Note that these options exclude indexes as they can be specified in a Drizzle table. ```js -import { toPowerSyncSchema } from '@powersync/drizzle-driver'; -// import { toPowerSyncSchema, type DrizzleTableWithPowerSyncOptions} from '@powersync/drizzle-driver'; for TypeScript +import { DrizzleAppSchema } from '@powersync/drizzle-driver'; +// import { DrizzleAppSchema, type DrizzleTableWithPowerSyncOptions} from '@powersync/drizzle-driver'; for TypeScript const listsWithOptions = { tableDefinition: logs, options: { localOnly: true } }; // const listsWithOptions: DrizzleTableWithPowerSyncOptions = { tableDefinition: logs, options: { localOnly: true } }; for TypeScript @@ -111,7 +111,7 @@ export const drizzleSchemaWithOptions = { lists: listsWithOptions }; -export const AppSchema = toPowerSyncSchema(drizzleSchemaWithOptions); +export const AppSchema = new DrizzleAppSchema(drizzleSchemaWithOptions); ``` ### Converting a Single Table From Drizzle to PowerSync diff --git a/packages/drizzle-driver/src/index.ts b/packages/drizzle-driver/src/index.ts index f808c057..f7692f34 100644 --- a/packages/drizzle-driver/src/index.ts +++ b/packages/drizzle-driver/src/index.ts @@ -1,7 +1,7 @@ import { wrapPowerSyncWithDrizzle, type PowerSyncSQLiteDatabase } from './sqlite/db'; import { toCompilableQuery } from './utils/compilableQuery'; import { - toPowerSyncSchema, + DrizzleAppSchema, toPowerSyncTable, type DrizzleTablePowerSyncOptions, type DrizzleTableWithPowerSyncOptions, @@ -12,6 +12,7 @@ import { } from './utils/schema'; export { + DrizzleAppSchema, DrizzleTablePowerSyncOptions, DrizzleTableWithPowerSyncOptions, Expand, @@ -20,7 +21,6 @@ export { TableName, TablesFromSchemaEntries, toCompilableQuery, - toPowerSyncSchema, toPowerSyncTable, wrapPowerSyncWithDrizzle }; diff --git a/packages/drizzle-driver/src/utils/schema.ts b/packages/drizzle-driver/src/utils/schema.ts index 6a939f9f..eadc744b 100644 --- a/packages/drizzle-driver/src/utils/schema.ts +++ b/packages/drizzle-driver/src/utils/schema.ts @@ -95,32 +95,7 @@ export type TablesFromSchemaEntries = { : never; }; -export function toPowerSyncSchema< - T extends Record | Relations | DrizzleTableWithPowerSyncOptions> ->(schemaEntries: T): Schema>> { - const tables: Record = {}; - for (const schemaEntry of Object.values(schemaEntries)) { - let maybeTable: SQLiteTableWithColumns | Relations | undefined = undefined; - let maybeOptions: DrizzleTablePowerSyncOptions | undefined = undefined; - - if (typeof schemaEntry === 'object' && 'tableDefinition' in schemaEntry) { - const tableWithOptions = schemaEntry as DrizzleTableWithPowerSyncOptions; - maybeTable = tableWithOptions.tableDefinition; - maybeOptions = tableWithOptions.options; - } else { - maybeTable = schemaEntry; - } - - if (isTable(maybeTable)) { - const { name } = getTableConfig(maybeTable); - tables[name] = toPowerSyncTable(maybeTable as SQLiteTableWithColumns, maybeOptions); - } - } - - return new Schema(tables) as Schema>>; -} - -export function toPowerSyncTables< +function toPowerSyncTables< T extends Record | Relations | DrizzleTableWithPowerSyncOptions> >(schemaEntries: T) { const tables: Record = {}; diff --git a/packages/drizzle-driver/tests/sqlite/schema.test.ts b/packages/drizzle-driver/tests/sqlite/schema.test.ts index fe31fc67..069d9788 100644 --- a/packages/drizzle-driver/tests/sqlite/schema.test.ts +++ b/packages/drizzle-driver/tests/sqlite/schema.test.ts @@ -1,12 +1,7 @@ import { column, Schema, Table } from '@powersync/common'; import { index, integer, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import { describe, expect, it } from 'vitest'; -import { - DrizzleAppSchema, - DrizzleTableWithPowerSyncOptions, - toPowerSyncSchema, - toPowerSyncTable -} from '../../src/utils/schema'; +import { DrizzleAppSchema, DrizzleTableWithPowerSyncOptions, toPowerSyncTable } from '../../src/utils/schema'; describe('toPowerSyncTable', () => { it('basic conversion', () => { @@ -29,36 +24,6 @@ describe('toPowerSyncTable', () => { expect(convertedList).toEqual(expectedLists); }); - it('basic conversion class', () => { - const lists = sqliteTable('lists', { - id: text('id').primaryKey(), - name: text('name').notNull(), - owner_id: text('owner_id'), - counter: integer('counter'), - completion: real('completion') - }); - const convertedList = new DrizzleAppSchema({ lists }); - - const a: (typeof convertedList)['types']['lists'] = { - name: 'd', - completion: 1, - counter: 0, - id: '1', - owner_id: null - }; - }); - - it('classed based types', () => { - const lists = sqliteTable('lists', { - id: text('id').primaryKey(), - name: text('name').notNull(), - owner_id: text('owner_id'), - counter: integer('counter'), - completion: real('completion') - }); - const drizzle = new DrizzleAppSchema({ lists }); - }); - it('conversion with index', () => { const lists = sqliteTable( 'lists', @@ -103,7 +68,7 @@ describe('toPowerSyncTable', () => { }); }); -describe('toPowerSyncSchema', () => { +describe('DrizzleAppSchema constructor', () => { it('basic conversion', () => { const lists = sqliteTable('lists', { id: text('id').primaryKey(), @@ -123,7 +88,8 @@ describe('toPowerSyncSchema', () => { lists, todos }; - const convertedSchema = toPowerSyncSchema(drizzleSchema); + + const convertedSchema = new DrizzleAppSchema(drizzleSchema); const expectedSchema = new Schema({ lists: new Table({ @@ -138,7 +104,7 @@ describe('toPowerSyncSchema', () => { }) }); - expect(convertedSchema).toEqual(expectedSchema); + expect(convertedSchema.tables).toEqual(expectedSchema.tables); }); it('conversion with options', () => { @@ -164,7 +130,7 @@ describe('toPowerSyncSchema', () => { todos }; - const convertedSchema = toPowerSyncSchema(drizzleSchemaWithOptions); + const convertedSchema = new DrizzleAppSchema(drizzleSchemaWithOptions); const expectedSchema = new Schema({ lists: new Table( @@ -182,7 +148,7 @@ describe('toPowerSyncSchema', () => { }) }); - expect(convertedSchema).toEqual(expectedSchema); + expect(convertedSchema.tables).toEqual(expectedSchema.tables); }); it('conversion with index', () => { @@ -211,7 +177,7 @@ describe('toPowerSyncSchema', () => { todos }; - const convertedSchema = toPowerSyncSchema(drizzleSchemaWithOptions); + const convertedSchema = new DrizzleAppSchema(drizzleSchemaWithOptions); const expectedSchema = new Schema({ lists: new Table({ @@ -229,6 +195,6 @@ describe('toPowerSyncSchema', () => { ) }); - expect(convertedSchema).toEqual(expectedSchema); + expect(convertedSchema.tables).toEqual(expectedSchema.tables); }); });