mutano 3.1.6 → 3.2.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/README.md +72 -0
- package/dist/main.js +44 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -191,6 +191,7 @@ CREATE TABLE `user` (
|
|
|
191
191
|
`name` varchar(255) COMMENT '@zod(z.string().min(2).max(50))',
|
|
192
192
|
`email` varchar(255) COMMENT '@ts(EmailAddress) @kysely(string)',
|
|
193
193
|
`metadata` json COMMENT '@ts(UserMetadata)',
|
|
194
|
+
`password_hash` varchar(255) COMMENT '@ignore',
|
|
194
195
|
PRIMARY KEY (`id`)
|
|
195
196
|
);
|
|
196
197
|
```
|
|
@@ -199,6 +200,77 @@ CREATE TABLE `user` (
|
|
|
199
200
|
- `@zod(...)` - Override Zod schema
|
|
200
201
|
- `@ts(...)` - Override TypeScript type
|
|
201
202
|
- `@kysely(...)` - Override Kysely type
|
|
203
|
+
- `@ignore` - Exclude column from generated types
|
|
204
|
+
- `@@ignore` - Exclude table/model from generated types
|
|
205
|
+
|
|
206
|
+
### Ignoring Columns and Tables
|
|
207
|
+
|
|
208
|
+
Use `@ignore` and `@@ignore` directives to exclude columns and tables from code generation:
|
|
209
|
+
|
|
210
|
+
#### Prisma Schemas
|
|
211
|
+
|
|
212
|
+
**Ignore specific fields:**
|
|
213
|
+
```prisma
|
|
214
|
+
model User {
|
|
215
|
+
id Int @id @default(autoincrement())
|
|
216
|
+
email String @unique
|
|
217
|
+
password String @ignore // This field will be excluded
|
|
218
|
+
createdAt DateTime @default(now())
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Ignore entire models:**
|
|
223
|
+
```prisma
|
|
224
|
+
model AuditLog {
|
|
225
|
+
id Int @id @default(autoincrement())
|
|
226
|
+
action String
|
|
227
|
+
userId Int
|
|
228
|
+
timestamp DateTime @default(now())
|
|
229
|
+
|
|
230
|
+
@@ignore // This entire model will be excluded
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### SQL Databases (MySQL, PostgreSQL, SQLite)
|
|
235
|
+
|
|
236
|
+
**Ignore specific columns in MySQL:**
|
|
237
|
+
```sql
|
|
238
|
+
ALTER TABLE users MODIFY COLUMN password_hash VARCHAR(255) COMMENT '@ignore';
|
|
239
|
+
ALTER TABLE users MODIFY COLUMN internal_id VARCHAR(100) COMMENT 'Internal tracking @ignore';
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Ignore specific columns in PostgreSQL:**
|
|
243
|
+
```sql
|
|
244
|
+
COMMENT ON COLUMN users.password_hash IS '@ignore';
|
|
245
|
+
COMMENT ON COLUMN users.internal_id IS 'Internal tracking @ignore';
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Ignore entire tables in MySQL:**
|
|
249
|
+
```sql
|
|
250
|
+
ALTER TABLE audit_logs COMMENT = '@@ignore';
|
|
251
|
+
ALTER TABLE internal_metrics COMMENT = 'Internal table @@ignore';
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Ignore entire tables in PostgreSQL:**
|
|
255
|
+
```sql
|
|
256
|
+
COMMENT ON TABLE audit_logs IS '@@ignore';
|
|
257
|
+
COMMENT ON TABLE internal_metrics IS 'Internal table @@ignore';
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Example with mixed ignored and non-ignored columns:**
|
|
261
|
+
```sql
|
|
262
|
+
CREATE TABLE `user` (
|
|
263
|
+
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
264
|
+
`email` varchar(255) NOT NULL,
|
|
265
|
+
`name` varchar(255),
|
|
266
|
+
`password_hash` varchar(255) COMMENT '@ignore',
|
|
267
|
+
`internal_tracking_id` varchar(100) COMMENT 'Internal use only @ignore',
|
|
268
|
+
`metadata` json COMMENT '@ts(UserMetadata)',
|
|
269
|
+
PRIMARY KEY (`id`)
|
|
270
|
+
);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Generated types will only include: `id`, `email`, `name`, and `metadata`
|
|
202
274
|
|
|
203
275
|
## Type Overrides
|
|
204
276
|
|
package/dist/main.js
CHANGED
|
@@ -200,6 +200,12 @@ const extractTypeExpression = (comment, prefix) => {
|
|
|
200
200
|
const extractTSExpression = (comment) => extractTypeExpression(comment, "@ts(");
|
|
201
201
|
const extractKyselyExpression = (comment) => extractTypeExpression(comment, "@kysely(");
|
|
202
202
|
const extractZodExpression = (comment) => extractTypeExpression(comment, "@zod(");
|
|
203
|
+
const hasIgnoreDirective = (comment) => {
|
|
204
|
+
return comment.includes("@ignore");
|
|
205
|
+
};
|
|
206
|
+
const hasTableIgnoreDirective = (comment) => {
|
|
207
|
+
return comment.includes("@@ignore");
|
|
208
|
+
};
|
|
203
209
|
|
|
204
210
|
function getType(op, desc, config, destination) {
|
|
205
211
|
const { Default, Extra, Null, Type, Comment, EnumOptions } = desc;
|
|
@@ -770,23 +776,23 @@ async function extractTables(db, config) {
|
|
|
770
776
|
switch (origin.type) {
|
|
771
777
|
case "mysql":
|
|
772
778
|
const mysqlTables = await db.raw(`
|
|
773
|
-
SELECT table_name
|
|
774
|
-
FROM information_schema.tables
|
|
779
|
+
SELECT table_name, table_comment
|
|
780
|
+
FROM information_schema.tables
|
|
775
781
|
WHERE table_schema = ? AND table_type = 'BASE TABLE'
|
|
776
782
|
`, [origin.database]);
|
|
777
|
-
return mysqlTables[0].map((row) => row.table_name);
|
|
783
|
+
return mysqlTables[0].filter((row) => !hasTableIgnoreDirective(row.table_comment || "")).map((row) => row.table_name);
|
|
778
784
|
case "postgres":
|
|
779
785
|
const schema = origin.schema || "public";
|
|
780
786
|
const postgresTables = await db.raw(`
|
|
781
|
-
SELECT table_name
|
|
782
|
-
FROM information_schema.tables
|
|
787
|
+
SELECT table_name
|
|
788
|
+
FROM information_schema.tables
|
|
783
789
|
WHERE table_schema = ? AND table_type = 'BASE TABLE'
|
|
784
790
|
`, [schema]);
|
|
785
791
|
return postgresTables.rows.map((row) => row.table_name);
|
|
786
792
|
case "sqlite":
|
|
787
793
|
const sqliteTables = await db.raw(`
|
|
788
|
-
SELECT name
|
|
789
|
-
FROM sqlite_master
|
|
794
|
+
SELECT name
|
|
795
|
+
FROM sqlite_master
|
|
790
796
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
791
797
|
`);
|
|
792
798
|
return sqliteTables.map((row) => row.name);
|
|
@@ -799,23 +805,23 @@ async function extractViews(db, config) {
|
|
|
799
805
|
switch (origin.type) {
|
|
800
806
|
case "mysql":
|
|
801
807
|
const mysqlViews = await db.raw(`
|
|
802
|
-
SELECT table_name
|
|
803
|
-
FROM information_schema.tables
|
|
808
|
+
SELECT table_name, table_comment
|
|
809
|
+
FROM information_schema.tables
|
|
804
810
|
WHERE table_schema = ? AND table_type = 'VIEW'
|
|
805
811
|
`, [origin.database]);
|
|
806
|
-
return mysqlViews[0].map((row) => row.table_name);
|
|
812
|
+
return mysqlViews[0].filter((row) => !hasTableIgnoreDirective(row.table_comment || "")).map((row) => row.table_name);
|
|
807
813
|
case "postgres":
|
|
808
814
|
const schema = origin.schema || "public";
|
|
809
815
|
const postgresViews = await db.raw(`
|
|
810
|
-
SELECT table_name
|
|
811
|
-
FROM information_schema.tables
|
|
816
|
+
SELECT table_name
|
|
817
|
+
FROM information_schema.tables
|
|
812
818
|
WHERE table_schema = ? AND table_type = 'VIEW'
|
|
813
819
|
`, [schema]);
|
|
814
820
|
return postgresViews.rows.map((row) => row.table_name);
|
|
815
821
|
case "sqlite":
|
|
816
822
|
const sqliteViews = await db.raw(`
|
|
817
|
-
SELECT name
|
|
818
|
-
FROM sqlite_master
|
|
823
|
+
SELECT name
|
|
824
|
+
FROM sqlite_master
|
|
819
825
|
WHERE type = 'view'
|
|
820
826
|
`);
|
|
821
827
|
return sqliteViews.map((row) => row.name);
|
|
@@ -828,18 +834,18 @@ async function extractColumnDescriptions(db, config, tableName) {
|
|
|
828
834
|
switch (origin.type) {
|
|
829
835
|
case "mysql":
|
|
830
836
|
const mysqlColumns = await db.raw(`
|
|
831
|
-
SELECT
|
|
837
|
+
SELECT
|
|
832
838
|
column_name as \`Field\`,
|
|
833
839
|
column_default as \`Default\`,
|
|
834
840
|
extra as \`Extra\`,
|
|
835
841
|
is_nullable as \`Null\`,
|
|
836
842
|
column_type as \`Type\`,
|
|
837
843
|
column_comment as \`Comment\`
|
|
838
|
-
FROM information_schema.columns
|
|
844
|
+
FROM information_schema.columns
|
|
839
845
|
WHERE table_schema = ? AND table_name = ?
|
|
840
846
|
ORDER BY ordinal_position
|
|
841
847
|
`, [origin.database, tableName]);
|
|
842
|
-
return mysqlColumns[0].map((row) => ({
|
|
848
|
+
return mysqlColumns[0].filter((row) => !hasIgnoreDirective(row.Comment || "")).map((row) => ({
|
|
843
849
|
Field: row.Field,
|
|
844
850
|
Default: row.Default,
|
|
845
851
|
Extra: row.Extra || "",
|
|
@@ -850,18 +856,18 @@ async function extractColumnDescriptions(db, config, tableName) {
|
|
|
850
856
|
case "postgres":
|
|
851
857
|
const schema = origin.schema || "public";
|
|
852
858
|
const postgresColumns = await db.raw(`
|
|
853
|
-
SELECT
|
|
859
|
+
SELECT
|
|
854
860
|
column_name as "Field",
|
|
855
861
|
column_default as "Default",
|
|
856
862
|
'' as "Extra",
|
|
857
863
|
is_nullable as "Null",
|
|
858
864
|
data_type as "Type",
|
|
859
865
|
'' as "Comment"
|
|
860
|
-
FROM information_schema.columns
|
|
866
|
+
FROM information_schema.columns
|
|
861
867
|
WHERE table_schema = ? AND table_name = ?
|
|
862
868
|
ORDER BY ordinal_position
|
|
863
869
|
`, [schema, tableName]);
|
|
864
|
-
return postgresColumns.rows.map((row) => ({
|
|
870
|
+
return postgresColumns.rows.filter((row) => !hasIgnoreDirective(row.Comment || "")).map((row) => ({
|
|
865
871
|
Field: row.Field,
|
|
866
872
|
Default: row.Default,
|
|
867
873
|
Extra: row.Extra || "",
|
|
@@ -871,7 +877,7 @@ async function extractColumnDescriptions(db, config, tableName) {
|
|
|
871
877
|
}));
|
|
872
878
|
case "sqlite":
|
|
873
879
|
const sqliteColumns = await db.raw(`PRAGMA table_info(${tableName})`);
|
|
874
|
-
return sqliteColumns.map((row) => ({
|
|
880
|
+
return sqliteColumns.filter((row) => !hasIgnoreDirective(row.Comment || "")).map((row) => ({
|
|
875
881
|
Field: row.name,
|
|
876
882
|
Default: row.dflt_value,
|
|
877
883
|
Extra: row.pk ? "PRIMARY KEY" : "",
|
|
@@ -891,7 +897,14 @@ function extractPrismaEntities(config) {
|
|
|
891
897
|
const schemaContent = readFileSync(config.origin.path, "utf-8");
|
|
892
898
|
const schema = createPrismaSchemaBuilder(schemaContent);
|
|
893
899
|
const prismaModels = schema.findAllByType("model", {});
|
|
894
|
-
const tables = prismaModels.filter((m) => m !== null).
|
|
900
|
+
const tables = prismaModels.filter((m) => m !== null).filter((model) => {
|
|
901
|
+
if (model.properties && Array.isArray(model.properties)) {
|
|
902
|
+
return !model.properties.some(
|
|
903
|
+
(prop) => prop.type === "attribute" && prop.name === "ignore" && prop.kind === "object"
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
return true;
|
|
907
|
+
}).map((model) => model.name);
|
|
895
908
|
const prismaViews = schema.findAllByType("view", {});
|
|
896
909
|
const views = prismaViews.filter((v) => v !== null).map((view) => view.name);
|
|
897
910
|
const enumDeclarations = {};
|
|
@@ -935,8 +948,16 @@ function extractPrismaColumnDescriptions(config, entityName, enumDeclarations) {
|
|
|
935
948
|
if (!entity || !("properties" in entity)) {
|
|
936
949
|
return [];
|
|
937
950
|
}
|
|
951
|
+
if (entity.type === "model" && entity.properties && Array.isArray(entity.properties)) {
|
|
952
|
+
const hasIgnore = entity.properties.some(
|
|
953
|
+
(prop) => prop.type === "attribute" && prop.name === "ignore" && prop.kind === "object"
|
|
954
|
+
);
|
|
955
|
+
if (hasIgnore) {
|
|
956
|
+
return [];
|
|
957
|
+
}
|
|
958
|
+
}
|
|
938
959
|
const fields = entity.properties.filter(
|
|
939
|
-
(p) => p.type === "field" && p.array !== true && !p.attributes?.find((a) => a.name === "relation")
|
|
960
|
+
(p) => p.type === "field" && p.array !== true && !p.attributes?.find((a) => a.name === "relation") && !p.attributes?.find((a) => a.name === "ignore")
|
|
940
961
|
);
|
|
941
962
|
return fields.map((field) => {
|
|
942
963
|
let defaultGenerated = false;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mutano",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.2.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",
|