mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-04 00:56:01 +00:00
copy kysely helper types to better guarantee types
This commit is contained in:
@@ -68,7 +68,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
|
|||||||
} else {
|
} else {
|
||||||
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
|
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
|
||||||
const conf = appConfig.connection ?? { url: ":memory:" };
|
const conf = appConfig.connection ?? { url: ":memory:" };
|
||||||
connection = sqlite(conf);
|
connection = sqlite(conf) as unknown as Connection;
|
||||||
$console.info(`Using ${connection!.name} connection`, conf.url);
|
$console.info(`Using ${connection!.name} connection`, conf.url);
|
||||||
}
|
}
|
||||||
appConfig.connection = connection;
|
appConfig.connection = connection;
|
||||||
@@ -168,7 +168,7 @@ export function serveStaticViaImport(opts?: { manifest?: Manifest }) {
|
|||||||
const path = c.req.path.substring(1);
|
const path = c.req.path.substring(1);
|
||||||
if (files.includes(path)) {
|
if (files.includes(path)) {
|
||||||
try {
|
try {
|
||||||
const content = await import(`bknd/static/${path}?raw`, {
|
const content = await import(/* @vite-ignore */ `bknd/static/${path}?raw`, {
|
||||||
assert: { type: "text" },
|
assert: { type: "text" },
|
||||||
}).then((m) => m.default);
|
}).then((m) => m.default);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* These are package global defaults.
|
* These are package global defaults.
|
||||||
*/
|
*/
|
||||||
import type { Generated } from "kysely";
|
import type { Generated } from "./types";
|
||||||
|
|
||||||
export type PrimaryFieldType<IdType = number | string> = IdType | Generated<IdType>;
|
export type PrimaryFieldType<IdType = number | string> = IdType | Generated<IdType>;
|
||||||
|
|
||||||
|
|||||||
@@ -4,3 +4,194 @@ export interface Serializable<Class, Json extends object = object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type MaybePromise<T> = T | Promise<T>;
|
export type MaybePromise<T> = T | Promise<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types below are copied from kysely.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type DrainOuterGeneric<T> = [T] extends [unknown] ? T : never;
|
||||||
|
/**
|
||||||
|
* This type can be used to specify a different type for
|
||||||
|
* select, insert and update operations.
|
||||||
|
*
|
||||||
|
* Also see the {@link Generated} type.
|
||||||
|
*
|
||||||
|
* ### Examples
|
||||||
|
*
|
||||||
|
* The next example defines a number column that is optional
|
||||||
|
* in inserts and updates. All columns are always optional
|
||||||
|
* in updates so therefore we don't need to specify `undefined`
|
||||||
|
* for the update type. The type below is useful for all kinds of
|
||||||
|
* database generated columns like identifiers. The `Generated`
|
||||||
|
* type is actually just a shortcut for the type in this example:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* type GeneratedNumber = ColumnType<number, number | undefined, number>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The above example makes the column optional in inserts
|
||||||
|
* and updates, but you can still choose to provide the
|
||||||
|
* column. If you want to prevent insertion/update you
|
||||||
|
* can se the type as `never`:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* type ReadonlyNumber = ColumnType<number, never, never>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Here's one more example where the type is different
|
||||||
|
* for each different operation:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* type UnupdateableDate = ColumnType<Date, string, never>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type ColumnType<SelectType, InsertType = SelectType, UpdateType = SelectType> = {
|
||||||
|
readonly __select__: SelectType;
|
||||||
|
readonly __insert__: InsertType;
|
||||||
|
readonly __update__: UpdateType;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* A shortcut for defining database-generated columns. The type
|
||||||
|
* is the same for all selects, inserts and updates but the
|
||||||
|
* column is optional for inserts and updates.
|
||||||
|
*
|
||||||
|
* The update type is `S` instead of `S | undefined` because updates are always
|
||||||
|
* optional --> no need to specify optionality.
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type Generated<S> = ColumnType<S, S | undefined, S>;
|
||||||
|
/**
|
||||||
|
* A shortcut for defining columns that are only database-generated
|
||||||
|
* (like postgres GENERATED ALWAYS AS IDENTITY). No insert/update
|
||||||
|
* is allowed.
|
||||||
|
*/
|
||||||
|
export type GeneratedAlways<S> = ColumnType<S, never, never>;
|
||||||
|
/**
|
||||||
|
* A shortcut for defining JSON columns, which are by default inserted/updated
|
||||||
|
* as stringified JSON strings.
|
||||||
|
*/
|
||||||
|
export type JSONColumnType<
|
||||||
|
SelectType extends object | null,
|
||||||
|
InsertType = string,
|
||||||
|
UpdateType = string,
|
||||||
|
> = ColumnType<SelectType, InsertType, UpdateType>;
|
||||||
|
/**
|
||||||
|
* Evaluates to `K` if `T` can be `null` or `undefined`.
|
||||||
|
*/
|
||||||
|
type IfNullable<T, K> = undefined extends T ? K : null extends T ? K : never;
|
||||||
|
/**
|
||||||
|
* Evaluates to `K` if `T` can't be `null` or `undefined`.
|
||||||
|
*/
|
||||||
|
type IfNotNullable<T, K> = undefined extends T
|
||||||
|
? never
|
||||||
|
: null extends T
|
||||||
|
? never
|
||||||
|
: T extends never
|
||||||
|
? never
|
||||||
|
: K;
|
||||||
|
/**
|
||||||
|
* Evaluates to `K` if `T` isn't `never`.
|
||||||
|
*/
|
||||||
|
type IfNotNever<T, K> = T extends never ? never : K;
|
||||||
|
export type SelectType<T> = T extends ColumnType<infer S, any, any> ? S : T;
|
||||||
|
export type InsertType<T> = T extends ColumnType<any, infer I, any> ? I : T;
|
||||||
|
export type UpdateType<T> = T extends ColumnType<any, any, infer U> ? U : T;
|
||||||
|
/**
|
||||||
|
* Keys of `R` whose `InsertType` values can be `null` or `undefined`.
|
||||||
|
*/
|
||||||
|
export type NullableInsertKeys<R> = {
|
||||||
|
[K in keyof R]: IfNullable<InsertType<R[K]>, K>;
|
||||||
|
}[keyof R];
|
||||||
|
/**
|
||||||
|
* Keys of `R` whose `InsertType` values can't be `null` or `undefined`.
|
||||||
|
*/
|
||||||
|
export type NonNullableInsertKeys<R> = {
|
||||||
|
[K in keyof R]: IfNotNullable<InsertType<R[K]>, K>;
|
||||||
|
}[keyof R];
|
||||||
|
/**
|
||||||
|
* Keys of `R` whose `SelectType` values are not `never`
|
||||||
|
*/
|
||||||
|
type NonNeverSelectKeys<R> = {
|
||||||
|
[K in keyof R]: IfNotNever<SelectType<R[K]>, K>;
|
||||||
|
}[keyof R];
|
||||||
|
/**
|
||||||
|
* Keys of `R` whose `UpdateType` values are not `never`
|
||||||
|
*/
|
||||||
|
export type UpdateKeys<R> = {
|
||||||
|
[K in keyof R]: IfNotNever<UpdateType<R[K]>, K>;
|
||||||
|
}[keyof R];
|
||||||
|
/**
|
||||||
|
* Given a table interface, extracts the select type from all
|
||||||
|
* {@link ColumnType} types.
|
||||||
|
*
|
||||||
|
* ### Examples
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* interface PersonTable {
|
||||||
|
* id: Generated<number>
|
||||||
|
* first_name: string
|
||||||
|
* modified_at: ColumnType<Date, string, never>
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* type Person = Selectable<PersonTable>
|
||||||
|
* // {
|
||||||
|
* // id: number,
|
||||||
|
* // first_name: string
|
||||||
|
* // modified_at: Date
|
||||||
|
* // }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type Selectable<R> = DrainOuterGeneric<{
|
||||||
|
[K in NonNeverSelectKeys<R>]: SelectType<R[K]>;
|
||||||
|
}>;
|
||||||
|
/**
|
||||||
|
* Given a table interface, extracts the insert type from all
|
||||||
|
* {@link ColumnType} types.
|
||||||
|
*
|
||||||
|
* ### Examples
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* interface PersonTable {
|
||||||
|
* id: Generated<number>
|
||||||
|
* first_name: string
|
||||||
|
* modified_at: ColumnType<Date, string, never>
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* type InsertablePerson = Insertable<PersonTable>
|
||||||
|
* // {
|
||||||
|
* // id?: number,
|
||||||
|
* // first_name: string
|
||||||
|
* // modified_at: string
|
||||||
|
* // }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type Insertable<R> = DrainOuterGeneric<
|
||||||
|
{
|
||||||
|
[K in NonNullableInsertKeys<R>]: InsertType<R[K]>;
|
||||||
|
} & {
|
||||||
|
[K in NullableInsertKeys<R>]?: InsertType<R[K]>;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
/**
|
||||||
|
* Given a table interface, extracts the update type from all
|
||||||
|
* {@link ColumnType} types.
|
||||||
|
*
|
||||||
|
* ### Examples
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* interface PersonTable {
|
||||||
|
* id: Generated<number>
|
||||||
|
* first_name: string
|
||||||
|
* modified_at: ColumnType<Date, string, never>
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* type UpdateablePerson = Updateable<PersonTable>
|
||||||
|
* // {
|
||||||
|
* // id?: number,
|
||||||
|
* // first_name?: string
|
||||||
|
* // }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type Updateable<R> = DrainOuterGeneric<{
|
||||||
|
[K in UpdateKeys<R>]?: UpdateType<R[K]>;
|
||||||
|
}>;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { DB, EntityData, RepoQueryIn } from "bknd";
|
import type { DB, EntityData, RepoQueryIn, Insertable, Selectable, Updateable } from "bknd";
|
||||||
|
|
||||||
import type { Insertable, Selectable, Updateable } from "kysely";
|
|
||||||
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
|
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
|
||||||
import type { FetchPromise, ResponseObject } from "modules/ModuleApi";
|
import type { FetchPromise, ResponseObject } from "modules/ModuleApi";
|
||||||
import type { RepositoryResultJSON } from "data/entities/query/RepositoryResult";
|
import type { RepositoryResultJSON } from "data/entities/query/RepositoryResult";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { autoFormatString } from "bknd/utils";
|
||||||
import type { Entity, EntityManager, TEntityType } from "data/entities";
|
import type { Entity, EntityManager, TEntityType } from "data/entities";
|
||||||
import type { EntityRelation } from "data/relations";
|
import type { EntityRelation } from "data/relations";
|
||||||
import { autoFormatString } from "core/utils";
|
|
||||||
import { usersFields } from "auth/auth-entities";
|
import { usersFields } from "auth/auth-entities";
|
||||||
import { mediaFields } from "media/media-entities";
|
import { mediaFields } from "media/media-entities";
|
||||||
|
|
||||||
@@ -170,8 +170,7 @@ export class EntityTypescript {
|
|||||||
const strings: string[] = [];
|
const strings: string[] = [];
|
||||||
const tables: Record<string, string> = {};
|
const tables: Record<string, string> = {};
|
||||||
const imports: Record<string, string[]> = {
|
const imports: Record<string, string[]> = {
|
||||||
"bknd/core": ["DB"],
|
bknd: ["DB", "Insertable", "Selectable", "Updateable", "Generated"],
|
||||||
kysely: ["Insertable", "Selectable", "Updateable", "Generated"],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// add global types
|
// add global types
|
||||||
@@ -207,7 +206,7 @@ export class EntityTypescript {
|
|||||||
strings.push(tables_string);
|
strings.push(tables_string);
|
||||||
|
|
||||||
// merge
|
// merge
|
||||||
let merge = `declare module "bknd/core" {\n`;
|
let merge = `declare module "bknd" {\n`;
|
||||||
for (const systemEntity of system_entities) {
|
for (const systemEntity of system_entities) {
|
||||||
const system_fields = Object.keys(systemEntities[systemEntity.name]);
|
const system_fields = Object.keys(systemEntities[systemEntity.name]);
|
||||||
const additional_fields = systemEntity.fields
|
const additional_fields = systemEntity.fields
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export type {
|
|||||||
ListenerHandler,
|
ListenerHandler,
|
||||||
} from "core/events/EventListener";
|
} from "core/events/EventListener";
|
||||||
export { EventManager, type EmitsEvents, type EventClass } from "core/events/EventManager";
|
export { EventManager, type EmitsEvents, type EventClass } from "core/events/EventManager";
|
||||||
|
export type * from "core/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auth
|
* Auth
|
||||||
|
|||||||
+1
-5
@@ -32,12 +32,8 @@
|
|||||||
"*": ["./src/*"],
|
"*": ["./src/*"],
|
||||||
"bknd": ["./src/index.ts"],
|
"bknd": ["./src/index.ts"],
|
||||||
"bknd/utils": ["./src/core/utils/index.ts"],
|
"bknd/utils": ["./src/core/utils/index.ts"],
|
||||||
"bknd/core": ["./src/core/index.ts"],
|
|
||||||
"bknd/adapter": ["./src/adapter/index.ts"],
|
"bknd/adapter": ["./src/adapter/index.ts"],
|
||||||
"bknd/client": ["./src/ui/client/index.ts"],
|
"bknd/client": ["./src/ui/client/index.ts"]
|
||||||
"bknd/data": ["./src/data/index.ts"],
|
|
||||||
"bknd/media": ["./src/media/index.ts"],
|
|
||||||
"bknd/auth": ["./src/auth/index.ts"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
Reference in New Issue
Block a user