mutano 3.4.0 → 3.5.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/main.d.ts CHANGED
@@ -7,6 +7,7 @@ interface Desc {
7
7
  Extra: string;
8
8
  Null: string;
9
9
  Type: string;
10
+ DataType?: string;
10
11
  Comment: string;
11
12
  EnumOptions?: string[];
12
13
  }
@@ -48,6 +49,7 @@ interface Config {
48
49
  password: string;
49
50
  database: string;
50
51
  ssl?: Record<string, any>;
52
+ tinyIntAsBoolean?: boolean;
51
53
  } | {
52
54
  type: 'postgres';
53
55
  host: string;
package/dist/main.js CHANGED
@@ -43,8 +43,8 @@ function filterViews(views, includedViews, ignoredViews) {
43
43
  }
44
44
  function createEntityList(tables, views) {
45
45
  const allEntities = [
46
- ...tables.map((name) => ({ name, type: "table" })),
47
- ...views.map((name) => ({ name, type: "view" }))
46
+ ...tables.filter((name) => typeof name === "string" && name.length > 0).map((name) => ({ name, type: "table" })),
47
+ ...views.filter((name) => typeof name === "string" && name.length > 0).map((name) => ({ name, type: "view" }))
48
48
  ];
49
49
  return allEntities.sort((a, b) => a.name.localeCompare(b.name));
50
50
  }
@@ -60,7 +60,7 @@ function applyInflection(name, inflection) {
60
60
  }
61
61
 
62
62
  const dateTypes = {
63
- mysql: ["date", "datetime", "timestamp"],
63
+ mysql: ["date", "datetime", "datetime(3)", "timestamp", "timestamp(3)"],
64
64
  postgres: [
65
65
  "timestamp",
66
66
  "timestamp with time zone",
@@ -219,9 +219,16 @@ const hasTableIgnoreDirective = (comment) => {
219
219
  };
220
220
 
221
221
  function getType(op, desc, config, destination, entityName) {
222
- const { Default, Extra, Null, Type, Comment, EnumOptions } = desc;
222
+ const { Default, Extra, Null, Type, DataType, Comment, EnumOptions } = desc;
223
223
  const schemaType = config.origin.type;
224
224
  const type = schemaType === "prisma" ? Type : Type.toLowerCase();
225
+ let dataType = DataType ? schemaType === "prisma" ? DataType : DataType.toLowerCase() : type;
226
+ const isMySQL = schemaType === "mysql";
227
+ const tinyIntAsBoolean = isMySQL && config.origin.tinyIntAsBoolean !== false;
228
+ const isTinyInt1 = isMySQL && dataType === "tinyint" && Type.toLowerCase().includes("(1)");
229
+ if (tinyIntAsBoolean && isTinyInt1) {
230
+ dataType = "boolean";
231
+ }
225
232
  const isNull = Null === "YES";
226
233
  const hasDefaultValue = Default !== null;
227
234
  const isGenerated = Extra.toLowerCase().includes("auto_increment") || Extra.toLowerCase().includes("default_generated");
@@ -278,18 +285,18 @@ function getType(op, desc, config, destination, entityName) {
278
285
  }
279
286
  }
280
287
  if (isTsDestination || isKyselyDestination) {
281
- const isJsonField = isJsonType(type);
288
+ const isJsonField = isJsonType(dataType);
282
289
  if (isKyselyDestination && isJsonField) {
283
290
  const shouldBeNullable = isNull || ["insertable", "updateable"].includes(op) && (hasDefaultValue || isGenerated) || op === "updateable" && !isNull && !hasDefaultValue;
284
291
  return shouldBeNullable ? "Json | null" : "Json";
285
292
  }
286
293
  }
287
- const enumTypesForSchema = typeMappings.enumTypes[schemaType] || [];
288
- const isEnum = enumTypesForSchema.includes(type);
294
+ const enumTypesForSchema = typeMappings.enumTypes || [];
295
+ const isEnum = enumTypesForSchema.includes(dataType);
289
296
  const isPrismaEnum = schemaType === "prisma" && config.enumDeclarations && config.enumDeclarations[type];
290
297
  if (isEnum || isPrismaEnum) {
291
298
  let enumValues = [];
292
- if (schemaType === "mysql" && type === "enum") {
299
+ if (schemaType === "mysql" && dataType === "enum") {
293
300
  const match = Type.match(enumRegex);
294
301
  if (match) {
295
302
  enumValues = match[1].split(",").map((v) => v.trim().replace(/'/g, ""));
@@ -343,12 +350,12 @@ function getType(op, desc, config, destination, entityName) {
343
350
  }
344
351
  }
345
352
  }
346
- return generateStandardType(op, desc, config, destination, typeMappings);
353
+ return generateStandardType(op, desc, config, destination, typeMappings, dataType);
347
354
  }
348
- function generateStandardType(op, desc, config, destination, typeMappings) {
355
+ function generateStandardType(op, desc, config, destination, typeMappings, dataType) {
349
356
  const { Default, Extra, Null, Type } = desc;
350
357
  const schemaType = config.origin.type;
351
- const type = schemaType === "prisma" ? Type : Type.toLowerCase();
358
+ schemaType === "prisma" ? Type : Type.toLowerCase();
352
359
  const isNull = Null === "YES";
353
360
  const hasDefaultValue = Default !== null;
354
361
  const isGenerated = Extra.toLowerCase().includes("auto_increment") || Extra.toLowerCase().includes("default_generated");
@@ -357,7 +364,7 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
357
364
  const shouldBeNullable = isNull;
358
365
  const shouldBeOptional = op === "insertable" && (hasDefaultValue || isGenerated) || op === "updateable";
359
366
  let baseType;
360
- if (typeMappings.dateTypes.includes(type)) {
367
+ if (typeMappings.dateTypes.includes(dataType)) {
361
368
  if (isZodDestination) {
362
369
  const useDateType = destination.useDateType;
363
370
  if (useDateType) {
@@ -368,7 +375,7 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
368
375
  } else {
369
376
  baseType = "Date";
370
377
  }
371
- } else if (typeMappings.bigIntTypes.includes(type)) {
378
+ } else if (typeMappings.bigIntTypes.includes(dataType)) {
372
379
  if (isZodDestination) {
373
380
  baseType = "z.string()";
374
381
  } else if (isKyselyDestination) {
@@ -376,7 +383,7 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
376
383
  } else {
377
384
  baseType = "string";
378
385
  }
379
- } else if (typeMappings.decimalTypes.includes(type)) {
386
+ } else if (typeMappings.decimalTypes.includes(dataType)) {
380
387
  if (isZodDestination) {
381
388
  baseType = "z.string()";
382
389
  if (op !== "selectable") {
@@ -390,13 +397,13 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
390
397
  } else {
391
398
  baseType = "string";
392
399
  }
393
- } else if (typeMappings.numberTypes.includes(type)) {
400
+ } else if (typeMappings.numberTypes.includes(dataType)) {
394
401
  if (isZodDestination) {
395
402
  baseType = "z.number()";
396
403
  } else {
397
404
  baseType = "number";
398
405
  }
399
- } else if (typeMappings.booleanTypes.includes(type)) {
406
+ } else if (typeMappings.booleanTypes.includes(dataType)) {
400
407
  if (isZodDestination) {
401
408
  const useBooleanType = destination.useBooleanType;
402
409
  if (useBooleanType) {
@@ -407,7 +414,7 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
407
414
  } else {
408
415
  baseType = "boolean";
409
416
  }
410
- } else if (typeMappings.stringTypes.includes(type)) {
417
+ } else if (typeMappings.stringTypes.includes(dataType)) {
411
418
  if (isZodDestination) {
412
419
  const useTrim = destination.useTrim;
413
420
  const requiredString = destination.requiredString;
@@ -425,11 +432,11 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
425
432
  const nullableMethod = nullishOption && op !== "selectable" ? "nullish" : "nullable";
426
433
  if ((op === "table" || op === "insertable" || op === "updateable") && hasDefaultValue && Default !== null && !isGenerated) {
427
434
  let defaultValueFormatted = Default;
428
- if (typeMappings.stringTypes.includes(type) || typeMappings.dateTypes.includes(type)) {
435
+ if (typeMappings.stringTypes.includes(dataType) || typeMappings.dateTypes.includes(dataType)) {
429
436
  defaultValueFormatted = `'${Default}'`;
430
- } else if (typeMappings.booleanTypes.includes(type)) {
437
+ } else if (typeMappings.booleanTypes.includes(dataType)) {
431
438
  defaultValueFormatted = Default.toLowerCase() === "true" ? "true" : "false";
432
- } else if (typeMappings.numberTypes.includes(type)) {
439
+ } else if (typeMappings.numberTypes.includes(dataType)) {
433
440
  defaultValueFormatted = Default;
434
441
  } else {
435
442
  defaultValueFormatted = `'${Default}'`;
@@ -444,9 +451,9 @@ function generateStandardType(op, desc, config, destination, typeMappings) {
444
451
  return `${baseType}.default(${defaultValueFormatted})`;
445
452
  }
446
453
  }
447
- const isDateField = typeMappings.dateTypes.includes(type);
454
+ const isDateField = typeMappings.dateTypes.includes(dataType);
448
455
  const shouldDateBeOptional = isDateField && (hasDefaultValue || isGenerated) && (op === "table" || op === "selectable");
449
- const isIdField = typeMappings.numberTypes.includes(type) || typeMappings.bigIntTypes.includes(type) || typeMappings.stringTypes.includes(type);
456
+ const isIdField = typeMappings.numberTypes.includes(dataType) || typeMappings.bigIntTypes.includes(dataType) || typeMappings.stringTypes.includes(dataType);
450
457
  const shouldIdBeOptional = isIdField && isGenerated && (op === "table" || op === "selectable");
451
458
  if (shouldBeNullable && shouldBeOptional) {
452
459
  return `${baseType}.${nullableMethod}()`;
@@ -808,7 +815,7 @@ async function extractTables(db, config) {
808
815
  FROM information_schema.tables
809
816
  WHERE table_schema = ? AND table_type = 'BASE TABLE'
810
817
  `, [origin.database]);
811
- return mysqlTables[0].filter((row) => !hasTableIgnoreDirective(row.table_comment || "")).map((row) => row.table_name);
818
+ return mysqlTables[0].filter((row) => !hasTableIgnoreDirective(row.TABLE_COMMENT || row.table_comment || "")).map((row) => row.TABLE_NAME || row.table_name).filter((name) => typeof name === "string" && name.length > 0);
812
819
  case "postgres":
813
820
  const schema = origin.schema || "public";
814
821
  const postgresTables = await db.raw(`
@@ -837,7 +844,7 @@ async function extractViews(db, config) {
837
844
  FROM information_schema.tables
838
845
  WHERE table_schema = ? AND table_type = 'VIEW'
839
846
  `, [origin.database]);
840
- return mysqlViews[0].filter((row) => !hasTableIgnoreDirective(row.table_comment || "")).map((row) => row.table_name);
847
+ return mysqlViews[0].filter((row) => !hasTableIgnoreDirective(row.TABLE_COMMENT || row.table_comment || "")).map((row) => row.TABLE_NAME || row.table_name).filter((name) => typeof name === "string" && name.length > 0);
841
848
  case "postgres":
842
849
  const schema = origin.schema || "public";
843
850
  const postgresViews = await db.raw(`
@@ -867,6 +874,7 @@ async function extractColumnDescriptions(db, config, tableName) {
867
874
  column_default as \`Default\`,
868
875
  extra as \`Extra\`,
869
876
  is_nullable as \`Null\`,
877
+ data_type as \`DataType\`,
870
878
  column_type as \`Type\`,
871
879
  column_comment as \`Comment\`
872
880
  FROM information_schema.columns
@@ -878,6 +886,7 @@ async function extractColumnDescriptions(db, config, tableName) {
878
886
  Default: row.Default,
879
887
  Extra: row.Extra || "",
880
888
  Null: row.Null,
889
+ DataType: row.DataType,
881
890
  Type: row.Type,
882
891
  Comment: row.Comment || ""
883
892
  }));
@@ -951,6 +960,9 @@ function extractPrismaEntities(config) {
951
960
  if (e.type === "attribute") {
952
961
  return false;
953
962
  }
963
+ if (!e.name || typeof e.name !== "string") {
964
+ return false;
965
+ }
954
966
  if ("attributes" in e && e.attributes) {
955
967
  const hasIgnore = e.attributes.some((attr) => attr.name === "ignore");
956
968
  if (hasIgnore) {
@@ -975,7 +987,7 @@ function extractPrismaEntities(config) {
975
987
  }
976
988
  }
977
989
  return e.name;
978
- });
990
+ }).filter((value) => typeof value === "string" && value !== "undefined");
979
991
  enumDeclarations[enumName] = filteredEnumValues;
980
992
  }
981
993
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mutano",
3
3
  "type": "module",
4
- "version": "3.4.0",
4
+ "version": "3.5.0",
5
5
  "description": "Converts Prisma/MySQL/PostgreSQL/SQLite schemas to Zod/TS/Kysely interfaces",
6
6
  "author": "Alisson Cavalcante Agiani <thelinuxlich@gmail.com>",
7
7
  "license": "MIT",