-
Notifications
You must be signed in to change notification settings - Fork 1
/
parser.js
109 lines (96 loc) · 2.67 KB
/
parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
const { parse: parseAst } = require("./ast");
const parseColumn = (column, primaryColumns) => {
return {
name: column.name,
type: column.type,
notNull: column.modifiers.includes("NOT_NULL"),
autoIncrement: column.modifiers.includes("AUTO_INCREMENT"),
primaryKey: primaryColumns.includes(column.name),
};
};
const parseTable = (table) => {
const primaryColumns = table.constraints
.filter((c) => c.type === "PRIMARY_KEY")
.flatMap((c) => c.columns);
const columns = table.columns
.map((column) => parseColumn(column, primaryColumns))
.reduce((columns, column) => {
columns[column.name] = {
...column,
name: undefined,
};
return columns;
}, {});
return {
name: table.name,
primaryColumns,
columns,
};
};
const parseRelationship = (relationship, table, tables) => {
if (tables[relationship.foreignTable] === undefined) {
throw new Error(
`Relationship points to undefined table ${relationship.foreignTable}`
);
}
if (
tables[relationship.foreignTable].columns[relationship.foreignColumn] ===
undefined
) {
throw new Error(
`Relationship points to undefined table column ${relationship.foreignTable}.${relationship.foreignColumn}`
);
}
if (tables[table.name].columns[relationship.selfColumn] === undefined) {
throw new Error(
`Relationship points to undefined table column ${tables[table.name]}.${
relationship.selfColumn
}`
);
}
return {
from: {
table: table.name,
column: relationship.selfColumn,
mandatory:
tables[table.name].columns[relationship.selfColumn].notNull ||
tables[table.name].columns[relationship.selfColumn].primaryKey,
type: "ONE",
},
to: {
table: relationship.foreignTable,
column: relationship.foreignColumn,
mandatory: relationship.foreignMandatory,
type:
tables[table.name].columns[relationship.selfColumn].primaryKey &&
tables[table.name].primaryColumns.length === 1
? "ONE"
: "MANY",
},
};
};
const parseRelationships = (table, tables) => {
return table.constraints
.filter((c) => c.type === "FOREIGN_KEY")
.map((relationship) => parseRelationship(relationship, table, tables));
};
const parse = (sql) => {
const rawTables = parseAst(sql);
const tables = rawTables.map(parseTable).reduce((tables, table) => {
tables[table.name] = {
...table,
name: undefined,
};
return tables;
}, {});
const relationships = rawTables.flatMap((table) =>
parseRelationships(table, tables)
);
return {
tables,
relationships,
};
};
module.exports = {
parse,
};