@biref/scanner 0.0.2 → 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.
package/dist/index.cjs CHANGED
@@ -1,5 +1,1089 @@
1
1
  'use strict';
2
2
 
3
+ // src/adapters/mysql/MySQLMeta.ts
4
+ var MYSQL_ADAPTER_NAME = "mysql";
5
+ var MYSQL_URL_SCHEMES = ["mysql", "mariadb"];
6
+
7
+ // src/adapters/mysql/mapping/ConstraintMapper.ts
8
+ var ConstraintMapper = class _ConstraintMapper {
9
+ static toConstraint(raw) {
10
+ return {
11
+ name: raw.name,
12
+ kind: _ConstraintMapper.toKind(raw.kind),
13
+ fields: raw.columns,
14
+ expression: raw.definition
15
+ };
16
+ }
17
+ static toKind(kind) {
18
+ switch (kind) {
19
+ case "UNIQUE": {
20
+ return "unique";
21
+ }
22
+ case "CHECK": {
23
+ return "check";
24
+ }
25
+ default: {
26
+ return "custom";
27
+ }
28
+ }
29
+ }
30
+ };
31
+
32
+ // src/adapters/mysql/mapping/FieldMapper.ts
33
+ var ENUM_VALUES_RE = /^enum\((.+)\)$/i;
34
+ var SET_VALUES_RE = /^set\((.+)\)$/i;
35
+ var QUOTED_VALUE_RE = /'([^']*)'/g;
36
+ var FieldMapper = class _FieldMapper {
37
+ static toField(col, isIdentifier) {
38
+ return {
39
+ name: col.name,
40
+ type: _FieldMapper.toType(col),
41
+ nullable: col.nullable,
42
+ isIdentifier,
43
+ defaultValue: col.default_value,
44
+ description: col.description
45
+ };
46
+ }
47
+ static toType(col) {
48
+ const dataType = col.data_type.toLowerCase();
49
+ if (dataType === "enum") {
50
+ return {
51
+ category: "enum",
52
+ nativeType: col.column_type,
53
+ enumValues: _FieldMapper.parseEnumValues(col.column_type)
54
+ };
55
+ }
56
+ if (dataType === "set") {
57
+ return {
58
+ category: "enum",
59
+ nativeType: col.column_type,
60
+ enumValues: _FieldMapper.parseSetValues(col.column_type)
61
+ };
62
+ }
63
+ if (col.column_type.toLowerCase() === "tinyint(1)") {
64
+ return {
65
+ category: "boolean",
66
+ nativeType: col.column_type
67
+ };
68
+ }
69
+ const base = {
70
+ category: _FieldMapper.categorize(dataType),
71
+ nativeType: col.column_type
72
+ };
73
+ if (col.numeric_precision !== null && (dataType === "decimal" || dataType === "numeric")) {
74
+ return {
75
+ ...base,
76
+ precision: col.numeric_precision,
77
+ scale: col.numeric_scale ?? void 0
78
+ };
79
+ }
80
+ if (col.character_max_length !== null) {
81
+ return { ...base, length: col.character_max_length };
82
+ }
83
+ return base;
84
+ }
85
+ static parseEnumValues(columnType) {
86
+ const match = ENUM_VALUES_RE.exec(columnType);
87
+ if (!match) {
88
+ return [];
89
+ }
90
+ return _FieldMapper.extractQuotedValues(match[1]);
91
+ }
92
+ static parseSetValues(columnType) {
93
+ const match = SET_VALUES_RE.exec(columnType);
94
+ if (!match) {
95
+ return [];
96
+ }
97
+ return _FieldMapper.extractQuotedValues(match[1]);
98
+ }
99
+ static extractQuotedValues(raw) {
100
+ return Array.from(raw.matchAll(QUOTED_VALUE_RE), (m) => m[1]);
101
+ }
102
+ static categorize(dataType) {
103
+ switch (dataType) {
104
+ case "varchar":
105
+ case "char":
106
+ case "text":
107
+ case "tinytext":
108
+ case "mediumtext":
109
+ case "longtext": {
110
+ return "string";
111
+ }
112
+ case "tinyint":
113
+ case "smallint":
114
+ case "mediumint":
115
+ case "int":
116
+ case "bigint": {
117
+ return "integer";
118
+ }
119
+ case "decimal":
120
+ case "numeric":
121
+ case "float":
122
+ case "double":
123
+ case "real": {
124
+ return "decimal";
125
+ }
126
+ case "bit": {
127
+ return "binary";
128
+ }
129
+ case "date":
130
+ case "year": {
131
+ return "date";
132
+ }
133
+ case "datetime":
134
+ case "timestamp": {
135
+ return "timestamp";
136
+ }
137
+ case "time": {
138
+ return "time";
139
+ }
140
+ case "json": {
141
+ return "json";
142
+ }
143
+ case "binary":
144
+ case "varbinary":
145
+ case "blob":
146
+ case "tinyblob":
147
+ case "mediumblob":
148
+ case "longblob": {
149
+ return "binary";
150
+ }
151
+ default: {
152
+ return "unknown";
153
+ }
154
+ }
155
+ }
156
+ };
157
+
158
+ // src/adapters/mysql/mysqlEnums.ts
159
+ var MySQLReferentialAction = {
160
+ Restrict: "RESTRICT",
161
+ Cascade: "CASCADE",
162
+ SetNull: "SET NULL",
163
+ NoAction: "NO ACTION",
164
+ SetDefault: "SET DEFAULT"
165
+ };
166
+ var MySQLIndexMethod = {
167
+ BTree: "BTREE",
168
+ Hash: "HASH"};
169
+
170
+ // src/adapters/mysql/mapping/IndexMapper.ts
171
+ var IndexMapper = class _IndexMapper {
172
+ static toIndex(raw) {
173
+ return {
174
+ name: raw.name,
175
+ fields: raw.columns,
176
+ unique: raw.unique,
177
+ kind: _IndexMapper.toKind(raw.method),
178
+ partial: false,
179
+ definition: null
180
+ };
181
+ }
182
+ static toKind(method) {
183
+ switch (method.toUpperCase()) {
184
+ case MySQLIndexMethod.BTree: {
185
+ return "btree";
186
+ }
187
+ case MySQLIndexMethod.Hash: {
188
+ return "hash";
189
+ }
190
+ default: {
191
+ return "unknown";
192
+ }
193
+ }
194
+ }
195
+ };
196
+
197
+ // src/adapters/mysql/mapping/ReferenceMapper.ts
198
+ var ReferenceMapper = class _ReferenceMapper {
199
+ static toReference(fk) {
200
+ return {
201
+ name: fk.name,
202
+ fromEntity: { namespace: fk.from_namespace, name: fk.from_table },
203
+ fromFields: fk.from_columns,
204
+ toEntity: { namespace: fk.to_namespace, name: fk.to_table },
205
+ toFields: fk.to_columns,
206
+ confidence: 1,
207
+ onUpdate: _ReferenceMapper.toAction(fk.update_action),
208
+ onDelete: _ReferenceMapper.toAction(fk.delete_action)
209
+ };
210
+ }
211
+ static toAction(rule) {
212
+ switch (rule) {
213
+ case MySQLReferentialAction.Restrict: {
214
+ return "restrict";
215
+ }
216
+ case MySQLReferentialAction.Cascade: {
217
+ return "cascade";
218
+ }
219
+ case MySQLReferentialAction.SetNull: {
220
+ return "set-null";
221
+ }
222
+ case MySQLReferentialAction.SetDefault: {
223
+ return "set-default";
224
+ }
225
+ case MySQLReferentialAction.NoAction: {
226
+ return "no-action";
227
+ }
228
+ default: {
229
+ return "no-action";
230
+ }
231
+ }
232
+ }
233
+ };
234
+
235
+ // src/adapters/mysql/mapping/EntityAssembler.ts
236
+ var EntityAssembler = class _EntityAssembler {
237
+ static assemble(inputs) {
238
+ const tableKeys = new Set(
239
+ inputs.tables.map((t) => _EntityAssembler.qualified(t.namespace, t.name))
240
+ );
241
+ const pkByEntity = _EntityAssembler.indexPrimaryKeys(inputs.primaryKeys);
242
+ const colsByEntity = _EntityAssembler.indexColumns(inputs.columns);
243
+ const relsByEntity = _EntityAssembler.buildRelationships(
244
+ inputs.foreignKeys,
245
+ tableKeys
246
+ );
247
+ const indexesByEntity = _EntityAssembler.buildIndexes(
248
+ inputs.indexes,
249
+ tableKeys
250
+ );
251
+ const constraintsByEntity = _EntityAssembler.buildConstraints(
252
+ inputs.constraints,
253
+ tableKeys
254
+ );
255
+ return inputs.tables.map((table) => {
256
+ const key = _EntityAssembler.qualified(table.namespace, table.name);
257
+ const pkColumns = pkByEntity.get(key) ?? [];
258
+ const pkSet = new Set(pkColumns);
259
+ const rawCols = colsByEntity.get(key) ?? [];
260
+ const fields = rawCols.map(
261
+ (col) => FieldMapper.toField(col, pkSet.has(col.name))
262
+ );
263
+ return {
264
+ namespace: table.namespace,
265
+ name: table.name,
266
+ fields,
267
+ identifier: pkColumns,
268
+ relationships: relsByEntity.get(key) ?? [],
269
+ constraints: constraintsByEntity.get(key) ?? [],
270
+ indexes: indexesByEntity.get(key) ?? [],
271
+ description: table.description
272
+ };
273
+ });
274
+ }
275
+ static indexPrimaryKeys(primaryKeys) {
276
+ const map = /* @__PURE__ */ new Map();
277
+ for (const pk of primaryKeys) {
278
+ map.set(
279
+ _EntityAssembler.qualified(pk.namespace, pk.table_name),
280
+ pk.columns
281
+ );
282
+ }
283
+ return map;
284
+ }
285
+ static indexColumns(columns) {
286
+ const map = /* @__PURE__ */ new Map();
287
+ for (const col of columns) {
288
+ const key = _EntityAssembler.qualified(col.namespace, col.table_name);
289
+ const list = map.get(key);
290
+ if (list) {
291
+ list.push(col);
292
+ } else {
293
+ map.set(key, [col]);
294
+ }
295
+ }
296
+ return map;
297
+ }
298
+ static buildRelationships(foreignKeys, tableKeys) {
299
+ const map = /* @__PURE__ */ new Map();
300
+ for (const fk of foreignKeys) {
301
+ const reference = ReferenceMapper.toReference(fk);
302
+ const fromKey = _EntityAssembler.qualified(
303
+ fk.from_namespace,
304
+ fk.from_table
305
+ );
306
+ const toKey = _EntityAssembler.qualified(fk.to_namespace, fk.to_table);
307
+ if (tableKeys.has(fromKey)) {
308
+ _EntityAssembler.push(map, fromKey, {
309
+ direction: "outbound",
310
+ reference
311
+ });
312
+ }
313
+ if (tableKeys.has(toKey)) {
314
+ _EntityAssembler.push(map, toKey, {
315
+ direction: "inbound",
316
+ reference
317
+ });
318
+ }
319
+ }
320
+ return map;
321
+ }
322
+ static buildIndexes(indexes, tableKeys) {
323
+ const map = /* @__PURE__ */ new Map();
324
+ for (const idx of indexes) {
325
+ const key = _EntityAssembler.qualified(idx.namespace, idx.table_name);
326
+ if (!tableKeys.has(key)) {
327
+ continue;
328
+ }
329
+ _EntityAssembler.push(map, key, IndexMapper.toIndex(idx));
330
+ }
331
+ return map;
332
+ }
333
+ static buildConstraints(constraints, tableKeys) {
334
+ const map = /* @__PURE__ */ new Map();
335
+ for (const cn of constraints) {
336
+ const key = _EntityAssembler.qualified(cn.namespace, cn.table_name);
337
+ if (!tableKeys.has(key)) {
338
+ continue;
339
+ }
340
+ _EntityAssembler.push(map, key, ConstraintMapper.toConstraint(cn));
341
+ }
342
+ return map;
343
+ }
344
+ static push(map, key, value) {
345
+ const list = map.get(key);
346
+ if (list) {
347
+ list.push(value);
348
+ } else {
349
+ map.set(key, [value]);
350
+ }
351
+ }
352
+ static qualified(namespace, name) {
353
+ return `${namespace}.${name}`;
354
+ }
355
+ };
356
+
357
+ // src/adapters/mysql/queries/inPlaceholders.ts
358
+ function inPlaceholders(count) {
359
+ return Array.from({ length: count }, () => "?").join(", ");
360
+ }
361
+
362
+ // src/adapters/mysql/queries/ColumnsQuery.ts
363
+ var ColumnsQuery = class {
364
+ static async fetch(client, namespaces) {
365
+ const sql = `
366
+ SELECT
367
+ c.TABLE_SCHEMA,
368
+ c.TABLE_NAME,
369
+ c.COLUMN_NAME,
370
+ c.DATA_TYPE,
371
+ c.COLUMN_TYPE,
372
+ c.IS_NULLABLE,
373
+ c.COLUMN_DEFAULT,
374
+ c.COLUMN_COMMENT,
375
+ c.CHARACTER_MAXIMUM_LENGTH,
376
+ c.NUMERIC_PRECISION,
377
+ c.NUMERIC_SCALE
378
+ FROM information_schema.COLUMNS c
379
+ JOIN information_schema.TABLES t
380
+ ON t.TABLE_SCHEMA = c.TABLE_SCHEMA
381
+ AND t.TABLE_NAME = c.TABLE_NAME
382
+ WHERE t.TABLE_TYPE = 'BASE TABLE'
383
+ AND c.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
384
+ ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, c.ORDINAL_POSITION
385
+ `;
386
+ const [rows] = await client.execute(sql, [...namespaces]);
387
+ return rows.map((row) => ({
388
+ namespace: row.TABLE_SCHEMA,
389
+ table_name: row.TABLE_NAME,
390
+ name: row.COLUMN_NAME,
391
+ data_type: row.DATA_TYPE,
392
+ column_type: row.COLUMN_TYPE,
393
+ nullable: row.IS_NULLABLE === "YES",
394
+ default_value: row.COLUMN_DEFAULT,
395
+ description: row.COLUMN_COMMENT || null,
396
+ character_max_length: row.CHARACTER_MAXIMUM_LENGTH,
397
+ numeric_precision: row.NUMERIC_PRECISION,
398
+ numeric_scale: row.NUMERIC_SCALE
399
+ }));
400
+ }
401
+ };
402
+
403
+ // src/adapters/mysql/queries/ConstraintsQuery.ts
404
+ var ConstraintsQuery = class _ConstraintsQuery {
405
+ static async fetch(client, namespaces) {
406
+ const [uniques, checks] = await Promise.all([
407
+ _ConstraintsQuery.fetchUniques(client, namespaces),
408
+ _ConstraintsQuery.fetchChecks(client, namespaces)
409
+ ]);
410
+ return [...uniques, ...checks];
411
+ }
412
+ static async fetchUniques(client, namespaces) {
413
+ const sql = `
414
+ SELECT
415
+ kcu.TABLE_SCHEMA,
416
+ kcu.TABLE_NAME,
417
+ kcu.CONSTRAINT_NAME,
418
+ kcu.COLUMN_NAME
419
+ FROM information_schema.KEY_COLUMN_USAGE kcu
420
+ JOIN information_schema.TABLE_CONSTRAINTS tc
421
+ ON tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
422
+ AND tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
423
+ AND tc.TABLE_NAME = kcu.TABLE_NAME
424
+ WHERE tc.CONSTRAINT_TYPE = 'UNIQUE'
425
+ AND kcu.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
426
+ ORDER BY kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION
427
+ `;
428
+ const [rows] = await client.execute(sql, [...namespaces]);
429
+ return _ConstraintsQuery.aggregateUniques(rows);
430
+ }
431
+ static aggregateUniques(rows) {
432
+ const map = /* @__PURE__ */ new Map();
433
+ for (const row of rows) {
434
+ const key = `${row.TABLE_SCHEMA}.${row.TABLE_NAME}.${row.CONSTRAINT_NAME}`;
435
+ const existing = map.get(key);
436
+ if (existing) {
437
+ existing.columns.push(row.COLUMN_NAME);
438
+ } else {
439
+ map.set(key, {
440
+ namespace: row.TABLE_SCHEMA,
441
+ table_name: row.TABLE_NAME,
442
+ name: row.CONSTRAINT_NAME,
443
+ kind: "UNIQUE",
444
+ definition: null,
445
+ columns: [row.COLUMN_NAME]
446
+ });
447
+ }
448
+ }
449
+ return [...map.values()];
450
+ }
451
+ static async fetchChecks(client, namespaces) {
452
+ const sql = `
453
+ SELECT
454
+ cc.CONSTRAINT_SCHEMA,
455
+ tc.TABLE_NAME,
456
+ cc.CONSTRAINT_NAME,
457
+ cc.CHECK_CLAUSE
458
+ FROM information_schema.CHECK_CONSTRAINTS cc
459
+ JOIN information_schema.TABLE_CONSTRAINTS tc
460
+ ON tc.CONSTRAINT_SCHEMA = cc.CONSTRAINT_SCHEMA
461
+ AND tc.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
462
+ WHERE tc.CONSTRAINT_TYPE = 'CHECK'
463
+ AND cc.CONSTRAINT_SCHEMA IN (${inPlaceholders(namespaces.length)})
464
+ ORDER BY cc.CONSTRAINT_SCHEMA, tc.TABLE_NAME, cc.CONSTRAINT_NAME
465
+ `;
466
+ try {
467
+ const [rows] = await client.execute(sql, [...namespaces]);
468
+ return rows.map((row) => ({
469
+ namespace: row.CONSTRAINT_SCHEMA,
470
+ table_name: row.TABLE_NAME,
471
+ name: row.CONSTRAINT_NAME,
472
+ kind: "CHECK",
473
+ definition: row.CHECK_CLAUSE,
474
+ columns: []
475
+ }));
476
+ } catch {
477
+ return [];
478
+ }
479
+ }
480
+ };
481
+
482
+ // src/adapters/mysql/queries/ForeignKeysQuery.ts
483
+ var ForeignKeysQuery = class _ForeignKeysQuery {
484
+ static async fetch(client, namespaces) {
485
+ const sql = `
486
+ SELECT
487
+ kcu.CONSTRAINT_NAME,
488
+ kcu.TABLE_SCHEMA,
489
+ kcu.TABLE_NAME,
490
+ kcu.COLUMN_NAME,
491
+ kcu.REFERENCED_TABLE_SCHEMA,
492
+ kcu.REFERENCED_TABLE_NAME,
493
+ kcu.REFERENCED_COLUMN_NAME,
494
+ rc.UPDATE_RULE,
495
+ rc.DELETE_RULE
496
+ FROM information_schema.KEY_COLUMN_USAGE kcu
497
+ JOIN information_schema.REFERENTIAL_CONSTRAINTS rc
498
+ ON rc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
499
+ AND rc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
500
+ WHERE kcu.REFERENCED_TABLE_NAME IS NOT NULL
501
+ AND kcu.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
502
+ ORDER BY kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION
503
+ `;
504
+ const [rows] = await client.execute(sql, [...namespaces]);
505
+ return _ForeignKeysQuery.aggregate(rows);
506
+ }
507
+ static aggregate(rows) {
508
+ const map = /* @__PURE__ */ new Map();
509
+ for (const row of rows) {
510
+ const key = `${row.TABLE_SCHEMA}.${row.TABLE_NAME}.${row.CONSTRAINT_NAME}`;
511
+ const existing = map.get(key);
512
+ if (existing) {
513
+ existing.from_columns.push(row.COLUMN_NAME);
514
+ existing.to_columns.push(row.REFERENCED_COLUMN_NAME);
515
+ } else {
516
+ map.set(key, {
517
+ name: row.CONSTRAINT_NAME,
518
+ from_namespace: row.TABLE_SCHEMA,
519
+ from_table: row.TABLE_NAME,
520
+ from_columns: [row.COLUMN_NAME],
521
+ to_namespace: row.REFERENCED_TABLE_SCHEMA,
522
+ to_table: row.REFERENCED_TABLE_NAME,
523
+ to_columns: [row.REFERENCED_COLUMN_NAME],
524
+ update_action: row.UPDATE_RULE,
525
+ delete_action: row.DELETE_RULE
526
+ });
527
+ }
528
+ }
529
+ return [...map.values()];
530
+ }
531
+ };
532
+
533
+ // src/adapters/mysql/queries/IndexesQuery.ts
534
+ var IndexesQuery = class _IndexesQuery {
535
+ static async fetch(client, namespaces) {
536
+ const sql = `
537
+ SELECT
538
+ s.TABLE_SCHEMA,
539
+ s.TABLE_NAME,
540
+ s.INDEX_NAME,
541
+ s.INDEX_TYPE,
542
+ s.NON_UNIQUE,
543
+ s.COLUMN_NAME
544
+ FROM information_schema.STATISTICS s
545
+ WHERE s.INDEX_NAME <> 'PRIMARY'
546
+ AND s.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
547
+ ORDER BY s.TABLE_SCHEMA, s.TABLE_NAME, s.INDEX_NAME, s.SEQ_IN_INDEX
548
+ `;
549
+ const [rows] = await client.execute(sql, [...namespaces]);
550
+ return _IndexesQuery.aggregate(rows);
551
+ }
552
+ static aggregate(rows) {
553
+ const map = /* @__PURE__ */ new Map();
554
+ for (const row of rows) {
555
+ const key = `${row.TABLE_SCHEMA}.${row.TABLE_NAME}.${row.INDEX_NAME}`;
556
+ const existing = map.get(key);
557
+ if (existing) {
558
+ existing.columns.push(row.COLUMN_NAME);
559
+ } else {
560
+ map.set(key, {
561
+ namespace: row.TABLE_SCHEMA,
562
+ table_name: row.TABLE_NAME,
563
+ name: row.INDEX_NAME,
564
+ method: row.INDEX_TYPE,
565
+ unique: row.NON_UNIQUE === 0,
566
+ partial: false,
567
+ definition: null,
568
+ columns: [row.COLUMN_NAME]
569
+ });
570
+ }
571
+ }
572
+ return [...map.values()];
573
+ }
574
+ };
575
+
576
+ // src/adapters/mysql/queries/PrimaryKeysQuery.ts
577
+ var PrimaryKeysQuery = class _PrimaryKeysQuery {
578
+ static async fetch(client, namespaces) {
579
+ const sql = `
580
+ SELECT
581
+ kcu.TABLE_SCHEMA,
582
+ kcu.TABLE_NAME,
583
+ kcu.COLUMN_NAME
584
+ FROM information_schema.KEY_COLUMN_USAGE kcu
585
+ JOIN information_schema.TABLE_CONSTRAINTS tc
586
+ ON tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
587
+ AND tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
588
+ AND tc.TABLE_NAME = kcu.TABLE_NAME
589
+ WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
590
+ AND kcu.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
591
+ ORDER BY kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.ORDINAL_POSITION
592
+ `;
593
+ const [rows] = await client.execute(sql, [...namespaces]);
594
+ return _PrimaryKeysQuery.aggregate(rows);
595
+ }
596
+ static aggregate(rows) {
597
+ const map = /* @__PURE__ */ new Map();
598
+ for (const row of rows) {
599
+ const key = `${row.TABLE_SCHEMA}.${row.TABLE_NAME}`;
600
+ const existing = map.get(key);
601
+ if (existing) {
602
+ existing.columns.push(row.COLUMN_NAME);
603
+ } else {
604
+ map.set(key, {
605
+ namespace: row.TABLE_SCHEMA,
606
+ table_name: row.TABLE_NAME,
607
+ columns: [row.COLUMN_NAME]
608
+ });
609
+ }
610
+ }
611
+ return [...map.values()];
612
+ }
613
+ };
614
+
615
+ // src/adapters/mysql/queries/TablesQuery.ts
616
+ var TablesQuery = class {
617
+ static async fetch(client, namespaces) {
618
+ const sql = `
619
+ SELECT
620
+ t.TABLE_SCHEMA AS TABLE_SCHEMA,
621
+ t.TABLE_NAME AS TABLE_NAME,
622
+ t.TABLE_COMMENT AS TABLE_COMMENT
623
+ FROM information_schema.TABLES t
624
+ WHERE t.TABLE_TYPE = 'BASE TABLE'
625
+ AND t.TABLE_SCHEMA IN (${inPlaceholders(namespaces.length)})
626
+ ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME
627
+ `;
628
+ const [rows] = await client.execute(sql, [...namespaces]);
629
+ return rows.map((row) => ({
630
+ namespace: row.TABLE_SCHEMA,
631
+ name: row.TABLE_NAME,
632
+ description: row.TABLE_COMMENT || null
633
+ }));
634
+ }
635
+ };
636
+
637
+ // src/domain/model/DataModel.ts
638
+ var DataModel = class _DataModel {
639
+ constructor(kind, entities) {
640
+ this.kind = kind;
641
+ this.entities = entities;
642
+ this.index = new Map(
643
+ entities.map((e) => [_DataModel.qualifiedName(e.namespace, e.name), e])
644
+ );
645
+ }
646
+ kind;
647
+ entities;
648
+ index;
649
+ /**
650
+ * Build the lookup key for an entity. Exposed as a static helper so
651
+ * consumers can compute keys consistently when building their own
652
+ * indexes on top of a `DataModel`.
653
+ */
654
+ static qualifiedName(namespace, name) {
655
+ return `${namespace}.${name}`;
656
+ }
657
+ getEntity(namespace, name) {
658
+ return this.index.get(_DataModel.qualifiedName(namespace, name));
659
+ }
660
+ hasEntity(namespace, name) {
661
+ return this.index.has(_DataModel.qualifiedName(namespace, name));
662
+ }
663
+ /**
664
+ * All relationships an entity participates in, in both directions.
665
+ * Returns an empty array if the entity is unknown.
666
+ */
667
+ relationshipsOf(namespace, name) {
668
+ return this.getEntity(namespace, name)?.relationships ?? [];
669
+ }
670
+ /**
671
+ * Outbound relationships: this entity holds the reference.
672
+ * In a relational store these correspond to FOREIGN KEY constraints
673
+ * declared by the entity itself.
674
+ */
675
+ outboundRelationshipsOf(namespace, name) {
676
+ return this.relationshipsOf(namespace, name).filter(
677
+ (r) => r.direction === "outbound"
678
+ );
679
+ }
680
+ /**
681
+ * Inbound relationships: other entities hold references pointing here.
682
+ *
683
+ * This is the differentiating feature of the SDK. Most introspection
684
+ * tools only surface outbound relationships, requiring consumers to
685
+ * know which other entities reference theirs ahead of time.
686
+ */
687
+ inboundRelationshipsOf(namespace, name) {
688
+ return this.relationshipsOf(namespace, name).filter(
689
+ (r) => r.direction === "inbound"
690
+ );
691
+ }
692
+ };
693
+
694
+ // src/adapters/mysql/MySQLIntrospector.ts
695
+ var MySQLIntrospector = class _MySQLIntrospector {
696
+ constructor(client) {
697
+ this.client = client;
698
+ }
699
+ client;
700
+ name = MYSQL_ADAPTER_NAME;
701
+ kind = "relational";
702
+ async introspect(options = {}) {
703
+ const namespaces = await this.resolveNamespaces(options.namespaces);
704
+ const [tables, columns, primaryKeys, foreignKeys, indexes, constraints] = await Promise.all([
705
+ TablesQuery.fetch(this.client, namespaces),
706
+ ColumnsQuery.fetch(this.client, namespaces),
707
+ PrimaryKeysQuery.fetch(this.client, namespaces),
708
+ ForeignKeysQuery.fetch(this.client, namespaces),
709
+ IndexesQuery.fetch(this.client, namespaces),
710
+ ConstraintsQuery.fetch(this.client, namespaces)
711
+ ]);
712
+ const filteredTables = _MySQLIntrospector.applyEntityFilters(
713
+ tables,
714
+ options
715
+ );
716
+ const entities = EntityAssembler.assemble({
717
+ tables: filteredTables,
718
+ columns,
719
+ primaryKeys,
720
+ foreignKeys,
721
+ indexes,
722
+ constraints
723
+ });
724
+ return new DataModel("relational", entities);
725
+ }
726
+ async resolveNamespaces(raw) {
727
+ if (raw === void 0) {
728
+ return this.currentDatabase();
729
+ }
730
+ if (raw === "all") {
731
+ const [rows] = await this.client.execute(
732
+ _MySQLIntrospector.ALL_SCHEMAS_SQL
733
+ );
734
+ return rows.map((row) => row.SCHEMA_NAME);
735
+ }
736
+ return raw;
737
+ }
738
+ async currentDatabase() {
739
+ const [rows] = await this.client.execute(
740
+ "SELECT DATABASE() AS db"
741
+ );
742
+ const db = rows[0]?.db;
743
+ if (!db) {
744
+ throw new Error(
745
+ "No database selected. Pass explicit namespaces or connect to a specific database."
746
+ );
747
+ }
748
+ return [db];
749
+ }
750
+ static ALL_SCHEMAS_SQL = `
751
+ SELECT s.SCHEMA_NAME
752
+ FROM information_schema.SCHEMATA s
753
+ WHERE s.SCHEMA_NAME NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
754
+ ORDER BY s.SCHEMA_NAME
755
+ `;
756
+ static applyEntityFilters(tables, options) {
757
+ const { includeEntities: allow, excludeEntities: deny } = options;
758
+ if (!allow && !deny) {
759
+ return tables;
760
+ }
761
+ return tables.filter((t) => {
762
+ if (allow && !allow.includes(t.name)) {
763
+ return false;
764
+ }
765
+ if (deny?.includes(t.name)) {
766
+ return false;
767
+ }
768
+ return true;
769
+ });
770
+ }
771
+ };
772
+
773
+ // src/adapters/mysql/query/SqlIdentifier.ts
774
+ var SqlIdentifier = class _SqlIdentifier {
775
+ static quote(id) {
776
+ return `\`${id.replace(/`/g, "``")}\``;
777
+ }
778
+ static qualified(namespace, name) {
779
+ return `${_SqlIdentifier.quote(namespace)}.${_SqlIdentifier.quote(name)}`;
780
+ }
781
+ };
782
+
783
+ // src/adapters/mysql/query/FilterBuilder.ts
784
+ var FilterBuilder = class {
785
+ constructor(params) {
786
+ this.params = params;
787
+ }
788
+ params;
789
+ build(filter) {
790
+ const col = SqlIdentifier.quote(filter.field);
791
+ switch (filter.operator) {
792
+ case "eq": {
793
+ return `${col} = ${this.params.add(filter.value)}`;
794
+ }
795
+ case "neq": {
796
+ return `${col} <> ${this.params.add(filter.value)}`;
797
+ }
798
+ case "lt": {
799
+ return `${col} < ${this.params.add(filter.value)}`;
800
+ }
801
+ case "lte": {
802
+ return `${col} <= ${this.params.add(filter.value)}`;
803
+ }
804
+ case "gt": {
805
+ return `${col} > ${this.params.add(filter.value)}`;
806
+ }
807
+ case "gte": {
808
+ return `${col} >= ${this.params.add(filter.value)}`;
809
+ }
810
+ case "like": {
811
+ return `${col} LIKE ${this.params.add(filter.value)}`;
812
+ }
813
+ case "ilike": {
814
+ return `LOWER(${col}) LIKE LOWER(${this.params.add(filter.value)})`;
815
+ }
816
+ case "is-null": {
817
+ return `${col} IS NULL`;
818
+ }
819
+ case "is-not-null": {
820
+ return `${col} IS NOT NULL`;
821
+ }
822
+ case "in": {
823
+ return this.buildInClause(col, filter.value, "FALSE", "IN");
824
+ }
825
+ case "not-in": {
826
+ return this.buildInClause(col, filter.value, "TRUE", "NOT IN");
827
+ }
828
+ case "between": {
829
+ return this.buildBetween(col, filter.value);
830
+ }
831
+ default: {
832
+ const exhaustive = filter.operator;
833
+ throw new Error(`Unknown filter operator: ${String(exhaustive)}`);
834
+ }
835
+ }
836
+ }
837
+ buildInClause(col, value, emptyFallback, keyword) {
838
+ if (!Array.isArray(value)) {
839
+ throw new Error(
840
+ `Operator '${keyword.toLowerCase()}' requires an array value.`
841
+ );
842
+ }
843
+ const values = value;
844
+ if (values.length === 0) {
845
+ return emptyFallback;
846
+ }
847
+ const placeholders = this.params.addAll(values);
848
+ return `${col} ${keyword} (${placeholders.join(", ")})`;
849
+ }
850
+ buildBetween(col, value) {
851
+ if (!Array.isArray(value) || value.length !== 2) {
852
+ throw new Error("Operator 'between' requires a [min, max] tuple.");
853
+ }
854
+ const tuple = value;
855
+ const lo = this.params.add(tuple[0]);
856
+ const hi = this.params.add(tuple[1]);
857
+ return `${col} BETWEEN ${lo} AND ${hi}`;
858
+ }
859
+ };
860
+
861
+ // src/adapters/mysql/query/SqlParamList.ts
862
+ var SqlParamList = class {
863
+ values = [];
864
+ /**
865
+ * Append a value and return a `?` placeholder.
866
+ */
867
+ add(value) {
868
+ this.values.push(value);
869
+ return "?";
870
+ }
871
+ /**
872
+ * Append many values and return their placeholders in order.
873
+ */
874
+ addAll(values) {
875
+ return values.map((v) => this.add(v));
876
+ }
877
+ /** Number of values currently bound. */
878
+ get size() {
879
+ return this.values.length;
880
+ }
881
+ /**
882
+ * Return a read-only copy of the bound values. The returned array
883
+ * is not backed by the internal storage.
884
+ */
885
+ toArray() {
886
+ return [...this.values];
887
+ }
888
+ };
889
+
890
+ // src/adapters/mysql/MySQLQueryEngine.ts
891
+ var MySQLQueryEngine = class {
892
+ name = MYSQL_ADAPTER_NAME;
893
+ kind = "relational";
894
+ build(spec, model) {
895
+ const entity = model.getEntity(spec.namespace, spec.entity);
896
+ if (!entity) {
897
+ throw new Error(
898
+ `Entity "${spec.namespace}.${spec.entity}" not found in the data model.`
899
+ );
900
+ }
901
+ const fieldNames = new Set(entity.fields.map((f) => f.name));
902
+ const selectedFields = spec.select && spec.select.length > 0 ? [...spec.select] : entity.fields.map((f) => f.name);
903
+ for (const field of selectedFields) {
904
+ if (!fieldNames.has(field)) {
905
+ throw new Error(
906
+ `Field "${field}" does not exist on "${spec.namespace}.${spec.entity}".`
907
+ );
908
+ }
909
+ }
910
+ const params = new SqlParamList();
911
+ const filterBuilder = new FilterBuilder(params);
912
+ const selectClause = selectedFields.map(SqlIdentifier.quote).join(", ");
913
+ const fromClause = SqlIdentifier.qualified(spec.namespace, spec.entity);
914
+ let sql = `SELECT ${selectClause} FROM ${fromClause}`;
915
+ if (spec.filters && spec.filters.length > 0) {
916
+ const wherePieces = spec.filters.map((filter) => {
917
+ if (!fieldNames.has(filter.field)) {
918
+ throw new Error(
919
+ `Filter field "${filter.field}" does not exist on "${spec.namespace}.${spec.entity}".`
920
+ );
921
+ }
922
+ return filterBuilder.build(filter);
923
+ });
924
+ sql += ` WHERE ${wherePieces.join(" AND ")}`;
925
+ }
926
+ if (spec.orderBy && spec.orderBy.length > 0) {
927
+ const orderPieces = spec.orderBy.map((order) => {
928
+ if (!fieldNames.has(order.field)) {
929
+ throw new Error(
930
+ `Order field "${order.field}" does not exist on "${spec.namespace}.${spec.entity}".`
931
+ );
932
+ }
933
+ return `${SqlIdentifier.quote(order.field)} ${order.direction.toUpperCase()}`;
934
+ });
935
+ sql += ` ORDER BY ${orderPieces.join(", ")}`;
936
+ }
937
+ if (spec.limit !== void 0) {
938
+ sql += ` LIMIT ${params.add(spec.limit)}`;
939
+ }
940
+ if (spec.offset !== void 0) {
941
+ sql += ` OFFSET ${params.add(spec.offset)}`;
942
+ }
943
+ return {
944
+ command: sql,
945
+ params: params.toArray(),
946
+ metadata: {
947
+ engine: MYSQL_ADAPTER_NAME,
948
+ paramCount: params.size
949
+ }
950
+ };
951
+ }
952
+ };
953
+
954
+ // src/parsing/DefaultRecordParser.ts
955
+ var DefaultRecordParser = class {
956
+ parse(entity, row) {
957
+ const result = {};
958
+ for (const field of entity.fields) {
959
+ if (field.name in row) {
960
+ result[field.name] = this.coerce(field, row[field.name]);
961
+ }
962
+ }
963
+ return result;
964
+ }
965
+ parseMany(entity, rows) {
966
+ return rows.map((row) => this.parse(entity, row));
967
+ }
968
+ coerce(field, raw) {
969
+ if (raw === null || raw === void 0) {
970
+ return null;
971
+ }
972
+ switch (field.type.category) {
973
+ case "string":
974
+ case "uuid":
975
+ case "enum": {
976
+ return String(raw);
977
+ }
978
+ case "integer": {
979
+ if (typeof raw === "bigint") {
980
+ return raw;
981
+ }
982
+ if (typeof raw === "number") {
983
+ return raw;
984
+ }
985
+ return Number(raw);
986
+ }
987
+ case "decimal": {
988
+ return typeof raw === "string" ? raw : String(raw);
989
+ }
990
+ case "boolean": {
991
+ return Boolean(raw);
992
+ }
993
+ case "date":
994
+ case "timestamp":
995
+ case "time": {
996
+ if (raw instanceof Date) {
997
+ return raw;
998
+ }
999
+ if (typeof raw === "string" || typeof raw === "number") {
1000
+ return new Date(raw);
1001
+ }
1002
+ return null;
1003
+ }
1004
+ case "json":
1005
+ case "binary":
1006
+ case "reference":
1007
+ case "unknown": {
1008
+ return raw;
1009
+ }
1010
+ case "array": {
1011
+ return Array.isArray(raw) ? raw : [];
1012
+ }
1013
+ default: {
1014
+ const exhaustive = field.type.category;
1015
+ return exhaustive;
1016
+ }
1017
+ }
1018
+ }
1019
+ };
1020
+
1021
+ // src/adapters/mysql/MySQLRecordParser.ts
1022
+ var BIGINT_NATIVE_TYPES = /* @__PURE__ */ new Set(["bigint"]);
1023
+ var MySQLRecordParser = class extends DefaultRecordParser {
1024
+ coerce(field, raw) {
1025
+ if (raw === null || raw === void 0) {
1026
+ return null;
1027
+ }
1028
+ if (field.type.category === "integer" && BIGINT_NATIVE_TYPES.has(field.type.nativeType.toLowerCase())) {
1029
+ if (typeof raw === "bigint") {
1030
+ return raw;
1031
+ }
1032
+ if (typeof raw === "string" || typeof raw === "number") {
1033
+ return BigInt(raw);
1034
+ }
1035
+ return null;
1036
+ }
1037
+ if (field.type.category === "boolean") {
1038
+ if (typeof raw === "number") {
1039
+ return raw !== 0;
1040
+ }
1041
+ return Boolean(raw);
1042
+ }
1043
+ if (field.type.category === "json" && typeof raw === "string") {
1044
+ try {
1045
+ return JSON.parse(raw);
1046
+ } catch {
1047
+ return raw;
1048
+ }
1049
+ }
1050
+ return super.coerce(field, raw);
1051
+ }
1052
+ };
1053
+
1054
+ // src/adapters/mysql/MySQLRawQueryRunner.ts
1055
+ var MySQLRawQueryRunner = class {
1056
+ constructor(client) {
1057
+ this.client = client;
1058
+ }
1059
+ client;
1060
+ async run(built) {
1061
+ const [rows] = await this.client.execute(built.command, [
1062
+ ...built.params
1063
+ ]);
1064
+ return rows;
1065
+ }
1066
+ };
1067
+
1068
+ // src/adapters/mysql/mysqlAdapter.ts
1069
+ var mysqlAdapter = {
1070
+ name: MYSQL_ADAPTER_NAME,
1071
+ urlSchemes: MYSQL_URL_SCHEMES,
1072
+ create(client) {
1073
+ return {
1074
+ name: MYSQL_ADAPTER_NAME,
1075
+ introspector: new MySQLIntrospector(client),
1076
+ engine: new MySQLQueryEngine(),
1077
+ runner: new MySQLRawQueryRunner(client),
1078
+ parser: new MySQLRecordParser(),
1079
+ urlSchemes: MYSQL_URL_SCHEMES
1080
+ };
1081
+ }
1082
+ };
1083
+ function isMySQLAdapter(adapter) {
1084
+ return adapter.name === MYSQL_ADAPTER_NAME;
1085
+ }
1086
+
3
1087
  // src/adapters/postgres/pgEnums.ts
4
1088
  var PgTypeCategory = {
5
1089
  Array: "A"};
@@ -27,7 +1111,7 @@ var PgIndexMethod = {
27
1111
  };
28
1112
 
29
1113
  // src/adapters/postgres/mapping/ConstraintMapper.ts
30
- var ConstraintMapper = class _ConstraintMapper {
1114
+ var ConstraintMapper2 = class _ConstraintMapper {
31
1115
  static toConstraint(raw) {
32
1116
  return {
33
1117
  name: raw.name,
@@ -55,7 +1139,7 @@ var ConstraintMapper = class _ConstraintMapper {
55
1139
  };
56
1140
 
57
1141
  // src/adapters/postgres/mapping/FieldMapper.ts
58
- var FieldMapper = class _FieldMapper {
1142
+ var FieldMapper2 = class _FieldMapper {
59
1143
  static toField(col, isIdentifier) {
60
1144
  return {
61
1145
  name: col.name,
@@ -159,7 +1243,7 @@ var FieldMapper = class _FieldMapper {
159
1243
  };
160
1244
 
161
1245
  // src/adapters/postgres/mapping/IndexMapper.ts
162
- var IndexMapper = class _IndexMapper {
1246
+ var IndexMapper2 = class _IndexMapper {
163
1247
  static toIndex(raw) {
164
1248
  return {
165
1249
  name: raw.name,
@@ -198,7 +1282,7 @@ var IndexMapper = class _IndexMapper {
198
1282
  };
199
1283
 
200
1284
  // src/adapters/postgres/mapping/ReferenceMapper.ts
201
- var ReferenceMapper = class _ReferenceMapper {
1285
+ var ReferenceMapper2 = class _ReferenceMapper {
202
1286
  static toReference(fk) {
203
1287
  return {
204
1288
  name: fk.name,
@@ -236,7 +1320,7 @@ var ReferenceMapper = class _ReferenceMapper {
236
1320
  };
237
1321
 
238
1322
  // src/adapters/postgres/mapping/EntityAssembler.ts
239
- var EntityAssembler = class _EntityAssembler {
1323
+ var EntityAssembler2 = class _EntityAssembler {
240
1324
  static assemble(inputs) {
241
1325
  const tableKeys = new Set(
242
1326
  inputs.tables.map((t) => _EntityAssembler.qualified(t.namespace, t.name))
@@ -261,7 +1345,7 @@ var EntityAssembler = class _EntityAssembler {
261
1345
  const pkSet = new Set(pkColumns);
262
1346
  const rawCols = colsByEntity.get(key) ?? [];
263
1347
  const fields = rawCols.map(
264
- (col) => FieldMapper.toField(col, pkSet.has(col.name))
1348
+ (col) => FieldMapper2.toField(col, pkSet.has(col.name))
265
1349
  );
266
1350
  return {
267
1351
  namespace: table.namespace,
@@ -301,7 +1385,7 @@ var EntityAssembler = class _EntityAssembler {
301
1385
  static buildRelationships(foreignKeys, tableKeys) {
302
1386
  const map = /* @__PURE__ */ new Map();
303
1387
  for (const fk of foreignKeys) {
304
- const reference = ReferenceMapper.toReference(fk);
1388
+ const reference = ReferenceMapper2.toReference(fk);
305
1389
  const fromKey = _EntityAssembler.qualified(
306
1390
  fk.from_namespace,
307
1391
  fk.from_table
@@ -329,7 +1413,7 @@ var EntityAssembler = class _EntityAssembler {
329
1413
  if (!tableKeys.has(key)) {
330
1414
  continue;
331
1415
  }
332
- _EntityAssembler.push(map, key, IndexMapper.toIndex(idx));
1416
+ _EntityAssembler.push(map, key, IndexMapper2.toIndex(idx));
333
1417
  }
334
1418
  return map;
335
1419
  }
@@ -340,7 +1424,7 @@ var EntityAssembler = class _EntityAssembler {
340
1424
  if (!tableKeys.has(key)) {
341
1425
  continue;
342
1426
  }
343
- _EntityAssembler.push(map, key, ConstraintMapper.toConstraint(cn));
1427
+ _EntityAssembler.push(map, key, ConstraintMapper2.toConstraint(cn));
344
1428
  }
345
1429
  return map;
346
1430
  }
@@ -365,7 +1449,7 @@ var POSTGRES_URL_SCHEMES = [
365
1449
  ];
366
1450
 
367
1451
  // src/adapters/postgres/queries/ColumnsQuery.ts
368
- var ColumnsQuery = class _ColumnsQuery {
1452
+ var ColumnsQuery2 = class _ColumnsQuery {
369
1453
  static SQL = `
370
1454
  SELECT
371
1455
  n.nspname AS namespace,
@@ -418,7 +1502,7 @@ ORDER BY n.nspname, c.relname, a.attnum
418
1502
  };
419
1503
 
420
1504
  // src/adapters/postgres/queries/ConstraintsQuery.ts
421
- var ConstraintsQuery = class _ConstraintsQuery {
1505
+ var ConstraintsQuery2 = class _ConstraintsQuery {
422
1506
  static SQL = `
423
1507
  SELECT
424
1508
  n.nspname AS namespace,
@@ -450,7 +1534,7 @@ ORDER BY n.nspname, cls.relname, c.conname
450
1534
  };
451
1535
 
452
1536
  // src/adapters/postgres/queries/ForeignKeysQuery.ts
453
- var ForeignKeysQuery = class _ForeignKeysQuery {
1537
+ var ForeignKeysQuery2 = class _ForeignKeysQuery {
454
1538
  static SQL = `
455
1539
  SELECT
456
1540
  c.conname AS name,
@@ -487,7 +1571,7 @@ WHERE c.contype = 'f'
487
1571
  };
488
1572
 
489
1573
  // src/adapters/postgres/queries/IndexesQuery.ts
490
- var IndexesQuery = class _IndexesQuery {
1574
+ var IndexesQuery2 = class _IndexesQuery {
491
1575
  static SQL = `
492
1576
  SELECT
493
1577
  n.nspname AS namespace,
@@ -520,7 +1604,7 @@ ORDER BY n.nspname, t.relname, i.relname
520
1604
  };
521
1605
 
522
1606
  // src/adapters/postgres/queries/PrimaryKeysQuery.ts
523
- var PrimaryKeysQuery = class _PrimaryKeysQuery {
1607
+ var PrimaryKeysQuery2 = class _PrimaryKeysQuery {
524
1608
  static SQL = `
525
1609
  SELECT
526
1610
  n.nspname AS namespace,
@@ -545,7 +1629,7 @@ WHERE c.contype = 'p'
545
1629
  };
546
1630
 
547
1631
  // src/adapters/postgres/queries/TablesQuery.ts
548
- var TablesQuery = class _TablesQuery {
1632
+ var TablesQuery2 = class _TablesQuery {
549
1633
  static SQL = `
550
1634
  SELECT
551
1635
  n.nspname AS namespace,
@@ -563,63 +1647,6 @@ ORDER BY n.nspname, c.relname
563
1647
  }
564
1648
  };
565
1649
 
566
- // src/domain/model/DataModel.ts
567
- var DataModel = class _DataModel {
568
- constructor(kind, entities) {
569
- this.kind = kind;
570
- this.entities = entities;
571
- this.index = new Map(
572
- entities.map((e) => [_DataModel.qualifiedName(e.namespace, e.name), e])
573
- );
574
- }
575
- kind;
576
- entities;
577
- index;
578
- /**
579
- * Build the lookup key for an entity. Exposed as a static helper so
580
- * consumers can compute keys consistently when building their own
581
- * indexes on top of a `DataModel`.
582
- */
583
- static qualifiedName(namespace, name) {
584
- return `${namespace}.${name}`;
585
- }
586
- getEntity(namespace, name) {
587
- return this.index.get(_DataModel.qualifiedName(namespace, name));
588
- }
589
- hasEntity(namespace, name) {
590
- return this.index.has(_DataModel.qualifiedName(namespace, name));
591
- }
592
- /**
593
- * All relationships an entity participates in, in both directions.
594
- * Returns an empty array if the entity is unknown.
595
- */
596
- relationshipsOf(namespace, name) {
597
- return this.getEntity(namespace, name)?.relationships ?? [];
598
- }
599
- /**
600
- * Outbound relationships: this entity holds the reference.
601
- * In a relational store these correspond to FOREIGN KEY constraints
602
- * declared by the entity itself.
603
- */
604
- outboundRelationshipsOf(namespace, name) {
605
- return this.relationshipsOf(namespace, name).filter(
606
- (r) => r.direction === "outbound"
607
- );
608
- }
609
- /**
610
- * Inbound relationships: other entities hold references pointing here.
611
- *
612
- * This is the differentiating feature of the SDK. Most introspection
613
- * tools only surface outbound relationships, requiring consumers to
614
- * know which other entities reference theirs ahead of time.
615
- */
616
- inboundRelationshipsOf(namespace, name) {
617
- return this.relationshipsOf(namespace, name).filter(
618
- (r) => r.direction === "inbound"
619
- );
620
- }
621
- };
622
-
623
1650
  // src/adapters/postgres/PostgresIntrospector.ts
624
1651
  var DEFAULT_NAMESPACES = ["public"];
625
1652
  var PostgresIntrospector = class _PostgresIntrospector {
@@ -632,18 +1659,18 @@ var PostgresIntrospector = class _PostgresIntrospector {
632
1659
  async introspect(options = {}) {
633
1660
  const namespaces = await this.resolveNamespaces(options.namespaces);
634
1661
  const [tables, columns, primaryKeys, foreignKeys, indexes, constraints] = await Promise.all([
635
- TablesQuery.fetch(this.client, namespaces),
636
- ColumnsQuery.fetch(this.client, namespaces),
637
- PrimaryKeysQuery.fetch(this.client, namespaces),
638
- ForeignKeysQuery.fetch(this.client, namespaces),
639
- IndexesQuery.fetch(this.client, namespaces),
640
- ConstraintsQuery.fetch(this.client, namespaces)
1662
+ TablesQuery2.fetch(this.client, namespaces),
1663
+ ColumnsQuery2.fetch(this.client, namespaces),
1664
+ PrimaryKeysQuery2.fetch(this.client, namespaces),
1665
+ ForeignKeysQuery2.fetch(this.client, namespaces),
1666
+ IndexesQuery2.fetch(this.client, namespaces),
1667
+ ConstraintsQuery2.fetch(this.client, namespaces)
641
1668
  ]);
642
1669
  const filteredTables = _PostgresIntrospector.applyEntityFilters(
643
1670
  tables,
644
1671
  options
645
1672
  );
646
- const entities = EntityAssembler.assemble({
1673
+ const entities = EntityAssembler2.assemble({
647
1674
  tables: filteredTables,
648
1675
  columns,
649
1676
  primaryKeys,
@@ -691,7 +1718,7 @@ ORDER BY n.nspname
691
1718
  };
692
1719
 
693
1720
  // src/adapters/postgres/query/SqlIdentifier.ts
694
- var SqlIdentifier = class _SqlIdentifier {
1721
+ var SqlIdentifier2 = class _SqlIdentifier {
695
1722
  static quote(id) {
696
1723
  return `"${id.replace(/"/g, '""')}"`;
697
1724
  }
@@ -701,13 +1728,13 @@ var SqlIdentifier = class _SqlIdentifier {
701
1728
  };
702
1729
 
703
1730
  // src/adapters/postgres/query/FilterBuilder.ts
704
- var FilterBuilder = class {
1731
+ var FilterBuilder2 = class {
705
1732
  constructor(params) {
706
1733
  this.params = params;
707
1734
  }
708
1735
  params;
709
1736
  build(filter) {
710
- const col = SqlIdentifier.quote(filter.field);
1737
+ const col = SqlIdentifier2.quote(filter.field);
711
1738
  switch (filter.operator) {
712
1739
  case "eq": {
713
1740
  return `${col} = ${this.params.add(filter.value)}`;
@@ -779,7 +1806,7 @@ var FilterBuilder = class {
779
1806
  };
780
1807
 
781
1808
  // src/adapters/postgres/query/SqlParamList.ts
782
- var SqlParamList = class {
1809
+ var SqlParamList2 = class {
783
1810
  values = [];
784
1811
  /**
785
1812
  * Append a value and return its placeholder (`$N`, where N is the
@@ -828,10 +1855,10 @@ var PostgresQueryEngine = class {
828
1855
  );
829
1856
  }
830
1857
  }
831
- const params = new SqlParamList();
832
- const filterBuilder = new FilterBuilder(params);
833
- const selectClause = selectedFields.map(SqlIdentifier.quote).join(", ");
834
- const fromClause = SqlIdentifier.qualified(spec.namespace, spec.entity);
1858
+ const params = new SqlParamList2();
1859
+ const filterBuilder = new FilterBuilder2(params);
1860
+ const selectClause = selectedFields.map(SqlIdentifier2.quote).join(", ");
1861
+ const fromClause = SqlIdentifier2.qualified(spec.namespace, spec.entity);
835
1862
  let sql = `SELECT ${selectClause} FROM ${fromClause}`;
836
1863
  if (spec.filters && spec.filters.length > 0) {
837
1864
  const wherePieces = spec.filters.map((filter) => {
@@ -851,7 +1878,7 @@ var PostgresQueryEngine = class {
851
1878
  `Order field "${order.field}" does not exist on "${spec.namespace}.${spec.entity}".`
852
1879
  );
853
1880
  }
854
- return `${SqlIdentifier.quote(order.field)} ${order.direction.toUpperCase()}`;
1881
+ return `${SqlIdentifier2.quote(order.field)} ${order.direction.toUpperCase()}`;
855
1882
  });
856
1883
  sql += ` ORDER BY ${orderPieces.join(", ")}`;
857
1884
  }
@@ -872,81 +1899,14 @@ var PostgresQueryEngine = class {
872
1899
  }
873
1900
  };
874
1901
 
875
- // src/parsing/DefaultRecordParser.ts
876
- var DefaultRecordParser = class {
877
- parse(entity, row) {
878
- const result = {};
879
- for (const field of entity.fields) {
880
- if (field.name in row) {
881
- result[field.name] = this.coerce(field, row[field.name]);
882
- }
883
- }
884
- return result;
885
- }
886
- parseMany(entity, rows) {
887
- return rows.map((row) => this.parse(entity, row));
888
- }
889
- coerce(field, raw) {
890
- if (raw === null || raw === void 0) {
891
- return null;
892
- }
893
- switch (field.type.category) {
894
- case "string":
895
- case "uuid":
896
- case "enum": {
897
- return String(raw);
898
- }
899
- case "integer": {
900
- if (typeof raw === "bigint") {
901
- return raw;
902
- }
903
- if (typeof raw === "number") {
904
- return raw;
905
- }
906
- return Number(raw);
907
- }
908
- case "decimal": {
909
- return typeof raw === "string" ? raw : String(raw);
910
- }
911
- case "boolean": {
912
- return Boolean(raw);
913
- }
914
- case "date":
915
- case "timestamp":
916
- case "time": {
917
- if (raw instanceof Date) {
918
- return raw;
919
- }
920
- if (typeof raw === "string" || typeof raw === "number") {
921
- return new Date(raw);
922
- }
923
- return null;
924
- }
925
- case "json":
926
- case "binary":
927
- case "reference":
928
- case "unknown": {
929
- return raw;
930
- }
931
- case "array": {
932
- return Array.isArray(raw) ? raw : [];
933
- }
934
- default: {
935
- const exhaustive = field.type.category;
936
- return exhaustive;
937
- }
938
- }
939
- }
940
- };
941
-
942
1902
  // src/adapters/postgres/PostgresRecordParser.ts
943
- var BIGINT_NATIVE_TYPES = /* @__PURE__ */ new Set(["int8", "bigint"]);
1903
+ var BIGINT_NATIVE_TYPES2 = /* @__PURE__ */ new Set(["int8", "bigint"]);
944
1904
  var PostgresRecordParser = class extends DefaultRecordParser {
945
1905
  coerce(field, raw) {
946
1906
  if (raw === null || raw === void 0) {
947
1907
  return null;
948
1908
  }
949
- if (field.type.category === "integer" && BIGINT_NATIVE_TYPES.has(field.type.nativeType.toLowerCase())) {
1909
+ if (field.type.category === "integer" && BIGINT_NATIVE_TYPES2.has(field.type.nativeType.toLowerCase())) {
950
1910
  if (typeof raw === "bigint") {
951
1911
  return raw;
952
1912
  }
@@ -2255,6 +3215,11 @@ exports.CsvFormatter = CsvFormatter;
2255
3215
  exports.DataModel = DataModel;
2256
3216
  exports.DefaultRecordParser = DefaultRecordParser;
2257
3217
  exports.JsonFormatter = JsonFormatter;
3218
+ exports.MYSQL_ADAPTER_NAME = MYSQL_ADAPTER_NAME;
3219
+ exports.MYSQL_URL_SCHEMES = MYSQL_URL_SCHEMES;
3220
+ exports.MySQLIntrospector = MySQLIntrospector;
3221
+ exports.MySQLQueryEngine = MySQLQueryEngine;
3222
+ exports.MySQLRecordParser = MySQLRecordParser;
2258
3223
  exports.POSTGRES_ADAPTER_NAME = POSTGRES_ADAPTER_NAME;
2259
3224
  exports.POSTGRES_URL_SCHEMES = POSTGRES_URL_SCHEMES;
2260
3225
  exports.PostgresIntrospector = PostgresIntrospector;
@@ -2265,7 +3230,9 @@ exports.RawFormatter = RawFormatter;
2265
3230
  exports.Scanner = Scanner;
2266
3231
  exports.generateSchema = generateSchema;
2267
3232
  exports.generateSchemaFiles = generateSchemaFiles;
3233
+ exports.isMySQLAdapter = isMySQLAdapter;
2268
3234
  exports.isPostgresAdapter = isPostgresAdapter;
3235
+ exports.mysqlAdapter = mysqlAdapter;
2269
3236
  exports.overridesScaffold = overridesScaffold;
2270
3237
  exports.postgresAdapter = postgresAdapter;
2271
3238
  exports.tsTypeFor = tsTypeFor;