mirror of
https://github.com/withastro/astro.git
synced 2025-04-07 23:41:43 -05:00
feat: better Table object for type inference
This commit is contained in:
parent
76f8c76ea8
commit
bfd2706378
3 changed files with 54 additions and 53 deletions
|
@ -35,15 +35,7 @@ import { nanoid } from 'nanoid';
|
|||
import type { AstroIntegrationLogger } from 'astro';
|
||||
|
||||
export type SqliteDB = SqliteRemoteDatabase;
|
||||
export type {
|
||||
AstroTable,
|
||||
AstroText,
|
||||
AstroDate,
|
||||
AstroBoolean,
|
||||
AstroNumber,
|
||||
AstroJson,
|
||||
AstroId,
|
||||
} from './types.js';
|
||||
export type { Table } from './types.js';
|
||||
|
||||
const sqlite = new SQLiteAsyncDialect();
|
||||
|
||||
|
|
|
@ -25,40 +25,21 @@ ${Object.entries(collections)
|
|||
}
|
||||
|
||||
function generateTableType(name: string, collection: DBCollection): string {
|
||||
let tableType = ` export const ${name}: import(${INTERNAL_MOD_IMPORT}).AstroTable<{
|
||||
name: ${JSON.stringify(name)};
|
||||
columns: {
|
||||
id: import(${INTERNAL_MOD_IMPORT}).AstroId<{
|
||||
tableName: ${JSON.stringify(name)};
|
||||
}>;`;
|
||||
|
||||
for (const [fieldName, field] of Object.entries(collection.fields)) {
|
||||
const drizzleInterface = schemaTypeToDrizzleInterface(field.type);
|
||||
tableType += `
|
||||
${fieldName}: import(${INTERNAL_MOD_IMPORT}).${drizzleInterface}<{
|
||||
tableName: ${JSON.stringify(name)};
|
||||
name: ${JSON.stringify(fieldName)};
|
||||
notNull: ${field.optional ? 'false' : 'true'};
|
||||
hasDefault: ${typeof field.default !== 'undefined' ? 'true' : 'false'};
|
||||
}>;`;
|
||||
}
|
||||
tableType += `
|
||||
};
|
||||
}>;`;
|
||||
let tableType = ` export const ${name}: import(${INTERNAL_MOD_IMPORT}).Table<
|
||||
${JSON.stringify(name)},
|
||||
${JSON.stringify(
|
||||
Object.fromEntries(
|
||||
Object.entries(collection.fields).map(([fieldName, field]) => [
|
||||
fieldName,
|
||||
{
|
||||
// Only select fields Drizzle needs for inference
|
||||
type: field.type,
|
||||
optional: field.optional,
|
||||
default: field.default,
|
||||
},
|
||||
])
|
||||
)
|
||||
)}
|
||||
>;`;
|
||||
return tableType;
|
||||
}
|
||||
|
||||
function schemaTypeToDrizzleInterface(type: FieldType) {
|
||||
switch (type) {
|
||||
case 'text':
|
||||
return 'AstroText';
|
||||
case 'number':
|
||||
return 'AstroNumber';
|
||||
case 'boolean':
|
||||
return 'AstroBoolean';
|
||||
case 'date':
|
||||
return 'AstroDate';
|
||||
case 'json':
|
||||
return 'AstroJson';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { ColumnDataType, ColumnBaseConfig } from 'drizzle-orm';
|
||||
import type { SQLiteColumn, SQLiteTableWithColumns, TableConfig } from 'drizzle-orm/sqlite-core';
|
||||
import type { SQLiteColumn, SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
|
||||
import { z } from 'zod';
|
||||
|
||||
const baseFieldSchema = z.object({
|
||||
|
@ -98,14 +98,7 @@ export type DBCollections = Record<string, DBCollection>;
|
|||
export type ReadableDBCollection = z.infer<typeof readableCollectionSchema>;
|
||||
export type WritableDBCollection = z.infer<typeof writableCollectionSchema>;
|
||||
|
||||
export type AstroTable<T extends Pick<TableConfig, 'name' | 'columns'>> = SQLiteTableWithColumns<
|
||||
T & {
|
||||
schema: undefined;
|
||||
dialect: 'sqlite';
|
||||
}
|
||||
>;
|
||||
|
||||
type GeneratedConfig<T extends ColumnDataType> = Pick<
|
||||
type GeneratedConfig<T extends ColumnDataType = ColumnDataType> = Pick<
|
||||
ColumnBaseConfig<T, string>,
|
||||
'name' | 'tableName' | 'notNull' | 'hasDefault'
|
||||
>;
|
||||
|
@ -180,3 +173,38 @@ export type AstroId<T extends Pick<GeneratedConfig<'string'>, 'tableName'>> = SQ
|
|||
>;
|
||||
|
||||
export type MaybePromise<T> = T | Promise<T>;
|
||||
|
||||
export type Column<T extends DBField['type'], S extends GeneratedConfig> = T extends 'boolean'
|
||||
? AstroBoolean<S>
|
||||
: T extends 'number'
|
||||
? AstroNumber<S>
|
||||
: T extends 'text'
|
||||
? AstroText<S>
|
||||
: T extends 'date'
|
||||
? AstroDate<S>
|
||||
: T extends 'json'
|
||||
? AstroJson<S>
|
||||
: never;
|
||||
|
||||
export type Table<
|
||||
TTableName extends string,
|
||||
TFields extends Record<string, Pick<DBField, 'type' | 'default' | 'optional'>>,
|
||||
> = SQLiteTableWithColumns<{
|
||||
name: TTableName;
|
||||
schema: undefined;
|
||||
dialect: 'sqlite';
|
||||
columns: {
|
||||
id: AstroId<{ tableName: TTableName }>;
|
||||
} & {
|
||||
[K in keyof TFields]: Column<
|
||||
TFields[K]['type'],
|
||||
{
|
||||
tableName: TTableName;
|
||||
// TODO: narrow K to string
|
||||
name: string;
|
||||
hasDefault: TFields[K]['default'] extends undefined ? false : true;
|
||||
notNull: TFields[K]['optional'] extends true ? false : true;
|
||||
}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
|
Loading…
Add table
Reference in a new issue