@biref/scanner 0.0.2 → 0.1.1

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