@dbml/core 2.3.0 → 2.4.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.
Files changed (52) hide show
  1. package/lib/export/DbmlExporter.js +17 -9
  2. package/lib/export/JsonExporter.js +1 -3
  3. package/lib/export/ModelExporter.js +1 -3
  4. package/lib/export/MysqlExporter.js +50 -42
  5. package/lib/export/PostgresExporter.js +64 -49
  6. package/lib/export/SqlServerExporter.js +52 -46
  7. package/lib/model_structure/database.js +73 -28
  8. package/lib/model_structure/dbState.js +1 -3
  9. package/lib/model_structure/element.js +13 -13
  10. package/lib/model_structure/endpoint.js +18 -14
  11. package/lib/model_structure/enum.js +18 -14
  12. package/lib/model_structure/enumValue.js +16 -12
  13. package/lib/model_structure/field.js +47 -13
  14. package/lib/model_structure/indexColumn.js +16 -12
  15. package/lib/model_structure/indexes.js +18 -14
  16. package/lib/model_structure/ref.js +19 -16
  17. package/lib/model_structure/schema.js +24 -36
  18. package/lib/model_structure/table.js +19 -15
  19. package/lib/model_structure/tableGroup.js +18 -14
  20. package/lib/model_structure/utils.js +5 -0
  21. package/lib/parse/Parser.js +2 -4
  22. package/lib/parse/buildParser.js +1 -3
  23. package/lib/parse/dbml/parser.pegjs +64 -20
  24. package/lib/parse/dbmlParser.js +1401 -899
  25. package/lib/parse/mssql/constraint_definition/actions.js +2 -2
  26. package/lib/parse/mssql/fk_definition/actions.js +10 -3
  27. package/lib/parse/mssql/keyword_parsers.js +12 -2
  28. package/lib/parse/mssql/statements/actions.js +37 -6
  29. package/lib/parse/mssql/statements/index.js +1 -1
  30. package/lib/parse/mssql/statements/statement_types/alter_table/actions.js +11 -5
  31. package/lib/parse/mssql/statements/statement_types/comments/actions.js +57 -0
  32. package/lib/parse/mssql/statements/statement_types/comments/index.js +97 -0
  33. package/lib/parse/mssql/statements/statement_types/create_index/actions.js +6 -1
  34. package/lib/parse/mssql/statements/statement_types/create_table/actions.js +12 -10
  35. package/lib/parse/mssql/statements/statement_types/index.js +4 -1
  36. package/lib/parse/mssql/utils.js +16 -1
  37. package/lib/parse/mysql/parser.pegjs +66 -40
  38. package/lib/parse/mysqlParser.js +534 -359
  39. package/lib/parse/postgresParser.js +15 -13
  40. package/lib/parse/postgresql/Base_rules.pegjs +45 -10
  41. package/lib/parse/postgresql/Commands/Alter_table/Alter_table.pegjs +49 -4
  42. package/lib/parse/postgresql/Commands/Comment.pegjs +18 -6
  43. package/lib/parse/postgresql/Commands/Create_table/Create_table_normal.pegjs +5 -3
  44. package/lib/parse/postgresql/Commands/Create_table/Create_table_of.pegjs +1 -1
  45. package/lib/parse/postgresql/Commands/Create_table/Create_table_partition_of.pegjs +1 -1
  46. package/lib/parse/postgresql/Commands/Create_type/Create_type_enum.pegjs +2 -2
  47. package/lib/parse/postgresql/Commands/Ignore_syntax.pegjs +10 -1
  48. package/lib/parse/postgresql/InitializerUtils.pegjs +14 -2
  49. package/lib/parse/postgresql/Keywords.pegjs +5 -1
  50. package/lib/parse/postgresql/parser.pegjs +22 -8
  51. package/lib/parse/schemarbParser.js +3 -3
  52. package/package.json +2 -2
@@ -1,8 +1,27 @@
1
1
  // Base rules:
2
2
  // collumn_name, table_name
3
3
  column_name "valid column name" = identifier
4
- table_name "valid table name"
5
- = ((identifier _ "." _)*)? name:identifier { return name }
4
+
5
+ path_name = names:(identifier _ "." _)* {
6
+ let dbName = null;
7
+ let schemaName = null;
8
+ if (names && names.length > 0) {
9
+ if (names.length === 1) schemaName = names[0][0];
10
+ else {
11
+ dbName = names[0][0];
12
+ schemaName = names[1][0];
13
+ }
14
+ }
15
+ return { dbName, schemaName }
16
+ }
17
+
18
+ table_name "valid table name" = pathName:path_name name:identifier {
19
+ return { ...pathName, name }
20
+ }
21
+
22
+ enum_name "valid enum name" = pathName:path_name? name:identifier {
23
+ return { ...pathName, name }
24
+ }
6
25
 
7
26
  // string constant
8
27
  string_constant "string" = "'" c:char_inside_single_quote+ "'" {
@@ -32,36 +51,43 @@ digits = d:digit+ { return d.join('') }
32
51
  digit = [0-9]
33
52
 
34
53
  // type
35
- data_type "VALID TYPE" = c1:"CHARACTER"i _ c2:"VARYING"i _ args:("("expression")")? {
54
+ data_type "VALID TYPE" = c1:"CHARACTER"i _ c2:"VARYING"i _ args:("("expression")")? dimensions:(array_extension)? {
36
55
  let c = `${c1} ${c2}`;
37
56
  c = args ? c + '(' + args[1] + ')' : c;
38
57
  return {
39
- type_name: c,
58
+ type_name: c + (dimensions ? dimensions.map((dimension) => '[' + dimension + ']').join('') : ''),
40
59
  args: args ? args[1] : null
41
60
  }
42
61
  }
43
- / "timestamp"i _ number:("(" _ numeric_constant _ ")" _)? (("without"i/"with"i) _ "time"i _ "zone"i)? {
62
+ / "timestamp"i _ number:("(" _ numeric_constant _ ")" _)? (("without"i/"with"i) _ "time"i _ "zone"i)? dimensions:(array_extension)? {
44
63
  const args = number ? number[2] : null;
45
64
  return {
46
- type_name: args !== null ? `timestamp(${args})`: `timestamp`,
65
+ type_name: (args !== null ? `timestamp(${args})`: `timestamp`) + (dimensions ? dimensions.map((dimension) => '[' + dimension + ']').join('') : ''),
47
66
  args
48
67
  }
49
68
  }
50
- / "time"i _ number:("(" _ numeric_constant _ ")" _)? (("without"i/"with"i) _ "time"i _ "zone"i)? {
69
+ / "time"i _ number:("(" _ numeric_constant _ ")" _)? (("without"i/"with"i) _ "time"i _ "zone"i)? dimensions:(array_extension)? {
51
70
  const args = number ? number[2] : null;
52
71
  return {
53
- type_name: args !== null ? `time(${args})`: `time`,
72
+ type_name: (args !== null ? `time(${args})`: `time`) + (dimensions ? dimensions.map((dimension) => '[' + dimension + ']').join('') : ''),
54
73
  args
55
74
  }
56
75
  }
57
- / c:type_name { return c }
76
+ / c:type_name dimensions:(array_extension)? {
77
+ const args = c.args;
78
+ return {
79
+ type_name: c.type_name + (dimensions ? dimensions.map((dimension) => '[' + dimension + ']').join('') : ''),
80
+ schemaName: c.schemaName,
81
+ args
82
+ };
83
+ }
58
84
  / double_quote c:[^\"\n]+ double_quote {
59
85
  return {
60
86
  type_name: c.join(""),
61
87
  args: null
62
88
  }
63
89
  }
64
- type_name = c:(character)+ _ args:("(" expression ")")? {
90
+ type_name = pathName:path_name? c:(character)+ _ args:("(" expression ")")? {
65
91
  let type_name = c.join("");
66
92
  args = args ? args[1] : null;
67
93
  if (type_name.toLowerCase() !== 'enum') {
@@ -69,10 +95,19 @@ type_name = c:(character)+ _ args:("(" expression ")")? {
69
95
  }
70
96
 
71
97
  return {
98
+ ...pathName,
72
99
  type_name,
73
100
  args
74
101
  }
75
102
  }
103
+ //https://www.postgresql.org/docs/13/arrays.html
104
+ array_extension = _ "array"i singledimenson:(_ "[" _ expression _ "]")? {
105
+ return [singledimenson ? singledimenson[3] : ''];
106
+ }
107
+ / _ multidimenson:("[" _ expression _ "]")+ {
108
+ // this will parse into Array(Array('[', _ , expression , _ ']'))
109
+ return multidimenson.map((dimension) => dimension[2]);
110
+ }
76
111
 
77
112
  // Default
78
113
  default_expr = val:string_constant { return { value: val, type: 'string' }}
@@ -1,17 +1,57 @@
1
- alter_table = alter_table_action:alter_table_action {
1
+ alter_table = alter_sub_syntax:(
2
+ alter_table_action /
3
+ alter_table_rename /
4
+ alter_table_set_schema /
5
+ alter_table_set_tablespace /
6
+ alter_table_attach /
7
+ alter_table_detach
8
+ ) {
2
9
  return {
3
10
  command_name: "alter_table",
4
- value: alter_table_action
11
+ value: alter_sub_syntax
5
12
  }
6
13
  }
7
14
 
8
- alter_table_action = _ ALTER __ TABLE (__ IF_EXISTS)? (__ ONLY)? __ name:table_name __
15
+ alter_table_rename = _ ALTER __ TABLE (__ IF_EXISTS)? (__ ONLY)? __ table_name (_ "*")? __ RENAME (cmt / !semicolon .)* _ semicolon _ {
16
+ return {
17
+ syntax_name: "alter_table_rename",
18
+ }
19
+ }
20
+
21
+ alter_table_set_schema = _ ALTER __ TABLE (__ IF_EXISTS)? __ table_name __ SET __ SCHEMA (cmt / !semicolon .)* _ semicolon _ {
22
+ return {
23
+ syntax_name: "alter_table_set_schema",
24
+ }
25
+ }
26
+
27
+ alter_table_set_tablespace = _ ALTER __ TABLE __ ALL __ IN __ TABLESPACE __ table_name
28
+ (__ OWNED __ BY __ identifier (_ comma _ identifier)*)? __ SET __ TABLESPACE
29
+ (cmt / !semicolon .)* _ semicolon _ {
30
+ return {
31
+ syntax_name: "alter_set_tablespace",
32
+ }
33
+ }
34
+
35
+ alter_table_attach = _ ALTER __ TABLE (__ IF_EXISTS)? __ table_name __ ATTACH __ PARTITION (cmt / !semicolon .)* _ semicolon _ {
36
+ return {
37
+ syntax_name: "alter_table_attach",
38
+ }
39
+ }
40
+
41
+ alter_table_detach = _ ALTER __ TABLE (__ IF_EXISTS)? __ table_name __ DETACH __ PARTITION (cmt / !semicolon .)* _ semicolon _ {
42
+ return {
43
+ syntax_name: "alter_table_detach",
44
+ }
45
+ }
46
+
47
+ alter_table_action = _ ALTER __ TABLE (__ IF_EXISTS)? (__ ONLY)? __ name:table_name (_ "*")? __
9
48
  actions:actions _ semicolon _ {
10
49
  actions.forEach(({ type, t_value}) => {
11
50
  switch(type.toLowerCase()) {
12
51
  case "fk":
13
52
  t_value.forEach(({ endpoints }) => {
14
- endpoints[0].tableName = name
53
+ endpoints[0].tableName = name.name;
54
+ endpoints[0].schemaName = name.schemaName;
15
55
  })
16
56
  }
17
57
  })
@@ -78,6 +118,11 @@ action = ADD __ table_constraint:table_constraint (__ NOT __ VALID)? { // reuse
78
118
  value: value.toLowerCase()
79
119
  }
80
120
  }
121
+ / (cmt / !semicolon .)* {
122
+ return {
123
+ type: "unknown",
124
+ }
125
+ }
81
126
 
82
127
 
83
128
  set_attribute_options = first:set_attribute_option rest:(_ comma _ set_attribute_option)* {
@@ -2,9 +2,7 @@ comment = _ COMMENT __ ON __ comment_option:comment_option __ IS __ text:(string
2
2
  _ semicolon _ {
3
3
  if (text.toLowerCase() !== "null") {
4
4
  comment_option.value.text = text;
5
- } else {
6
- comment_option.value.syntax_name = "remove_comment";
7
- }
5
+ } else comment_option.value.text = null;
8
6
 
9
7
  return {
10
8
  command_name: "comment",
@@ -13,12 +11,26 @@ comment = _ COMMENT __ ON __ comment_option:comment_option __ IS __ text:(string
13
11
  }
14
12
 
15
13
  comment_option = (
16
- COLUMN __ relation_name:identifier "." column_name:column_name {
14
+ COLUMN __ path:(identifier '.')+ column_name:column_name {
15
+ let dbName = null, schemaName = null, tableName;
16
+ if (path.length === 1) {
17
+ tableName = path[0][0];
18
+ } else if (path.length === 2) {
19
+ schemaName = path[0][0];
20
+ tableName = path[1][0];
21
+ }
22
+ else {
23
+ dbName = path[0][0];
24
+ schemaName = path[1][0];
25
+ tableName = path[2][0];
26
+ }
17
27
  return {
18
28
  syntax_name: "column",
19
29
  value: {
20
- relation_name: relation_name,
21
- column_name
30
+ dbName,
31
+ schemaName,
32
+ tableName,
33
+ columnName: column_name
22
34
  }
23
35
  }
24
36
  }
@@ -7,7 +7,7 @@ create_table_normal =
7
7
  (__ ON __ COMMIT __ (PRESERVE __ ROWS/ DELETE __ ROWS/ DROP))?
8
8
  (__ TABLESPACE __ tablespace_name:identifier)?
9
9
  _ semicolon _ {
10
- const table = { name: table_name, fields: [], indexes: [] }
10
+ const table = { name: table_name.name, schemaName: table_name.schemaName, fields: [], indexes: [] }
11
11
  // process table_properties
12
12
  table_properties.forEach(({ table_property_name, value }) => {
13
13
  switch(table_property_name.toLowerCase()) {
@@ -156,7 +156,8 @@ column_constraint = (CONSTRAINT __ constraint_name:identifier __)?
156
156
  type: "fk",
157
157
  value: {
158
158
  endpoint: {
159
- tableName: reftable,
159
+ tableName: reftable.name,
160
+ schemaName: reftable.schemaName,
160
161
  fieldNames: refcolumn ? [refcolumn] : null,
161
162
  relation: "1"
162
163
  },
@@ -192,7 +193,8 @@ table_constraint = (CONSTRAINT __ constraint_name:identifier __)?
192
193
  relation: "*",
193
194
  },
194
195
  {
195
- tableName: reftable,
196
+ tableName: reftable.name,
197
+ schemaName: reftable.schemaName,
196
198
  fieldNames: refcolumn,// ? refcolumn[key] : null,
197
199
  relation: "1",
198
200
  },
@@ -6,7 +6,7 @@ create_table_of =
6
6
  (__ ON __ COMMIT __ (PRESERVE __ ROWS/ DELETE __ ROWS/ DROP))?
7
7
  (__ TABLESPACE __ tablespace_name:identifier)?
8
8
  _ semicolon _ {
9
- const table = { name: table_name, type: type_name}
9
+ const table = { name: table_name.name, schemaName: table_name.schemaName, type: type_name}
10
10
  return {
11
11
  syntax_name: "create_table_of",
12
12
  value: table
@@ -7,7 +7,7 @@ create_table_partition_of =
7
7
  (__ ON __ COMMIT __ (PRESERVE __ ROWS/ DELETE __ ROWS/ DROP))?
8
8
  (__ TABLESPACE __ tablespace_name:identifier)?
9
9
  _ semicolon _ {
10
- const table = { name: table_name, parent_table: parent_table}
10
+ const table = { name: table_name.name, schemaName: table_name.schemaName, parent_table: parent_table}
11
11
  return {
12
12
  syntax_name: "create_table_partition_of",
13
13
  value: table
@@ -1,12 +1,12 @@
1
1
  create_type_enum =
2
- _ CREATE __ TYPE __ name:identifier __ AS __ ENUM _
2
+ _ CREATE __ TYPE __ enumName:enum_name __ AS __ ENUM _
3
3
  "(" _ labels:labels _ ")"
4
4
  _ semicolon _ {
5
5
  const values = labels.map(name => ({ name }))
6
6
  return {
7
7
  syntax_name: "create_type_enum",
8
8
  value: {
9
- name,
9
+ ...enumName,
10
10
  values,
11
11
  }
12
12
  }
@@ -8,10 +8,19 @@ ignore_syntax = _ value:(
8
8
  / CREATE __ SEQUENCE [^;]* { return { syntax_name: "create_sequence" } }
9
9
  / CREATE __ SCHEMA [^;]* { return { syntax_name: "create_schema" } }
10
10
  / CREATE __ VIEW [^;]* { return { syntax_name: "create_view" } }
11
+ / ALTER __ (cmt / !(semicolon) .)* { return { syntax_name: "alter_not_table" } }
11
12
  / __ { return { syntax_name: "comment_and_space" } }
12
13
  ) semicolon _ {
14
+ const loc = location();
15
+ const t = text();
13
16
  return {
14
17
  command_name: "ignore_syntax",
15
- value
18
+ value,
19
+ warning: {
20
+ type: 'ignore',
21
+ location: loc,
22
+ text: t,
23
+ message: `ignoring "${t}" at line: ${loc.start.line}`,
24
+ },
16
25
  }
17
26
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  // intput:
3
- // `
3
+ // `
4
4
  // 'created'
5
- // ,
5
+ // ,
6
6
  // 'pending', 'done'
7
7
  // `
8
8
  // => `'created', 'pending', 'done'`
@@ -14,4 +14,16 @@
14
14
  });
15
15
  return arrAfterTrim.join(', ');
16
16
  }
17
+
18
+ // TODO: support configurable default schema name other than 'public'
19
+ const findTable = (schemaName, tableName) => {
20
+ const realSchemaName = schemaName || 'public';
21
+ const table = tables.find(table => {
22
+ const targetSchemaName = table.schemaName || 'public';
23
+ return targetSchemaName === realSchemaName && table.name === tableName;
24
+ });
25
+ return table;
26
+ };
27
+
28
+ const findField = (table, fieldName) => table.fields.find(field => field.name === fieldName);
17
29
  }
@@ -110,4 +110,8 @@ SELECT = "SELECT"i
110
110
  USE = "USE"i
111
111
  SEQUENCE = "SEQUENCE"i
112
112
  SCHEMA = "SCHEMA"i
113
- VIEW = "VIEW"i
113
+ VIEW = "VIEW"i
114
+ RENAME = "RENAME"i
115
+ OWNED = "OWNED"i
116
+ ATTACH = "ATTACH"i
117
+ DETACH = "DETACH"i
@@ -2,10 +2,12 @@
2
2
  const tables = [];
3
3
  const refs = [];
4
4
  const enums = [];
5
+ const warnings = [];
5
6
  }
6
7
 
7
8
  parser = commands:command* {
8
- commands.forEach(({ command_name, value: { syntax_name, value } }) => {
9
+ commands.forEach((cmd) => {
10
+ const { command_name, value: { syntax_name, value }, warning } = cmd;
9
11
  switch(command_name.toLowerCase()){
10
12
  case "create_table":
11
13
  const table = value;
@@ -23,6 +25,7 @@ parser = commands:command* {
23
25
  endpoints: [
24
26
  {
25
27
  tableName: table.name,
28
+ schemaName: table.schemaName,
26
29
  fieldNames: [field.name],
27
30
  relation: "*",
28
31
  },
@@ -70,7 +73,7 @@ parser = commands:command* {
70
73
  case "create_index":
71
74
  const { table_name } = value;
72
75
  delete value.table_name; // remove table_name from column
73
- const table_index = tables.find(table => table.name === table_name);
76
+ const table_index = findTable(table_name.schemaName, table_name.name);
74
77
  if (table_index.indexes) {
75
78
  table_index.indexes.push(value);
76
79
  } else {
@@ -103,18 +106,29 @@ parser = commands:command* {
103
106
  break;
104
107
  case "comment":
105
108
  switch(syntax_name.toLowerCase()) {
106
- case "column":
107
- const table_comment = tables.find(table => table.name === value.relation_name);
108
- const field_comment = table_comment.fields.find(field => field.name === value.column_name);
109
- field_comment.note = value.text;
109
+ case "column": {
110
+ const { schemaName, tableName, columnName } = value;
111
+ const foundTable = findTable(schemaName, tableName);
112
+ if (foundTable) {
113
+ const foundField = findField(foundTable, columnName);
114
+ if (foundField) foundField.note = value.text;
115
+ }
116
+ break;
117
+ }
118
+ case "table": {
119
+ const { schemaName, name: tableName } = value.table_name;
120
+ const foundTable = findTable(schemaName, tableName);
121
+ if (foundTable) foundTable.note = value.text;
110
122
  break;
123
+ }
111
124
  }
112
125
  break;
113
- case "ignore_commands":
126
+ case "ignore_syntax":
127
+ // warnings.push(warning);
114
128
  break;
115
129
  }
116
130
  })
117
- // console.log({tables, refs, enums, indexes});
131
+
118
132
  return {tables, refs, enums};
119
133
  }
120
134
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
9
9
 
10
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
10
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
11
11
 
12
12
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
13
13
 
@@ -2738,13 +2738,13 @@ function peg$parse(input, options) {
2738
2738
  }
2739
2739
 
2740
2740
  if (currentProp.onDelete) {
2741
- refProp = _objectSpread({}, refProp, {
2741
+ refProp = _objectSpread(_objectSpread({}, refProp), {}, {
2742
2742
  onDelete: currentProp.onDelete
2743
2743
  });
2744
2744
  }
2745
2745
 
2746
2746
  if (currentProp.onUpdate) {
2747
- refProp = _objectSpread({}, refProp, {
2747
+ refProp = _objectSpread(_objectSpread({}, refProp), {}, {
2748
2748
  onUpdate: currentProp.onUpdate
2749
2749
  });
2750
2750
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbml/core",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "> TODO: description",
5
5
  "author": "Holistics <dev@holistics.io>",
6
6
  "license": "Apache-2.0",
@@ -56,5 +56,5 @@
56
56
  "\\.(?!json$)[^.]*$": "jest-raw-loader"
57
57
  }
58
58
  },
59
- "gitHead": "f2ae87a2105a1c1ed1075eb181688adc985efeec"
59
+ "gitHead": "4a4ec93db569e677bf15eb53964bd6b26762a421"
60
60
  }