Skip to content

Commit 0b17a78

Browse files
committed
feat(prisma-parser): added utilities to transform prisma ast to json table schema
1 parent ac5406a commit 0b17a78

File tree

6 files changed

+242
-0
lines changed

6 files changed

+242
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { getSchema } from "@mrleebo/prisma-ast";
2+
import { type JSONTableSchema } from "shared/types/tableSchema";
3+
4+
import { prismaASTToJSONTableSchema } from "./utils/transformers/prismaASTToJSONTableSchema";
5+
6+
export const parsePrismaToJSON = (prismaCode: string): JSONTableSchema => {
7+
const rawParsedSchema = getSchema(prismaCode);
8+
return prismaASTToJSONTableSchema(rawParsedSchema);
9+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { type JSONTableRef } from "shared/types/tableSchema";
2+
3+
import { computeKey } from "../computeKey";
4+
5+
import type {
6+
FieldRelationsMap,
7+
IntermediateSchema,
8+
} from "@/types/intermediateFormattedNode";
9+
10+
export const createRefsAndFieldRelationsArray = (
11+
rawRelations: IntermediateSchema["rawRelations"],
12+
inverseRelationMap: IntermediateSchema["inverseRelationMap"],
13+
tablesNames: IntermediateSchema["tablesNames"],
14+
): [JSONTableRef[], FieldRelationsMap] => {
15+
const refs: JSONTableRef[] = [];
16+
const allFieldRelations: FieldRelationsMap = new Map();
17+
18+
const appendFieldRelation = (
19+
fieldKey: string,
20+
relationName: string,
21+
): void => {
22+
if (allFieldRelations.has(fieldKey)) {
23+
allFieldRelations.get(fieldKey)?.push(relationName);
24+
} else {
25+
allFieldRelations.set(fieldKey, [relationName]);
26+
}
27+
};
28+
29+
rawRelations.forEach((relation) => {
30+
// check if invest relationship exists
31+
if (
32+
// check all table exists
33+
!tablesNames.has(relation.table) &&
34+
!tablesNames.has(relation.referenceTable)
35+
)
36+
return;
37+
38+
const id = computeKey(
39+
relation.referenceTable,
40+
relation.table,
41+
...(relation.name !== undefined ? [relation.name] : []),
42+
);
43+
const relationType = inverseRelationMap.get(id);
44+
if (relationType === undefined) return;
45+
46+
const ref: JSONTableRef = {
47+
name: relation.name,
48+
endpoints: [
49+
{
50+
relation: "1",
51+
tableName: relation.referenceTable,
52+
fieldNames: [relation.referenceField],
53+
},
54+
{
55+
relation: relationType === "many" ? "*" : "1",
56+
fieldNames: [relation.field],
57+
tableName: relation.table,
58+
},
59+
],
60+
};
61+
62+
refs.push(ref);
63+
64+
appendFieldRelation(
65+
computeKey(relation.referenceTable, relation.referenceField),
66+
relation.table,
67+
);
68+
69+
appendFieldRelation(
70+
computeKey(relation.table, relation.field),
71+
relation.referenceTable,
72+
);
73+
});
74+
75+
return [refs, allFieldRelations];
76+
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { type JSONTableEnum } from "shared/types/tableSchema";
2+
3+
import { enumNodeToJSONTableEnum } from "../enumNodeToJSONTableEnum";
4+
5+
import { formatIntermediateTable } from "./formatIntermediateTable";
6+
7+
import type { Schema } from "@mrleebo/prisma-ast";
8+
9+
import {
10+
type RawRelationInfo,
11+
type IntermediateSchema,
12+
type IntermediateTable,
13+
type RelationType,
14+
} from "@/types/intermediateFormattedNode";
15+
import { isEnumNode, isModelNode, isTypeNode } from "@/utils/isTypeOf";
16+
17+
export const createIntermediateSchema = (
18+
nodes: Schema["list"],
19+
): IntermediateSchema => {
20+
const enums: JSONTableEnum[] = [];
21+
const tables: IntermediateTable[] = [];
22+
const enumsNames = new Set<string>();
23+
const types = new Set<string>();
24+
const rawRelations: RawRelationInfo[] = [];
25+
const inverseRelationMap = new Map<string, RelationType>();
26+
const tablesNames = new Set<string>();
27+
28+
const registerInverseRelation = (name: string, type: RelationType): void => {
29+
inverseRelationMap.set(name, type);
30+
};
31+
32+
const registerRawRelation = (info: RawRelationInfo): void => {
33+
rawRelations.push(info);
34+
};
35+
36+
for (const node of nodes) {
37+
if (isEnumNode(node)) {
38+
const _enum = enumNodeToJSONTableEnum(node);
39+
enumsNames.add(_enum.name);
40+
enums.push(_enum);
41+
}
42+
43+
if (isModelNode(node)) {
44+
tablesNames.add(node.name);
45+
tables.push(
46+
formatIntermediateTable(
47+
node,
48+
registerRawRelation,
49+
registerInverseRelation,
50+
),
51+
);
52+
}
53+
54+
if (isTypeNode(node)) {
55+
types.add(node.name);
56+
}
57+
}
58+
59+
return {
60+
enums,
61+
tables,
62+
enumsNames,
63+
rawRelations,
64+
inverseRelationMap,
65+
tablesNames,
66+
compositeTypesNames: types,
67+
};
68+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { type JSONTableField } from "shared/types/tableSchema";
2+
3+
import { computeKey } from "../computeKey";
4+
5+
import type {
6+
FieldRelationsMap,
7+
IntermediateField,
8+
} from "@/types/intermediateFormattedNode";
9+
10+
export const intermediateFieldToJSONTableField = (
11+
tableName: string,
12+
intermediateField: IntermediateField,
13+
enumsSet: Set<string>,
14+
fieldRelationTable: FieldRelationsMap,
15+
): JSONTableField => {
16+
const isEnum = enumsSet.has(intermediateField.type.type_name);
17+
18+
const keyInFieldRelationTable = computeKey(tableName, intermediateField.name);
19+
const relationship = fieldRelationTable.get(keyInFieldRelationTable);
20+
21+
const field: JSONTableField = {
22+
...intermediateField,
23+
type: { type_name: intermediateField.type.type_name, is_enum: isEnum },
24+
is_relation: relationship !== undefined && relationship.length > 0,
25+
relational_tables: relationship,
26+
};
27+
28+
return field;
29+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { type JSONTableTable } from "shared/types/tableSchema";
2+
3+
import { intermediateFieldToJSONTableField } from "./intermediateFieldToJSONTableField";
4+
5+
import {
6+
type FieldRelationsMap,
7+
type IntermediateTable,
8+
} from "@/types/intermediateFormattedNode";
9+
10+
export const intermediateTableToJSONTableTable = (
11+
{ fields: intermediateFields, name, indexes }: IntermediateTable,
12+
enumsSet: Set<string>,
13+
fieldRelationTable: FieldRelationsMap,
14+
): JSONTableTable => {
15+
const fields = intermediateFields.map((intermediateField) =>
16+
intermediateFieldToJSONTableField(
17+
name,
18+
intermediateField,
19+
enumsSet,
20+
fieldRelationTable,
21+
),
22+
);
23+
24+
return { name, fields, indexes };
25+
};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { type Schema } from "@mrleebo/prisma-ast";
2+
import { type JSONTableSchema } from "shared/types/tableSchema";
3+
4+
import { createIntermediateSchema } from "./intermediate/createIntermediateSchema";
5+
import { createRefsAndFieldRelationsArray } from "./createRefsFromPrismaASTNodes";
6+
import { intermediateTableToJSONTableTable } from "./intermediateTableToJSONTableTable";
7+
8+
export const prismaASTToJSONTableSchema = (
9+
prismaAST: Schema,
10+
): JSONTableSchema => {
11+
const {
12+
enums,
13+
tables: intermediateTables,
14+
enumsNames,
15+
rawRelations,
16+
inverseRelationMap,
17+
tablesNames,
18+
} = createIntermediateSchema(prismaAST.list);
19+
20+
const [refs, fieldRelationsArray] = createRefsAndFieldRelationsArray(
21+
rawRelations,
22+
inverseRelationMap,
23+
tablesNames,
24+
);
25+
26+
const tables = intermediateTables.map((intermediateTable) => {
27+
return intermediateTableToJSONTableTable(
28+
intermediateTable,
29+
enumsNames,
30+
fieldRelationsArray,
31+
);
32+
});
33+
34+
return { tables, enums, refs };
35+
};

0 commit comments

Comments
 (0)