@elysiumjs/drizzle 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ import type { MigrationConnection } from './migration';
2
+ /** A query of a tagged-template client, which runs once awaited. */
3
+ type UnsafeQuery = PromiseLike<unknown> & {
4
+ simple?(): PromiseLike<unknown>;
5
+ };
6
+ /**
7
+ * What `migration:run` uses of a tagged-template client (Bun SQL and postgres.js share it).
8
+ */
9
+ export type TemplateClient = {
10
+ unsafe(text: string, params?: unknown[]): UnsafeQuery;
11
+ begin<T>(fn: (tx: TemplateClient) => Promise<T>): Promise<T>;
12
+ };
13
+ /**
14
+ * The migration connection of a tagged-template client: Bun SQL or postgres.js.
15
+ * @author Axel Nana <ax.lnana@outlook.com>
16
+ * @param client The client.
17
+ */
18
+ export declare const templateClientMigrations: (client: TemplateClient) => MigrationConnection;
19
+ /** What `migration:run` uses of a node-postgres client. */
20
+ type PgQueryable = {
21
+ query(text: string, values?: unknown[]): Promise<{
22
+ rows: unknown[];
23
+ }>;
24
+ };
25
+ /** What `migration:run` uses of a node-postgres pool. */
26
+ export type PgPool = PgQueryable & {
27
+ connect(): Promise<PgQueryable & {
28
+ release(): void;
29
+ }>;
30
+ };
31
+ /**
32
+ * The migration connection of a node-postgres pool.
33
+ * @author Axel Nana <ax.lnana@outlook.com>
34
+ * @param pool The pool.
35
+ */
36
+ export declare const nodePostgresMigrations: (pool: PgPool) => MigrationConnection;
37
+ export {};
@@ -0,0 +1,120 @@
1
+ import type { SQL } from 'drizzle-orm';
2
+ import { Service } from '@elysiumjs/olympus';
3
+ /**
4
+ * Where `migration:run` runs SQL: a transaction, or the connection outside of one. Every driver
5
+ * gives one through `DrizzleDriver.migrations()`.
6
+ * @author Axel Nana <ax.lnana@outlook.com>
7
+ */
8
+ export interface MigrationDatabase {
9
+ /**
10
+ * Runs one statement, with its parameters.
11
+ * @param query The statement, from the `sql` template of Drizzle.
12
+ * @returns The rows of the statement.
13
+ */
14
+ execute<T = Record<string, unknown>>(query: SQL): Promise<T[]>;
15
+ /**
16
+ * Runs a script of several statements, without parameters, such as a migration file.
17
+ * @param text The script.
18
+ */
19
+ script(text: string): Promise<void>;
20
+ }
21
+ /**
22
+ * The connection `migration:run` works on, from the driver of a Drizzle connection.
23
+ * @author Axel Nana <ax.lnana@outlook.com>
24
+ */
25
+ export interface MigrationConnection extends MigrationDatabase {
26
+ /**
27
+ * Runs a function in a transaction, committed when it resolves and rolled back when it
28
+ * throws.
29
+ * @param fn Receives the transaction.
30
+ */
31
+ transaction<T>(fn: (db: MigrationDatabase) => Promise<T>): Promise<T>;
32
+ }
33
+ /**
34
+ * A run of `migration:run`, as its hooks see it.
35
+ * @author Axel Nana <ax.lnana@outlook.com>
36
+ */
37
+ export type MigrationRun = {
38
+ /** The transaction of the run. */
39
+ readonly db: MigrationDatabase;
40
+ /** The tenant the migrations run in: the schema set as `search_path`. */
41
+ readonly tenant: string;
42
+ /** The name of the connection the migrations run on. */
43
+ readonly connection: string;
44
+ /** The batch number of the migrations applied by this run. */
45
+ readonly batch: number;
46
+ /** The names of the migrations this run applies, in order. Empty when none is pending. */
47
+ readonly pending: readonly string[];
48
+ /** The names of the migrations applied so far by this run, in order. */
49
+ readonly applied: readonly string[];
50
+ };
51
+ /**
52
+ * One migration of a run, as the hooks see it.
53
+ * @author Axel Nana <ax.lnana@outlook.com>
54
+ */
55
+ export type MigrationStep = {
56
+ /** The transaction of the run. */
57
+ readonly db: MigrationDatabase;
58
+ /** The name of the migration. */
59
+ readonly name: string;
60
+ /** The absolute path of the migration file. */
61
+ readonly path: string;
62
+ /** The run the migration is part of. */
63
+ readonly run: MigrationRun;
64
+ };
65
+ /**
66
+ * Runs SQL around the migrations of `migration:run`, inside its transaction and after its lock:
67
+ * what fails rolls the whole run back. Every method is optional.
68
+ * @author Axel Nana <ax.lnana@outlook.com>
69
+ */
70
+ export interface MigrationHook {
71
+ /**
72
+ * Runs before the pending migrations, once the tenant schema and the migrations table exist.
73
+ * @param run The run.
74
+ */
75
+ before?(run: MigrationRun): Promise<void> | void;
76
+ /**
77
+ * Runs before each migration.
78
+ * @param step The migration about to be applied.
79
+ */
80
+ beforeEach?(step: MigrationStep): Promise<void> | void;
81
+ /**
82
+ * Runs after each migration, once it is recorded, before the next one.
83
+ * @param step The migration just applied.
84
+ */
85
+ afterEach?(step: MigrationStep): Promise<void> | void;
86
+ /**
87
+ * Runs after the pending migrations, also when there is none.
88
+ * @param run The run.
89
+ */
90
+ after?(run: MigrationRun): Promise<void> | void;
91
+ }
92
+ /**
93
+ * Migrations: the hooks that `migration:run` calls around them.
94
+ * @author Axel Nana <ax.lnana@outlook.com>
95
+ */
96
+ export declare namespace Migration {
97
+ /**
98
+ * The tag of the migration hooks.
99
+ */
100
+ const Hooks: import("@elysiumjs/olympus").ServiceTag<MigrationHook>;
101
+ /**
102
+ * Registers a service as a migration hook. Hooks run in the order the modules register them,
103
+ * for every tenant: read `run.tenant` to act on some of them only.
104
+ * @example
105
+ * ```ts
106
+ * @Migration.hook()
107
+ * export class GrantsHook implements MigrationHook {
108
+ * public async after({ db, tenant }: MigrationRun) {
109
+ * await db.execute(sql`GRANT USAGE ON SCHEMA ${sql.identifier(tenant)} TO app`);
110
+ * }
111
+ * }
112
+ * ```
113
+ * @author Axel Nana <ax.lnana@outlook.com>
114
+ * @param props The service options.
115
+ */
116
+ const hook: (props?: Parameters<typeof Service.register>[0]) => (target: {
117
+ new (...arguments_: any[]): any;
118
+ prototype: Pick<any, string | number | symbol>;
119
+ }) => void;
120
+ }
@@ -0,0 +1,45 @@
1
+ /** A migration recorded as applied in `elysium_migrations`. */
2
+ export type AppliedMigration = {
3
+ name: string;
4
+ appliedAt: Date;
5
+ };
6
+ /** The migrations to run, and the applied records to rename to their new names. */
7
+ export type MigrationPlan = {
8
+ pending: string[];
9
+ renames: {
10
+ from: string;
11
+ to: string;
12
+ }[];
13
+ };
14
+ /**
15
+ * Gets the name under which a migration file is tracked. Drizzle Kit 1.0 stores each migration
16
+ * as `<folder>/migration.sql`, in which case the folder name identifies the migration.
17
+ * @author Axel Nana <ax.lnana@outlook.com>
18
+ * @param path The path of the migration file.
19
+ */
20
+ export declare const getMigrationName: (path: string) => string;
21
+ /**
22
+ * Decides which migration files to run.
23
+ *
24
+ * `drizzle-kit up` moves each flat `<prefix>_<name>.sql` file into a
25
+ * `<timestamp>_<name>/migration.sql` folder, where the timestamp is when the migration was
26
+ * generated. An applied record whose flat file is gone is matched, in order, to a folder with
27
+ * the same `<name>` generated before the record was applied; that folder is not run again and
28
+ * the record is renamed. Folders generated later are new migrations and run.
29
+ * @author Axel Nana <ax.lnana@outlook.com>
30
+ * @param files The paths of the migration files.
31
+ * @param applied The applied migrations.
32
+ */
33
+ export declare const planMigrations: (files: string[], applied: AppliedMigration[]) => MigrationPlan;
34
+ /**
35
+ * Removes the `"public".` qualifier Drizzle Kit writes before identifiers, so that a migration
36
+ * runs in the schema selected by the `search_path` (the tenant schema).
37
+ *
38
+ * Only identifier qualifiers are changed: string literals, dollar-quoted bodies (functions, `DO`
39
+ * blocks), comments and other quoted identifiers are kept as is. Qualifiers inside a `DO` block
40
+ * are therefore kept: such blocks are not rewritten, since their contents are not parsed here.
41
+ * @author Axel Nana <ax.lnana@outlook.com>
42
+ * @param sql The migration SQL.
43
+ * @returns The SQL without the public schema qualifiers.
44
+ */
45
+ export declare const stripPublicSchema: (sql: string) => string;
@@ -0,0 +1,62 @@
1
+ import type { ModelAdapter } from '@elysiumjs/olympus/mnemosyne';
2
+ import type { PgTable, PgTableWithColumns } from 'drizzle-orm/pg-core';
3
+ /**
4
+ * Drizzle-specific model adapter.
5
+ *
6
+ * Bridges Drizzle's `PgTableWithColumns` to the framework's
7
+ * normalized model metadata.
8
+ *
9
+ * @author Axel Nana <ax.lnana@outlook.com>
10
+ */
11
+ export declare const drizzleAdapter: ModelAdapter<PgTableWithColumns<any>>;
12
+ /**
13
+ * Creates Elysia validation schemas from a Drizzle table.
14
+ *
15
+ * This is a convenience wrapper around `createSchemaFromModel` that
16
+ * automatically extracts column metadata via the `drizzleAdapter`.
17
+ *
18
+ * @author Axel Nana <ax.lnana@outlook.com>
19
+ * @param table The Drizzle table to generate schemas for.
20
+ * @param opts Schema generation options.
21
+ * @returns An Elysia validation schema.
22
+ */
23
+ export declare const createSchemaFromDrizzle: (table: PgTableWithColumns<any>, opts?: {
24
+ mode?: 'create' | 'update' | 'select';
25
+ }) => import("typebox").TObject<{}>;
26
+ /**
27
+ * Options for creating a DrizzleModel.
28
+ */
29
+ export interface DrizzleModelOptions {
30
+ /**
31
+ * Enable tenant schema support for this model.
32
+ * @default false
33
+ */
34
+ supportTenancy?: boolean;
35
+ }
36
+ /**
37
+ * Creates a model class backed by a Drizzle pgTable.
38
+ *
39
+ * @author Axel Nana <ax.lnana@outlook.com>
40
+ * @param table The Drizzle table (created with enhanced pgTable).
41
+ * @param options Model configuration options.
42
+ * @returns A model class with Drizzle-backed static metadata.
43
+ */
44
+ export declare const DrizzleModel: <TTable extends PgTable>(table: TTable, options?: DrizzleModelOptions) => {
45
+ new (): {};
46
+ readonly $inferSelect: unknown;
47
+ readonly $inferInsert: unknown;
48
+ readonly $inferUpdate: unknown;
49
+ readonly table: TTable;
50
+ readonly tableName: string;
51
+ readonly columns: Record<string, import("drizzle-orm/pg-core").AnyPgColumnBuilder>;
52
+ readonly insertSchema: import("typebox").TObject<{}>;
53
+ readonly updateSchema: import("typebox").TObject<{}>;
54
+ readonly selectSchema: import("typebox").TObject<{}>;
55
+ readonly supportTenancy: boolean;
56
+ readonly adapter: ModelAdapter<TTable>;
57
+ } & {
58
+ readonly $inferSelect: { [Key in keyof TTable["_"]["columns"] & string]: TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null; } extends infer T ? { [K in keyof T]: T[K]; } : never;
59
+ readonly $inferInsert: { [Key in keyof TTable["_"]["columns"] & string as import("drizzle-orm").RequiredKeyOnly<Key, TTable["_"]["columns"][Key]>]: TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null; } & { [Key in keyof TTable["_"]["columns"] & string as import("drizzle-orm").OptionalKeyOnly<Key, TTable["_"]["columns"][Key], false>]?: (TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null) | undefined; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never;
60
+ readonly $inferUpdate: Partial<{ [Key in keyof TTable["_"]["columns"] & string as import("drizzle-orm").RequiredKeyOnly<Key, TTable["_"]["columns"][Key]>]: TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null; } & { [Key in keyof TTable["_"]["columns"] & string as import("drizzle-orm").OptionalKeyOnly<Key, TTable["_"]["columns"][Key], false>]?: (TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null) | undefined; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
61
+ readonly table: TTable;
62
+ };