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); }); });