Skip to content

Commit 03ff775

Browse files
authored
feat(db-sqlite): add idType: 'uuid' support (#10016)
Adds `idType: 'uuid'` to the SQLite adapter support: ```ts sqliteAdapter({ idType: 'uuid', }) ``` Achieved through Drizzle's `$defaultFn()` https://orm.drizzle.team/docs/latest-releases/drizzle-orm-v0283#-added-defaultfn--default-methods-to-column-builders as SQLite doesn't have native UUID support. Added `sqlite-uuid` to CI.
1 parent 0e5bda9 commit 03ff775

File tree

10 files changed

+42
-16
lines changed

10 files changed

+42
-16
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ jobs:
180180
- postgres-uuid
181181
- supabase
182182
- sqlite
183+
- sqlite-uuid
183184
env:
184185
POSTGRES_USER: postgres
185186
POSTGRES_PASSWORD: postgres

docs/database/sqlite.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default buildConfig({
4040
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
4141
| `migrationDir` | Customize the directory that migrations are stored. |
4242
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
43+
| `idType` | A string of 'number', or 'uuid' that is used for the data type given to id columns. |
4344
| `transactionOptions` | A SQLiteTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
4445
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
4546
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |

packages/db-sqlite/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ export { sql } from 'drizzle-orm'
6161
const filename = fileURLToPath(import.meta.url)
6262

6363
export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
64-
const postgresIDType = args.idType || 'serial'
65-
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
64+
const sqliteIDType = args.idType || 'number'
65+
const payloadIDType = sqliteIDType === 'uuid' ? 'text' : 'number'
6666

6767
function adapter({ payload }: { payload: Payload }) {
6868
const migrationDir = findMigrationDir(args.migrationDir)
@@ -93,7 +93,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
9393
json: true,
9494
},
9595
fieldConstraints: {},
96-
idType: postgresIDType,
96+
idType: sqliteIDType,
9797
initializing,
9898
localesSuffix: args.localesSuffix || '_locales',
9999
logger: args.logger,

packages/db-sqlite/src/schema/buildDrizzleTable.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ export const buildDrizzleTable: BuildDrizzleTable = ({ adapter, locales, rawTabl
5959
break
6060
}
6161

62-
// Not used yet in SQLite but ready here.
6362
case 'uuid': {
64-
let builder = text(column.name)
63+
let builder = text(column.name, { length: 36 })
6564

6665
if (column.defaultRandom) {
6766
builder = builder.$defaultFn(() => uuidv4())

packages/db-sqlite/src/schema/setColumnID.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SetColumnID } from '@payloadcms/drizzle/types'
22

3-
export const setColumnID: SetColumnID = ({ columns, fields }) => {
3+
export const setColumnID: SetColumnID = ({ adapter, columns, fields }) => {
44
const idField = fields.find((field) => field.name === 'id')
55
if (idField) {
66
if (idField.type === 'number') {
@@ -22,6 +22,17 @@ export const setColumnID: SetColumnID = ({ columns, fields }) => {
2222
}
2323
}
2424

25+
if (adapter.idType === 'uuid') {
26+
columns.id = {
27+
name: 'id',
28+
type: 'uuid',
29+
defaultRandom: true,
30+
primaryKey: true,
31+
}
32+
33+
return 'uuid'
34+
}
35+
2536
columns.id = {
2637
name: 'id',
2738
type: 'integer',

packages/db-sqlite/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export type Args = {
4040
client: Config
4141
/** Generated schema from payload generate:db-schema file path */
4242
generateSchemaOutputFile?: string
43-
idType?: 'serial' | 'uuid'
43+
idType?: 'number' | 'uuid'
4444
localesSuffix?: string
4545
logger?: DrizzleConfig['logger']
4646
migrationDir?: string
@@ -106,6 +106,7 @@ type SQLiteDrizzleAdapter = Omit<
106106
| 'drizzle'
107107
| 'dropDatabase'
108108
| 'execute'
109+
| 'idType'
109110
| 'insert'
110111
| 'operators'
111112
| 'relations'

packages/drizzle/src/utilities/pushDevSchema.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import prompts from 'prompts'
22

33
import type { BasePostgresAdapter } from '../postgres/types.js'
4-
import type { DrizzleAdapter } from '../types.js'
4+
import type { DrizzleAdapter, PostgresDB } from '../types.js'
55

66
/**
77
* Pushes the development schema to the database using Drizzle.
@@ -60,21 +60,24 @@ export const pushDevSchema = async (adapter: DrizzleAdapter) => {
6060
? `"${adapter.schemaName}"."payload_migrations"`
6161
: '"payload_migrations"'
6262

63+
const drizzle = adapter.drizzle as PostgresDB
64+
6365
const result = await adapter.execute({
64-
drizzle: adapter.drizzle,
66+
drizzle,
6567
raw: `SELECT * FROM ${migrationsTable} WHERE batch = '-1'`,
6668
})
6769

6870
const devPush = result.rows
6971

7072
if (!devPush.length) {
71-
await adapter.execute({
72-
drizzle: adapter.drizzle,
73-
raw: `INSERT INTO ${migrationsTable} (name, batch) VALUES ('dev', '-1')`,
73+
// Use drizzle for insert so $defaultFn's are called
74+
await drizzle.insert(adapter.tables.payload_migrations).values({
75+
name: 'dev',
76+
batch: -1,
7477
})
7578
} else {
7679
await adapter.execute({
77-
drizzle: adapter.drizzle,
80+
drizzle,
7881
raw: `UPDATE ${migrationsTable} SET updated_at = CURRENT_TIMESTAMP WHERE batch = '-1'`,
7982
})
8083
}

test/custom-graphql/int.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('Custom GraphQL', () => {
2424
}
2525
})
2626

27-
if (!['sqlite'].includes(process.env.PAYLOAD_DATABASE || '')) {
27+
if (!['sqlite', 'sqlite-uuid'].includes(process.env.PAYLOAD_DATABASE || '')) {
2828
describe('Isolated Transaction ID', () => {
2929
it('should isolate transaction IDs between queries in the same request', async () => {
3030
const query = `query {

test/database/int.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ describe('database', () => {
530530
describe('transactions', () => {
531531
describe('local api', () => {
532532
// sqlite cannot handle concurrent write transactions
533-
if (!['sqlite'].includes(process.env.PAYLOAD_DATABASE)) {
533+
if (!['sqlite', 'sqlite-uuid'].includes(process.env.PAYLOAD_DATABASE)) {
534534
it('should commit multiple operations in isolation', async () => {
535535
const req = {
536536
payload,
@@ -1074,7 +1074,8 @@ describe('database', () => {
10741074
data: { title: 'invalid', relationship: 'not-real-id' },
10751075
})
10761076
} catch (error) {
1077-
expect(error).toBeInstanceOf(Error)
1077+
// instanceof checks don't work with libsql
1078+
expect(error).toBeTruthy()
10781079
}
10791080

10801081
expect(invalidDoc).toBeUndefined()

test/generateDatabaseAdapter.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ export const allDatabaseAdapters = {
5353
url: process.env.SQLITE_URL || 'file:./payloadtests.db',
5454
},
5555
})`,
56+
'sqlite-uuid': `
57+
import { sqliteAdapter } from '@payloadcms/db-sqlite'
58+
59+
export const databaseAdapter = sqliteAdapter({
60+
idType: 'uuid',
61+
client: {
62+
url: process.env.SQLITE_URL || 'file:./payloadtests.db',
63+
},
64+
})`,
5665
supabase: `
5766
import { postgresAdapter } from '@payloadcms/db-postgres'
5867

0 commit comments

Comments
 (0)