diff --git a/packages/db/src/config.ts b/packages/db/src/config.ts index 9e6956cab3..0336f9af99 100644 --- a/packages/db/src/config.ts +++ b/packages/db/src/config.ts @@ -1,6 +1,6 @@ import type { SQLiteInsertValue } from 'drizzle-orm/sqlite-core'; import type { SqliteDB, Table } from './internal.js'; -import type { MaybeArray, collectionSchema } from './types.js'; +import type { DBCollection, MaybeArray, collectionSchema } from './types.js'; import { type BooleanField, type DBFieldInput, @@ -9,15 +9,14 @@ import { type NumberField, type TextField, collectionsSchema, + type indexSchema, type MaybePromise, } from './types.js'; import { z } from 'zod'; -export type DBFieldsConfig = z.input['fields']; - export type DBDataContext = { db: SqliteDB; - seed( + seed( collection: ResolvedCollectionConfig, data: MaybeArray< SQLiteInsertValue< @@ -25,7 +24,7 @@ export type DBDataContext = { string, /** TODO: true type inference */ Record< Extract, - DBFieldsConfig[number] + FieldsConfig[number] > > > @@ -51,26 +50,36 @@ export const astroConfigWithDbSchema = z.object({ db: dbConfigSchema.optional(), }); -type CollectionMeta = { +export type FieldsConfig = z.input['fields']; + +type CollectionMeta = { // Collection table is set later when running the data() function. // Collection config is assigned to an object key, // so the collection itself does not know the table name. table: Table; }; -type CollectionConfig = { +interface CollectionConfig + // use `extends` to ensure types line up with zod, + // only adding generics for type completions. + extends Pick, 'fields' | 'indexes'> { fields: TFields; -}; + indexes?: Record>; +} + +interface IndexConfig extends z.input { + on: MaybeArray>; +} export type ResolvedCollectionConfig< - TFields extends DBFieldsConfig = DBFieldsConfig, + TFields extends FieldsConfig = FieldsConfig, Writable extends boolean = boolean, > = CollectionConfig & { writable: Writable; table: Table; }; -export function defineCollection( +export function defineCollection( userConfig: CollectionConfig ): ResolvedCollectionConfig { const meta: CollectionMeta = { table: null! }; @@ -88,7 +97,7 @@ export function defineCollection( }; } -export function defineWritableCollection( +export function defineWritableCollection( userConfig: CollectionConfig ): ResolvedCollectionConfig { const meta: CollectionMeta = { table: null! }; diff --git a/packages/db/src/types.ts b/packages/db/src/types.ts index ff580bafd8..510d99ea3a 100644 --- a/packages/db/src/types.ts +++ b/packages/db/src/types.ts @@ -52,18 +52,25 @@ const fieldSchema = z.union([ ]); const fieldsSchema = z.record(fieldSchema); -export const readableCollectionSchema = z.object({ +export const indexSchema = z.object({ + on: z.string().or(z.array(z.string())), + unique: z.boolean().optional(), +}); +const indexesSchema = z.record(indexSchema); + +const baseCollectionSchema = z.object({ fields: fieldsSchema, - writable: z.literal(false), + indexes: indexesSchema.optional(), table: z.any(), _setMeta: z.function().optional(), }); -export const writableCollectionSchema = z.object({ - fields: fieldsSchema, +export const readableCollectionSchema = baseCollectionSchema.extend({ + writable: z.literal(false), +}); + +export const writableCollectionSchema = baseCollectionSchema.extend({ writable: z.literal(true), - table: z.any(), - _setMeta: z.function().optional(), }); export const collectionSchema = z.union([readableCollectionSchema, writableCollectionSchema]); diff --git a/packages/db/test/fixtures/recipes/astro.config.ts b/packages/db/test/fixtures/recipes/astro.config.ts index fd09536894..0a8eedbae2 100644 --- a/packages/db/test/fixtures/recipes/astro.config.ts +++ b/packages/db/test/fixtures/recipes/astro.config.ts @@ -16,6 +16,9 @@ const Ingredient = defineCollection({ quantity: field.number(), recipeId: field.text(), }, + indexes: { + recipeIdx: { on: 'recipeId', unique: true }, + }, }); export default defineConfig({