metal-orm 1.0.14 → 1.0.16

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 (129) hide show
  1. package/README.md +69 -67
  2. package/dist/decorators/index.cjs +1983 -224
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -6
  5. package/dist/decorators/index.d.ts +6 -6
  6. package/dist/decorators/index.js +1982 -224
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +5284 -3751
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +524 -169
  11. package/dist/index.d.ts +524 -169
  12. package/dist/index.js +5197 -3736
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-BKZrMRCQ.d.cts} +555 -94
  15. package/dist/{select-CCp1oz9p.d.ts → select-BKZrMRCQ.d.ts} +555 -94
  16. package/package.json +1 -1
  17. package/src/codegen/naming-strategy.ts +64 -0
  18. package/src/codegen/typescript.ts +19 -21
  19. package/src/core/ast/adapters.ts +21 -0
  20. package/src/core/ast/aggregate-functions.ts +13 -13
  21. package/src/core/ast/builders.ts +56 -43
  22. package/src/core/ast/expression-builders.ts +34 -34
  23. package/src/core/ast/expression-nodes.ts +18 -16
  24. package/src/core/ast/expression-visitor.ts +122 -69
  25. package/src/core/ast/expression.ts +6 -4
  26. package/src/core/ast/join-metadata.ts +15 -0
  27. package/src/core/ast/join-node.ts +22 -20
  28. package/src/core/ast/join.ts +5 -5
  29. package/src/core/ast/query.ts +52 -88
  30. package/src/core/ast/types.ts +20 -0
  31. package/src/core/ast/window-functions.ts +55 -55
  32. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  33. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  34. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  35. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  36. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  37. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  38. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  39. package/src/core/ddl/introspect/context.ts +9 -0
  40. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  41. package/src/core/ddl/introspect/mssql.ts +149 -149
  42. package/src/core/ddl/introspect/mysql.ts +99 -99
  43. package/src/core/ddl/introspect/postgres.ts +245 -154
  44. package/src/core/ddl/introspect/registry.ts +26 -0
  45. package/src/core/ddl/introspect/run-select.ts +25 -0
  46. package/src/core/ddl/introspect/sqlite.ts +7 -7
  47. package/src/core/ddl/introspect/types.ts +23 -19
  48. package/src/core/ddl/introspect/utils.ts +1 -1
  49. package/src/core/ddl/naming-strategy.ts +10 -0
  50. package/src/core/ddl/schema-dialect.ts +41 -0
  51. package/src/core/ddl/schema-diff.ts +211 -179
  52. package/src/core/ddl/schema-generator.ts +17 -90
  53. package/src/core/ddl/schema-introspect.ts +25 -32
  54. package/src/core/ddl/schema-plan-executor.ts +17 -0
  55. package/src/core/ddl/schema-types.ts +46 -39
  56. package/src/core/ddl/sql-writing.ts +170 -0
  57. package/src/core/dialect/abstract.ts +172 -126
  58. package/src/core/dialect/base/cte-compiler.ts +33 -0
  59. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  60. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  61. package/src/core/dialect/base/join-compiler.ts +26 -0
  62. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  63. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  64. package/src/core/dialect/base/returning-strategy.ts +56 -0
  65. package/src/core/dialect/base/sql-dialect.ts +181 -204
  66. package/src/core/dialect/dialect-factory.ts +91 -0
  67. package/src/core/dialect/mssql/functions.ts +101 -0
  68. package/src/core/dialect/mssql/index.ts +128 -126
  69. package/src/core/dialect/mysql/functions.ts +101 -0
  70. package/src/core/dialect/mysql/index.ts +20 -18
  71. package/src/core/dialect/postgres/functions.ts +95 -0
  72. package/src/core/dialect/postgres/index.ts +30 -28
  73. package/src/core/dialect/sqlite/functions.ts +115 -0
  74. package/src/core/dialect/sqlite/index.ts +30 -28
  75. package/src/core/driver/database-driver.ts +11 -0
  76. package/src/core/driver/mssql-driver.ts +20 -0
  77. package/src/core/driver/mysql-driver.ts +20 -0
  78. package/src/core/driver/postgres-driver.ts +20 -0
  79. package/src/core/driver/sqlite-driver.ts +20 -0
  80. package/src/core/execution/db-executor.ts +63 -0
  81. package/src/core/execution/executors/mssql-executor.ts +39 -0
  82. package/src/core/execution/executors/mysql-executor.ts +47 -0
  83. package/src/core/execution/executors/postgres-executor.ts +32 -0
  84. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  85. package/src/core/functions/datetime.ts +132 -0
  86. package/src/core/functions/numeric.ts +179 -0
  87. package/src/core/functions/standard-strategy.ts +47 -0
  88. package/src/core/functions/text.ts +147 -0
  89. package/src/core/functions/types.ts +18 -0
  90. package/src/core/hydration/types.ts +57 -0
  91. package/src/decorators/bootstrap.ts +10 -0
  92. package/src/decorators/column.ts +13 -4
  93. package/src/decorators/relations.ts +15 -0
  94. package/src/index.ts +37 -19
  95. package/src/orm/entity-context.ts +30 -0
  96. package/src/orm/entity-meta.ts +2 -2
  97. package/src/orm/entity-metadata.ts +8 -6
  98. package/src/orm/entity.ts +72 -41
  99. package/src/orm/execute.ts +42 -25
  100. package/src/orm/execution-context.ts +12 -0
  101. package/src/orm/hydration-context.ts +14 -0
  102. package/src/orm/hydration.ts +25 -17
  103. package/src/orm/identity-map.ts +4 -0
  104. package/src/orm/interceptor-pipeline.ts +29 -0
  105. package/src/orm/lazy-batch.ts +50 -6
  106. package/src/orm/orm-session.ts +234 -0
  107. package/src/orm/orm.ts +58 -0
  108. package/src/orm/query-logger.ts +1 -1
  109. package/src/orm/relation-change-processor.ts +48 -3
  110. package/src/orm/relations/belongs-to.ts +45 -44
  111. package/src/orm/relations/has-many.ts +44 -43
  112. package/src/orm/relations/has-one.ts +140 -0
  113. package/src/orm/relations/many-to-many.ts +46 -45
  114. package/src/orm/transaction-runner.ts +1 -1
  115. package/src/orm/unit-of-work.ts +66 -61
  116. package/src/query-builder/delete.ts +22 -5
  117. package/src/query-builder/hydration-manager.ts +2 -1
  118. package/src/query-builder/hydration-planner.ts +8 -7
  119. package/src/query-builder/insert.ts +22 -5
  120. package/src/query-builder/relation-conditions.ts +9 -8
  121. package/src/query-builder/relation-service.ts +3 -2
  122. package/src/query-builder/select.ts +575 -64
  123. package/src/query-builder/update.ts +22 -5
  124. package/src/schema/column.ts +246 -246
  125. package/src/schema/relation.ts +35 -1
  126. package/src/schema/table.ts +28 -28
  127. package/src/schema/types.ts +41 -31
  128. package/src/orm/db-executor.ts +0 -11
  129. package/src/orm/orm-context.ts +0 -159
@@ -1,149 +1,149 @@
1
- import { SchemaIntrospector, IntrospectOptions } from './types.js';
2
- import { queryRows, shouldIncludeTable } from './utils.js';
3
- import { DatabaseSchema, DatabaseTable, DatabaseIndex, DatabaseColumn } from '../schema-types.js';
4
- import { DbExecutor } from '../../orm/db-executor.js';
5
-
6
- export const mssqlIntrospector: SchemaIntrospector = {
7
- async introspect(executor: DbExecutor, options: IntrospectOptions): Promise<DatabaseSchema> {
8
- const schema = options.schema;
9
- const filterSchema = schema ? 'sch.name = @p1' : '1=1';
10
- const params = schema ? [schema] : [];
11
-
12
- const columnRows = await queryRows(
13
- executor,
14
- `
15
- SELECT
16
- sch.name AS table_schema,
17
- t.name AS table_name,
18
- c.name AS column_name,
19
- ty.name AS data_type,
20
- c.is_nullable,
21
- c.is_identity,
22
- object_definition(c.default_object_id) AS column_default
23
- FROM sys.columns c
24
- JOIN sys.tables t ON t.object_id = c.object_id
25
- JOIN sys.schemas sch ON sch.schema_id = t.schema_id
26
- JOIN sys.types ty ON ty.user_type_id = c.user_type_id
27
- WHERE t.is_ms_shipped = 0 AND ${filterSchema}
28
- `,
29
- params
30
- );
31
-
32
- const pkRows = await queryRows(
33
- executor,
34
- `
35
- SELECT
36
- sch.name AS table_schema,
37
- t.name AS table_name,
38
- c.name AS column_name,
39
- ic.key_ordinal
40
- FROM sys.indexes i
41
- JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
42
- JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
43
- JOIN sys.tables t ON t.object_id = i.object_id
44
- JOIN sys.schemas sch ON sch.schema_id = t.schema_id
45
- WHERE i.is_primary_key = 1 AND ${filterSchema}
46
- ORDER BY ic.key_ordinal
47
- `,
48
- params
49
- );
50
-
51
- const pkMap = new Map<string, string[]>();
52
- pkRows.forEach(r => {
53
- const key = `${r.table_schema}.${r.table_name}`;
54
- const list = pkMap.get(key) || [];
55
- list.push(r.column_name);
56
- pkMap.set(key, list);
57
- });
58
-
59
- const indexRows = await queryRows(
60
- executor,
61
- `
62
- SELECT
63
- sch.name AS table_schema,
64
- t.name AS table_name,
65
- i.name AS index_name,
66
- i.is_unique,
67
- i.has_filter,
68
- i.filter_definition
69
- FROM sys.indexes i
70
- JOIN sys.tables t ON t.object_id = i.object_id
71
- JOIN sys.schemas sch ON sch.schema_id = t.schema_id
72
- WHERE i.is_primary_key = 0 AND i.is_hypothetical = 0 AND ${filterSchema}
73
- `,
74
- params
75
- );
76
-
77
- const indexColsRows = await queryRows(
78
- executor,
79
- `
80
- SELECT
81
- sch.name AS table_schema,
82
- t.name AS table_name,
83
- i.name AS index_name,
84
- c.name AS column_name,
85
- ic.key_ordinal
86
- FROM sys.index_columns ic
87
- JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id
88
- JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
89
- JOIN sys.tables t ON t.object_id = i.object_id
90
- JOIN sys.schemas sch ON sch.schema_id = t.schema_id
91
- WHERE i.is_primary_key = 0 AND ${filterSchema}
92
- ORDER BY ic.key_ordinal
93
- `,
94
- params
95
- );
96
-
97
- const indexColumnsMap = new Map<string, { column: string; order: number }[]>();
98
- indexColsRows.forEach(r => {
99
- const key = `${r.table_schema}.${r.table_name}.${r.index_name}`;
100
- const list = indexColumnsMap.get(key) || [];
101
- list.push({ column: r.column_name, order: r.key_ordinal });
102
- indexColumnsMap.set(key, list);
103
- });
104
-
105
- const tablesByKey = new Map<string, DatabaseTable>();
106
-
107
- columnRows.forEach(r => {
108
- if (!shouldIncludeTable(r.table_name, options)) return;
109
- const key = `${r.table_schema}.${r.table_name}`;
110
- if (!tablesByKey.has(key)) {
111
- tablesByKey.set(key, {
112
- name: r.table_name,
113
- schema: r.table_schema,
114
- columns: [],
115
- primaryKey: pkMap.get(key) || [],
116
- indexes: []
117
- });
118
- }
119
- const t = tablesByKey.get(key)!;
120
- const column: DatabaseColumn = {
121
- name: r.column_name,
122
- type: r.data_type,
123
- notNull: r.is_nullable === false || r.is_nullable === 0,
124
- default: r.column_default ?? undefined,
125
- autoIncrement: !!r.is_identity
126
- };
127
- t.columns.push(column);
128
- });
129
-
130
- indexRows.forEach(r => {
131
- const key = `${r.table_schema}.${r.table_name}`;
132
- const table = tablesByKey.get(key);
133
- if (!table) return;
134
- const cols = (indexColumnsMap.get(`${r.table_schema}.${r.table_name}.${r.index_name}`) || [])
135
- .sort((a, b) => a.order - b.order)
136
- .map(c => ({ column: c.column }));
137
- const idx: DatabaseIndex = {
138
- name: r.index_name,
139
- columns: cols,
140
- unique: !!r.is_unique,
141
- where: r.has_filter ? r.filter_definition : undefined
142
- };
143
- table.indexes = table.indexes || [];
144
- table.indexes.push(idx);
145
- });
146
-
147
- return { tables: Array.from(tablesByKey.values()) };
148
- }
149
- };
1
+ import { SchemaIntrospector, IntrospectOptions } from './types.js';
2
+ import { queryRows, shouldIncludeTable } from './utils.js';
3
+ import { DatabaseSchema, DatabaseTable, DatabaseIndex, DatabaseColumn } from '../schema-types.js';
4
+ import { DbExecutor } from '../../execution/db-executor.js';
5
+
6
+ export const mssqlIntrospector: SchemaIntrospector = {
7
+ async introspect(ctx: { executor: DbExecutor }, options: IntrospectOptions): Promise<DatabaseSchema> {
8
+ const schema = options.schema;
9
+ const filterSchema = schema ? 'sch.name = @p1' : '1=1';
10
+ const params = schema ? [schema] : [];
11
+
12
+ const columnRows = await queryRows(
13
+ ctx.executor,
14
+ `
15
+ SELECT
16
+ sch.name AS table_schema,
17
+ t.name AS table_name,
18
+ c.name AS column_name,
19
+ ty.name AS data_type,
20
+ c.is_nullable,
21
+ c.is_identity,
22
+ object_definition(c.default_object_id) AS column_default
23
+ FROM sys.columns c
24
+ JOIN sys.tables t ON t.object_id = c.object_id
25
+ JOIN sys.schemas sch ON sch.schema_id = t.schema_id
26
+ JOIN sys.types ty ON ty.user_type_id = c.user_type_id
27
+ WHERE t.is_ms_shipped = 0 AND ${filterSchema}
28
+ `,
29
+ params
30
+ );
31
+
32
+ const pkRows = await queryRows(
33
+ ctx.executor,
34
+ `
35
+ SELECT
36
+ sch.name AS table_schema,
37
+ t.name AS table_name,
38
+ c.name AS column_name,
39
+ ic.key_ordinal
40
+ FROM sys.indexes i
41
+ JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
42
+ JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
43
+ JOIN sys.tables t ON t.object_id = i.object_id
44
+ JOIN sys.schemas sch ON sch.schema_id = t.schema_id
45
+ WHERE i.is_primary_key = 1 AND ${filterSchema}
46
+ ORDER BY ic.key_ordinal
47
+ `,
48
+ params
49
+ );
50
+
51
+ const pkMap = new Map<string, string[]>();
52
+ pkRows.forEach(r => {
53
+ const key = `${r.table_schema}.${r.table_name}`;
54
+ const list = pkMap.get(key) || [];
55
+ list.push(r.column_name);
56
+ pkMap.set(key, list);
57
+ });
58
+
59
+ const indexRows = await queryRows(
60
+ ctx.executor,
61
+ `
62
+ SELECT
63
+ sch.name AS table_schema,
64
+ t.name AS table_name,
65
+ i.name AS index_name,
66
+ i.is_unique,
67
+ i.has_filter,
68
+ i.filter_definition
69
+ FROM sys.indexes i
70
+ JOIN sys.tables t ON t.object_id = i.object_id
71
+ JOIN sys.schemas sch ON sch.schema_id = t.schema_id
72
+ WHERE i.is_primary_key = 0 AND i.is_hypothetical = 0 AND ${filterSchema}
73
+ `,
74
+ params
75
+ );
76
+
77
+ const indexColsRows = await queryRows(
78
+ ctx.executor,
79
+ `
80
+ SELECT
81
+ sch.name AS table_schema,
82
+ t.name AS table_name,
83
+ i.name AS index_name,
84
+ c.name AS column_name,
85
+ ic.key_ordinal
86
+ FROM sys.index_columns ic
87
+ JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id
88
+ JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
89
+ JOIN sys.tables t ON t.object_id = i.object_id
90
+ JOIN sys.schemas sch ON sch.schema_id = t.schema_id
91
+ WHERE i.is_primary_key = 0 AND ${filterSchema}
92
+ ORDER BY ic.key_ordinal
93
+ `,
94
+ params
95
+ );
96
+
97
+ const indexColumnsMap = new Map<string, { column: string; order: number }[]>();
98
+ indexColsRows.forEach(r => {
99
+ const key = `${r.table_schema}.${r.table_name}.${r.index_name}`;
100
+ const list = indexColumnsMap.get(key) || [];
101
+ list.push({ column: r.column_name, order: r.key_ordinal });
102
+ indexColumnsMap.set(key, list);
103
+ });
104
+
105
+ const tablesByKey = new Map<string, DatabaseTable>();
106
+
107
+ columnRows.forEach(r => {
108
+ if (!shouldIncludeTable(r.table_name, options)) return;
109
+ const key = `${r.table_schema}.${r.table_name}`;
110
+ if (!tablesByKey.has(key)) {
111
+ tablesByKey.set(key, {
112
+ name: r.table_name,
113
+ schema: r.table_schema,
114
+ columns: [],
115
+ primaryKey: pkMap.get(key) || [],
116
+ indexes: []
117
+ });
118
+ }
119
+ const t = tablesByKey.get(key)!;
120
+ const column: DatabaseColumn = {
121
+ name: r.column_name,
122
+ type: r.data_type,
123
+ notNull: r.is_nullable === false || r.is_nullable === 0,
124
+ default: r.column_default ?? undefined,
125
+ autoIncrement: !!r.is_identity
126
+ };
127
+ t.columns.push(column);
128
+ });
129
+
130
+ indexRows.forEach(r => {
131
+ const key = `${r.table_schema}.${r.table_name}`;
132
+ const table = tablesByKey.get(key);
133
+ if (!table) return;
134
+ const cols = (indexColumnsMap.get(`${r.table_schema}.${r.table_name}.${r.index_name}`) || [])
135
+ .sort((a, b) => a.order - b.order)
136
+ .map(c => ({ column: c.column }));
137
+ const idx: DatabaseIndex = {
138
+ name: r.index_name,
139
+ columns: cols,
140
+ unique: !!r.is_unique,
141
+ where: r.has_filter ? r.filter_definition : undefined
142
+ };
143
+ table.indexes = table.indexes || [];
144
+ table.indexes.push(idx);
145
+ });
146
+
147
+ return { tables: Array.from(tablesByKey.values()) };
148
+ }
149
+ };
@@ -1,99 +1,99 @@
1
- import { SchemaIntrospector, IntrospectOptions } from './types.js';
2
- import { queryRows, shouldIncludeTable } from './utils.js';
3
- import { DatabaseSchema, DatabaseTable, DatabaseIndex, DatabaseColumn } from '../schema-types.js';
4
- import { DbExecutor } from '../../orm/db-executor.js';
5
-
6
- export const mysqlIntrospector: SchemaIntrospector = {
7
- async introspect(executor: DbExecutor, options: IntrospectOptions): Promise<DatabaseSchema> {
8
- const schema = options.schema;
9
- const filterClause = schema ? 'table_schema = ?' : 'table_schema = database()';
10
- const params = schema ? [schema] : [];
11
-
12
- const columnRows = await queryRows(
13
- executor,
14
- `
15
- SELECT table_schema, table_name, column_name, data_type, is_nullable, column_default, extra
16
- FROM information_schema.columns
17
- WHERE ${filterClause}
18
- ORDER BY table_name, ordinal_position
19
- `,
20
- params
21
- );
22
-
23
- const pkRows = await queryRows(
24
- executor,
25
- `
26
- SELECT table_schema, table_name, column_name
27
- FROM information_schema.key_column_usage
28
- WHERE constraint_name = 'PRIMARY' AND ${filterClause}
29
- ORDER BY ordinal_position
30
- `,
31
- params
32
- );
33
-
34
- const pkMap = new Map<string, string[]>();
35
- pkRows.forEach(r => {
36
- const key = `${r.table_schema}.${r.table_name}`;
37
- const list = pkMap.get(key) || [];
38
- list.push(r.column_name);
39
- pkMap.set(key, list);
40
- });
41
-
42
- const indexRows = await queryRows(
43
- executor,
44
- `
45
- SELECT
46
- table_schema,
47
- table_name,
48
- index_name,
49
- non_unique,
50
- GROUP_CONCAT(column_name ORDER BY seq_in_index) AS cols
51
- FROM information_schema.statistics
52
- WHERE ${filterClause} AND index_name <> 'PRIMARY'
53
- GROUP BY table_schema, table_name, index_name, non_unique
54
- `,
55
- params
56
- );
57
-
58
- const tablesByKey = new Map<string, DatabaseTable>();
59
-
60
- columnRows.forEach(r => {
61
- const key = `${r.table_schema}.${r.table_name}`;
62
- if (!shouldIncludeTable(r.table_name, options)) return;
63
- if (!tablesByKey.has(key)) {
64
- tablesByKey.set(key, {
65
- name: r.table_name,
66
- schema: r.table_schema,
67
- columns: [],
68
- primaryKey: pkMap.get(key) || [],
69
- indexes: []
70
- });
71
- }
72
- const cols = tablesByKey.get(key)!;
73
- const column: DatabaseColumn = {
74
- name: r.column_name,
75
- type: r.data_type,
76
- notNull: r.is_nullable === 'NO',
77
- default: r.column_default ?? undefined,
78
- autoIncrement: typeof r.extra === 'string' && r.extra.includes('auto_increment')
79
- };
80
- cols.columns.push(column);
81
- });
82
-
83
- indexRows.forEach(r => {
84
- const key = `${r.table_schema}.${r.table_name}`;
85
- const table = tablesByKey.get(key);
86
- if (!table) return;
87
- const cols = (typeof r.cols === 'string' ? r.cols.split(',') : []).map((c: string) => ({ column: c.trim() }));
88
- const idx: DatabaseIndex = {
89
- name: r.index_name,
90
- columns: cols,
91
- unique: r.non_unique === 0
92
- };
93
- table.indexes = table.indexes || [];
94
- table.indexes.push(idx);
95
- });
96
-
97
- return { tables: Array.from(tablesByKey.values()) };
98
- }
99
- };
1
+ import { SchemaIntrospector, IntrospectOptions } from './types.js';
2
+ import { queryRows, shouldIncludeTable } from './utils.js';
3
+ import { DatabaseSchema, DatabaseTable, DatabaseIndex, DatabaseColumn } from '../schema-types.js';
4
+ import { DbExecutor } from '../../execution/db-executor.js';
5
+
6
+ export const mysqlIntrospector: SchemaIntrospector = {
7
+ async introspect(ctx: { executor: DbExecutor }, options: IntrospectOptions): Promise<DatabaseSchema> {
8
+ const schema = options.schema;
9
+ const filterClause = schema ? 'table_schema = ?' : 'table_schema = database()';
10
+ const params = schema ? [schema] : [];
11
+
12
+ const columnRows = await queryRows(
13
+ ctx.executor,
14
+ `
15
+ SELECT table_schema, table_name, column_name, data_type, is_nullable, column_default, extra
16
+ FROM information_schema.columns
17
+ WHERE ${filterClause}
18
+ ORDER BY table_name, ordinal_position
19
+ `,
20
+ params
21
+ );
22
+
23
+ const pkRows = await queryRows(
24
+ ctx.executor,
25
+ `
26
+ SELECT table_schema, table_name, column_name
27
+ FROM information_schema.key_column_usage
28
+ WHERE constraint_name = 'PRIMARY' AND ${filterClause}
29
+ ORDER BY ordinal_position
30
+ `,
31
+ params
32
+ );
33
+
34
+ const pkMap = new Map<string, string[]>();
35
+ pkRows.forEach(r => {
36
+ const key = `${r.table_schema}.${r.table_name}`;
37
+ const list = pkMap.get(key) || [];
38
+ list.push(r.column_name);
39
+ pkMap.set(key, list);
40
+ });
41
+
42
+ const indexRows = await queryRows(
43
+ ctx.executor,
44
+ `
45
+ SELECT
46
+ table_schema,
47
+ table_name,
48
+ index_name,
49
+ non_unique,
50
+ GROUP_CONCAT(column_name ORDER BY seq_in_index) AS cols
51
+ FROM information_schema.statistics
52
+ WHERE ${filterClause} AND index_name <> 'PRIMARY'
53
+ GROUP BY table_schema, table_name, index_name, non_unique
54
+ `,
55
+ params
56
+ );
57
+
58
+ const tablesByKey = new Map<string, DatabaseTable>();
59
+
60
+ columnRows.forEach(r => {
61
+ const key = `${r.table_schema}.${r.table_name}`;
62
+ if (!shouldIncludeTable(r.table_name, options)) return;
63
+ if (!tablesByKey.has(key)) {
64
+ tablesByKey.set(key, {
65
+ name: r.table_name,
66
+ schema: r.table_schema,
67
+ columns: [],
68
+ primaryKey: pkMap.get(key) || [],
69
+ indexes: []
70
+ });
71
+ }
72
+ const cols = tablesByKey.get(key)!;
73
+ const column: DatabaseColumn = {
74
+ name: r.column_name,
75
+ type: r.data_type,
76
+ notNull: r.is_nullable === 'NO',
77
+ default: r.column_default ?? undefined,
78
+ autoIncrement: typeof r.extra === 'string' && r.extra.includes('auto_increment')
79
+ };
80
+ cols.columns.push(column);
81
+ });
82
+
83
+ indexRows.forEach(r => {
84
+ const key = `${r.table_schema}.${r.table_name}`;
85
+ const table = tablesByKey.get(key);
86
+ if (!table) return;
87
+ const cols = (typeof r.cols === 'string' ? r.cols.split(',') : []).map((c: string) => ({ column: c.trim() }));
88
+ const idx: DatabaseIndex = {
89
+ name: r.index_name,
90
+ columns: cols,
91
+ unique: r.non_unique === 0
92
+ };
93
+ table.indexes = table.indexes || [];
94
+ table.indexes.push(idx);
95
+ });
96
+
97
+ return { tables: Array.from(tablesByKey.values()) };
98
+ }
99
+ };