@elysiumjs/mnemosyne-drizzle 0.2.0 → 0.4.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/cache.d.ts +60 -0
  3. package/dist/commands/migration_run.command.d.ts +13 -0
  4. package/dist/commands/project.d.ts +11 -0
  5. package/dist/database.d.ts +82 -31
  6. package/dist/driver.d.ts +39 -0
  7. package/dist/drivers/bun-sql.d.ts +25 -0
  8. package/dist/drivers/bun-sql.js +1 -0
  9. package/dist/drivers/hyperdrive.d.ts +46 -0
  10. package/dist/drivers/hyperdrive.js +1 -0
  11. package/dist/drivers/node-postgres.d.ts +23 -0
  12. package/dist/drivers/node-postgres.js +1 -0
  13. package/dist/drivers/postgres-js.d.ts +25 -0
  14. package/dist/drivers/postgres-js.js +1 -0
  15. package/dist/drizzle.module.d.ts +3 -3
  16. package/dist/index.d.ts +5 -3
  17. package/dist/index.js +11 -1
  18. package/dist/migrations.d.ts +12 -0
  19. package/dist/model.d.ts +9 -9
  20. package/dist/query.d.ts +28 -0
  21. package/dist/repository.d.ts +34 -6
  22. package/dist/tenancy.d.ts +25 -8
  23. package/package.json +63 -11
  24. package/.omc/state/agent-replay-3920b579-6d8e-4f5f-924a-319202936685.jsonl +0 -7
  25. package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/last-tool-error-state.json +0 -7
  26. package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/mission-state.json +0 -93
  27. package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/pre-tool-advisory-throttle.json +0 -18
  28. package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/subagent-tracking-state.json +0 -61
  29. package/.turbo/turbo-build.log +0 -3
  30. package/dist/commands/migration_generate.command.js +0 -1
  31. package/dist/commands/migration_run.command.js +0 -15
  32. package/dist/database.js +0 -1
  33. package/dist/drizzle.module.js +0 -1
  34. package/dist/migrations.js +0 -1
  35. package/dist/model.js +0 -1
  36. package/dist/repository.js +0 -1
  37. package/dist/table.js +0 -1
  38. package/dist/tenancy.js +0 -1
  39. package/scripts/minify.ts +0 -10
  40. package/src/commands/migration_generate.command.ts +0 -101
  41. package/src/commands/migration_run.command.ts +0 -160
  42. package/src/database.ts +0 -205
  43. package/src/drizzle.module.ts +0 -97
  44. package/src/index.ts +0 -47
  45. package/src/migrations.ts +0 -100
  46. package/src/model.ts +0 -178
  47. package/src/repository.ts +0 -113
  48. package/src/table.ts +0 -70
  49. package/src/tenancy.ts +0 -249
  50. package/tests/drizzle.module.test.ts +0 -201
  51. package/tests/migrations.test.ts +0 -123
  52. package/tests/model.test.ts +0 -362
  53. package/tests/setup.ts +0 -0
  54. package/tests/table.test.ts +0 -72
  55. package/tests/tenancy.test.ts +0 -212
  56. package/tsconfig.json +0 -12
package/src/index.ts DELETED
@@ -1,47 +0,0 @@
1
- // Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- // Re-export drizzle-orm/pg-core with enhanced pgTable
16
- export * from 'drizzle-orm';
17
- export * from 'drizzle-orm/pg-core';
18
- export type {
19
- SelectedFields,
20
- SelectedFieldsFlat,
21
- SelectedFieldsOrdered,
22
- TableConfig
23
- } from 'drizzle-orm/pg-core';
24
- export { pgTable, getTableBuilders } from './table';
25
-
26
- // Re-exports
27
- export { Database, DrizzleDatabaseCache } from './database';
28
- export type { DrizzleConnectionProps, DrizzleConnection } from './database';
29
- export {
30
- DrizzleModel,
31
- createSchemaFromDrizzle,
32
- drizzleAdapter,
33
- type DrizzleModelOptions
34
- } from './model';
35
- export { DrizzleModule, type DrizzleModuleConfig } from './drizzle.module';
36
- export { DrizzleRepository } from './repository';
37
- export {
38
- DrizzleSchemaTenancy,
39
- DrizzleRLSTenancy,
40
- wrapTenantSchema,
41
- registerTenantSchema,
42
- getTenantSchema,
43
- withRLS,
44
- setConnectionTenant,
45
- getSessionTenant,
46
- createRLSPolicy
47
- } from './tenancy';
package/src/migrations.ts DELETED
@@ -1,100 +0,0 @@
1
- // Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import { basename, dirname } from 'node:path';
16
-
17
- /** A migration recorded as applied in `elysium_migrations`. */
18
- export type AppliedMigration = {
19
- name: string;
20
- appliedAt: Date;
21
- };
22
-
23
- /** The migrations to run, and the applied records to rename to their new names. */
24
- export type MigrationPlan = {
25
- pending: string[];
26
- renames: { from: string; to: string }[];
27
- };
28
-
29
- const FOLDER_MIGRATION_FILE = 'migration.sql';
30
-
31
- /**
32
- * Gets the name under which a migration file is tracked. Drizzle Kit 1.0 stores each migration
33
- * as `<folder>/migration.sql`, in which case the folder name identifies the migration.
34
- * @author Axel Nana <axel.nana@workbud.com>
35
- * @param path The path of the migration file.
36
- */
37
- export const getMigrationName = (path: string): string =>
38
- basename(path) === FOLDER_MIGRATION_FILE ? basename(dirname(path)) : basename(path);
39
-
40
- /** Drops the `.sql` extension and the leading index or timestamp: `0001_users.sql` → `users`. */
41
- const descriptiveName = (name: string): string =>
42
- name
43
- .replace(/\.sql$/, '')
44
- .split('_')
45
- .slice(1)
46
- .join('_');
47
-
48
- /** Reads the UTC `YYYYMMDDHHmmss` timestamp that starts a Drizzle Kit 1.0 folder name. */
49
- const folderTime = (name: string): number | undefined => {
50
- const match = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/.exec(name);
51
- return match
52
- ? Date.UTC(+match[1]!, +match[2]! - 1, +match[3]!, +match[4]!, +match[5]!, +match[6]!)
53
- : undefined;
54
- };
55
-
56
- /**
57
- * Decides which migration files to run.
58
- *
59
- * `drizzle-kit up` moves each flat `<prefix>_<name>.sql` file into a
60
- * `<timestamp>_<name>/migration.sql` folder, where the timestamp is when the migration was
61
- * generated. An applied record whose flat file is gone is matched, in order, to a folder with
62
- * the same `<name>` generated before the record was applied; that folder is not run again and
63
- * the record is renamed. Folders generated later are new migrations and run.
64
- * @author Axel Nana <axel.nana@workbud.com>
65
- * @param files The paths of the migration files.
66
- * @param applied The applied migrations.
67
- */
68
- export const planMigrations = (files: string[], applied: AppliedMigration[]): MigrationPlan => {
69
- const appliedNames = new Set(applied.map(({ name }) => name));
70
- const fileNames = new Set(files.map(getMigrationName));
71
-
72
- const moved = new Map<string, AppliedMigration[]>();
73
- for (const record of [...applied].sort((a, b) => a.name.localeCompare(b.name))) {
74
- if (!record.name.endsWith('.sql') || fileNames.has(record.name)) continue;
75
- const key = descriptiveName(record.name);
76
- moved.set(key, [...(moved.get(key) ?? []), record]);
77
- }
78
-
79
- const plan: MigrationPlan = { pending: [], renames: [] };
80
- for (const file of [...files].sort()) {
81
- const name = getMigrationName(file);
82
- if (appliedNames.has(name)) continue;
83
-
84
- const from = basename(file) === FOLDER_MIGRATION_FILE ? takeMoved(moved, name) : undefined;
85
- if (from) plan.renames.push({ from, to: name });
86
- else plan.pending.push(file);
87
- }
88
- return plan;
89
- };
90
-
91
- /** Removes and returns the first moved record that the folder `name` can be the new home of. */
92
- const takeMoved = (moved: Map<string, AppliedMigration[]>, name: string): string | undefined => {
93
- const records = moved.get(descriptiveName(name));
94
- const generatedAt = folderTime(name);
95
- const index =
96
- records?.findIndex(
97
- ({ appliedAt }) => generatedAt === undefined || generatedAt <= appliedAt.getTime()
98
- ) ?? -1;
99
- return index < 0 ? undefined : records!.splice(index, 1)[0]!.name;
100
- };
package/src/model.ts DELETED
@@ -1,178 +0,0 @@
1
- // Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import type { ColumnMetadata, ModelAdapter } from '@elysiumjs/mnemosyne';
16
- import type { PgColumn, PgTableWithColumns, TableConfig } from 'drizzle-orm/pg-core';
17
-
18
- import { AbstractModel, createSchemaFromModel } from '@elysiumjs/mnemosyne';
19
- import { getTableConfig } from 'drizzle-orm/pg-core';
20
-
21
- import { getTableBuilders } from './table';
22
- import { wrapTenantSchema } from './tenancy';
23
-
24
- // ============================================================================
25
- // Column Type Mapping
26
- // ============================================================================
27
-
28
- /**
29
- * Maps a Drizzle column to a normalized data type.
30
- * @param col The Drizzle column to inspect.
31
- * @returns A normalized data type string.
32
- */
33
- const mapDrizzleDataType = (col: PgColumn): ColumnMetadata['dataType'] => {
34
- if (col.columnType === 'PgUUID') return 'uuid';
35
- if ((col as { dimensions?: number }).dimensions) return 'array';
36
-
37
- // Drizzle 1.0 column data types are `<kind>` or `<kind> <constraint>` (e.g. `object json`).
38
- const [kind, constraint] = col.dataType.split(' ');
39
- switch (kind) {
40
- case 'number':
41
- return 'number';
42
- case 'boolean':
43
- return 'boolean';
44
- case 'array':
45
- return 'array';
46
- case 'bigint':
47
- return 'bigint';
48
- case 'object':
49
- switch (constraint) {
50
- case 'json':
51
- return 'json';
52
- case 'date':
53
- return 'date';
54
- case 'buffer':
55
- return 'buffer';
56
- default:
57
- return 'string';
58
- }
59
- default:
60
- return 'string';
61
- }
62
- };
63
-
64
- // ============================================================================
65
- // Drizzle Model Adapter
66
- // ============================================================================
67
-
68
- /**
69
- * Drizzle-specific model adapter.
70
- *
71
- * Bridges Drizzle's `PgTableWithColumns` to the framework's
72
- * normalized model metadata.
73
- *
74
- * @author Axel Nana <axel.nana@workbud.com>
75
- */
76
- export const drizzleAdapter: ModelAdapter<PgTableWithColumns<any>> = {
77
- getTableName(table) {
78
- return getTableConfig(table).name;
79
- },
80
-
81
- getColumns(table): ColumnMetadata[] {
82
- const config = getTableConfig(table);
83
- return config.columns.map((col: PgColumn) => ({
84
- name: col.name,
85
- dataType: mapDrizzleDataType(col),
86
- nullable: !col.notNull,
87
- hasDefault: col.hasDefault,
88
- isPrimaryKey:
89
- col.primary || config.primaryKeys.some((pk) => pk.columns.some((c) => c.name === col.name))
90
- }));
91
- },
92
-
93
- createTenantTable(table, tenant) {
94
- const builders = getTableBuilders(table);
95
- if (!builders) {
96
- throw new Error(
97
- `No column builders registered for table. ` +
98
- `Use pgTable() from '@elysiumjs/mnemosyne-drizzle' for tenant support.`
99
- );
100
- }
101
- const config = getTableConfig(table);
102
- return wrapTenantSchema(tenant, config.name, builders) as PgTableWithColumns<any>;
103
- }
104
- };
105
-
106
- // ============================================================================
107
- // Schema Helper
108
- // ============================================================================
109
-
110
- /**
111
- * Creates Elysia validation schemas from a Drizzle table.
112
- *
113
- * This is a convenience wrapper around `createSchemaFromModel` that
114
- * automatically extracts column metadata via the `drizzleAdapter`.
115
- *
116
- * @author Axel Nana <axel.nana@workbud.com>
117
- * @param table The Drizzle table to generate schemas for.
118
- * @param opts Schema generation options.
119
- * @returns An Elysia validation schema.
120
- */
121
- export const createSchemaFromDrizzle = (
122
- table: PgTableWithColumns<any>,
123
- opts?: { mode?: 'create' | 'update' | 'select' }
124
- ) => {
125
- return createSchemaFromModel(drizzleAdapter.getColumns(table), opts);
126
- };
127
-
128
- // ============================================================================
129
- // DrizzleModel Options
130
- // ============================================================================
131
-
132
- /**
133
- * Options for creating a DrizzleModel.
134
- */
135
- export interface DrizzleModelOptions {
136
- /**
137
- * Enable tenant schema support for this model.
138
- * @default false
139
- */
140
- supportTenancy?: boolean;
141
- }
142
-
143
- // ============================================================================
144
- // DrizzleModel Function
145
- // ============================================================================
146
-
147
- /**
148
- * Creates a model class backed by a Drizzle pgTable.
149
- *
150
- * @author Axel Nana <axel.nana@workbud.com>
151
- * @param table The Drizzle table (created with enhanced pgTable).
152
- * @param options Model configuration options.
153
- * @returns A model class with Drizzle-backed static metadata.
154
- */
155
- export const DrizzleModel = <TTable extends PgTableWithColumns<TableConfig>>(
156
- table: TTable,
157
- options?: DrizzleModelOptions
158
- ) => {
159
- const config = getTableConfig(table);
160
- const builders = getTableBuilders(table);
161
-
162
- type TSelect = TTable['$inferSelect'];
163
- type TInsert = TTable['$inferInsert'];
164
-
165
- const Base = AbstractModel(config.name, builders ?? {}, drizzleAdapter, table);
166
-
167
- // Override supportTenancy if specified
168
- if (options?.supportTenancy !== undefined) {
169
- (Base as any).supportTenancy = options.supportTenancy;
170
- }
171
-
172
- return Base as typeof Base & {
173
- readonly $inferSelect: TSelect;
174
- readonly $inferInsert: TInsert;
175
- readonly $inferUpdate: Partial<TInsert>;
176
- readonly table: TTable;
177
- };
178
- };
package/src/repository.ts DELETED
@@ -1,113 +0,0 @@
1
- // Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import type { IdType, ModelClass } from '@elysiumjs/mnemosyne';
16
- import type { PgTableWithColumns } from 'drizzle-orm/pg-core';
17
- import type { DrizzleConnection } from './database';
18
-
19
- import { AbstractRepository } from '@elysiumjs/mnemosyne';
20
- import { eq } from 'drizzle-orm';
21
-
22
- import { Database } from './database';
23
-
24
- // ============================================================================
25
- // DrizzleRepository Mixin
26
- // ============================================================================
27
-
28
- /**
29
- * Drizzle-specific repository mixin with concrete CRUD operations.
30
- *
31
- * Extends the abstract repository with Drizzle query builder calls
32
- * for all standard CRUD methods.
33
- *
34
- * @author Axel Nana <axel.nana@workbud.com>
35
- * @template TModel The model class type.
36
- * @param model The model class to create the repository for.
37
- * @returns A concrete repository class with CRUD methods.
38
- */
39
- export const DrizzleRepository = <
40
- TModel extends ModelClass<any, any, any, PgTableWithColumns<any>>
41
- >(
42
- model: TModel
43
- ) => {
44
- type TSelect = TModel['$inferSelect'];
45
- type TInsert = TModel['$inferInsert'];
46
- type TUpdate = TModel['$inferUpdate'];
47
-
48
- class R extends AbstractRepository<TModel, DrizzleConnection>(model, Database) {
49
- public async all(): Promise<TSelect[]> {
50
- return await this.db.select().from(model.table);
51
- }
52
-
53
- public async paginate(
54
- count: number,
55
- page: number = 1
56
- ): Promise<{ page: number; data: TSelect[]; total: number }> {
57
- const total = await this.db.$count(model.table);
58
- const offset = Math.max(page - 1, 0) * count;
59
- return {
60
- page,
61
- total,
62
- data: await this.db.select().from(model.table).offset(offset).limit(count)
63
- };
64
- }
65
-
66
- public async find(id: IdType): Promise<TSelect | null> {
67
- const [row] = await this.db.select().from(model.table).where(eq(model.table.id, id));
68
- return (row ?? null) as TSelect | null;
69
- }
70
-
71
- public async findBy<TKey extends keyof TSelect>(
72
- column: TKey,
73
- value: TSelect[TKey]
74
- ): Promise<TSelect | null> {
75
- const [row] = await this.db.select().from(model.table).where(eq(model.table[column], value));
76
- return (row ?? null) as TSelect | null;
77
- }
78
-
79
- public async insert(data: TInsert): Promise<TSelect> {
80
- const [row] = await this.db.insert(model.table).values(data).returning();
81
- return row as TSelect;
82
- }
83
-
84
- public async update(id: IdType, data: TUpdate): Promise<TSelect> {
85
- const [row] = await this.db
86
- .update(model.table)
87
- .set(data)
88
- .where(eq(model.table.id, id))
89
- .returning();
90
- return row as TSelect;
91
- }
92
-
93
- public async updateAll(data: TUpdate): Promise<TSelect[]> {
94
- return await this.db.update(model.table).set(data).returning();
95
- }
96
-
97
- public async delete(id: IdType): Promise<TSelect> {
98
- const [row] = await this.db.delete(model.table).where(eq(model.table.id, id)).returning();
99
- return row as TSelect;
100
- }
101
-
102
- public async deleteAll(): Promise<TSelect[]> {
103
- return await this.db.delete(model.table).returning();
104
- }
105
-
106
- public async exists(id: IdType): Promise<boolean> {
107
- const count = await this.db.$count(model.table, eq(model.table.id, id));
108
- return count > 0;
109
- }
110
- }
111
-
112
- return R;
113
- };
package/src/table.ts DELETED
@@ -1,70 +0,0 @@
1
- // Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import type { AnyPgColumnBuilder, PgTableWithColumns } from 'drizzle-orm/pg-core';
16
-
17
- import { pgTable as drizzlePgTable } from 'drizzle-orm/pg-core';
18
-
19
- // ============================================================================
20
- // Column Builder Registry
21
- // ============================================================================
22
-
23
- /**
24
- * Maps tables to their original column builder definitions.
25
- *
26
- * When `pgTable()` is called, column builders are consumed and turned into
27
- * built `PgColumn` instances. This registry preserves the original builder
28
- * objects so that tenant tables can be re-created in different schemas.
29
- */
30
- const tableRegistry = new WeakMap<PgTableWithColumns<any>, Record<string, AnyPgColumnBuilder>>();
31
-
32
- /**
33
- * Retrieves the original column builders for a table.
34
- * @param table The table created with enhanced pgTable.
35
- * @returns The original column builder definitions, or `undefined`.
36
- */
37
- export const getTableBuilders = (
38
- table: PgTableWithColumns<any>
39
- ): Record<string, AnyPgColumnBuilder> | undefined => {
40
- return tableRegistry.get(table);
41
- };
42
-
43
- // ============================================================================
44
- // Enhanced pgTable Function
45
- // ============================================================================
46
-
47
- /**
48
- * Creates a PostgreSQL table with automatic column builder registration.
49
- *
50
- * This is an enhanced version of Drizzle's `pgTable` that automatically
51
- * registers column builders for tenancy support. It has the exact same
52
- * signature and behavior as the original.
53
- *
54
- * @param tableName The name of the database table.
55
- * @param columns The column definitions.
56
- * @param extraConfig Optional extra Drizzle table configuration.
57
- * @returns A Drizzle PostgreSQL table with registered column builders.
58
- */
59
- export const pgTable = <
60
- TTableName extends string,
61
- TColumns extends Record<string, AnyPgColumnBuilder>
62
- >(
63
- tableName: TTableName,
64
- columns: TColumns,
65
- extraConfig?: (table: any) => any
66
- ) => {
67
- const table = drizzlePgTable(tableName, columns, extraConfig);
68
- tableRegistry.set(table, columns);
69
- return table;
70
- };