@deterministic-code/datasources-cli 0.1.3 → 0.1.5

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.
@@ -1,6 +1,6 @@
1
1
  import { createCasingStrategy } from "@deterministic-code/generators-common/casing-strategy";
2
2
  import { createDatasourceNaming } from "@deterministic-code/generators-common/datasource-naming";
3
- import { identityColumns, isCollectionField, isDictionaryType, isOwnerIdentityRef, persistedColumnFields } from "@deterministic-code/generators-common/spec-types";
3
+ import { identityColumns, isCollectionField, persistedColumnFields } from "@deterministic-code/generators-common/spec-types";
4
4
  const referenceOf = (references) => {
5
5
  if (references === void 0) return void 0;
6
6
  const [type, field] = [references].flat().join(".").split(".");
@@ -55,7 +55,7 @@ const planRepositories = (spec, dialect, settings) => {
55
55
  const tableType = expanded.get(table.name) ?? types.get(table.name) ?? full;
56
56
  const overlays = new Map(table.fields.map((field) => [field.name, field]));
57
57
  const projected = new Set(Object.values(authored.mapping ?? {}));
58
- const columns = (isDictionaryType(tableType) ? persistedColumnFields(tableType, expanded) : tableType.fields).filter((field) => !isCollectionField(field) && !projected.has(field.name));
58
+ const columns = persistedColumnFields(tableType, expanded).filter((field) => !projected.has(field.name));
59
59
  return [
60
60
  {
61
61
  specName: authored.name,
@@ -101,16 +101,21 @@ const relations = (authored, full, casing, types, expanded, repoName, identity)
101
101
  if (!isCollectionField(field)) continue;
102
102
  if (field.isMap === true) {
103
103
  const dict = expanded.get(field.base) ?? types.get(field.base);
104
- const owner = dict?.fields.find((item) => isOwnerIdentityRef(item.references, dict.name, expanded));
104
+ const owner = referenceOf(field.references);
105
105
  if (dict === void 0 || owner === void 0) continue;
106
- const via = named(dict.name);
106
+ const via = named(owner.type);
107
107
  const value = dict.fields.find((item) => item.name === "value");
108
- const nested = value === void 0 ? void 0 : expanded.get(value.base) ?? types.get(value.base);
108
+ const nested = value !== void 0 && value.kind === "type" && !value.isArray && value.isMap !== true ? expanded.get(value.base) ?? types.get(value.base) : void 0;
109
+ const roleColumn = (role) => {
110
+ const item = dict.fields.find((entry) => entry.name === role);
111
+ const ref2 = referenceOf(item?.references);
112
+ return ref2?.type === owner.type ? ref2.field : role;
113
+ };
109
114
  planned.push({
110
115
  destination: property(field.name),
111
116
  source,
112
- relatedKey: property(owner.name),
113
- relatedProperty: nested === void 0 ? property("value") : void 0,
117
+ relatedKey: property(owner.field),
118
+ relatedProperty: nested === void 0 ? property(roleColumn("value")) : void 0,
114
119
  kind: "dictionary",
115
120
  via: via.via,
116
121
  viaType: via.viaType
@@ -10,6 +10,6 @@ namespace Backend.Types.Datasource;
10
10
  {{/descriptionDoc}}public class {{className}}{{#hasExtends}} : {{&extendsType}}{{/hasExtends}}
11
11
  {
12
12
  {{#fields}}
13
- public {{csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}}{{/hasInitializer}};
13
+ public {{csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}};{{/hasInitializer}}
14
14
  {{/fields}}
15
15
  }
@@ -15,6 +15,6 @@ namespace Backend.Types.View;
15
15
  {{/descriptionDoc}}public class {{className}}{{#hasExtends}} : {{&extendsType}}{{/hasExtends}}
16
16
  {
17
17
  {{#fields}}
18
- public {{&csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}}{{/hasInitializer}};
18
+ public {{&csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}};{{/hasInitializer}}
19
19
  {{/fields}}
20
20
  }
@@ -10,6 +10,6 @@ namespace Backend.Types.Datasource;
10
10
  {{/descriptionDoc}}public class {{className}}{{#hasExtends}} : {{&extendsType}}{{/hasExtends}}
11
11
  {
12
12
  {{#fields}}
13
- public {{csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}}{{/hasInitializer}};
13
+ public {{csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}};{{/hasInitializer}}
14
14
  {{/fields}}
15
15
  }
@@ -15,6 +15,6 @@ namespace Backend.Types.View;
15
15
  {{/descriptionDoc}}public class {{className}}{{#hasExtends}} : {{&extendsType}}{{/hasExtends}}
16
16
  {
17
17
  {{#fields}}
18
- public {{&csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}}{{/hasInitializer}};
18
+ public {{&csType}} {{ident}} { get; set; }{{#hasInitializer}} = {{&initializer}};{{/hasInitializer}}
19
19
  {{/fields}}
20
20
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deterministic-code/datasources-code-generators",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/generateSql.js",
@@ -10,12 +10,12 @@
10
10
  "./sql/dialect-converters": "./dist/sql/dialect-converters.js"
11
11
  },
12
12
  "dependencies": {
13
- "@deterministic-code/datasources": "^0.1.3",
14
- "@deterministic-code/datasources-mysql": "^0.1.3",
15
- "@deterministic-code/datasources-oracle": "^0.1.3",
16
- "@deterministic-code/datasources-postgres": "^0.1.3",
17
- "@deterministic-code/datasources-sqlite": "^0.1.3",
18
- "@deterministic-code/datasources-sqlserver": "^0.1.3",
13
+ "@deterministic-code/datasources": "^0.1.5",
14
+ "@deterministic-code/datasources-mysql": "^0.1.5",
15
+ "@deterministic-code/datasources-oracle": "^0.1.5",
16
+ "@deterministic-code/datasources-postgres": "^0.1.5",
17
+ "@deterministic-code/datasources-sqlite": "^0.1.5",
18
+ "@deterministic-code/datasources-sqlserver": "^0.1.5",
19
19
  "@deterministic-code/deterministic-generators-common": "0.1.0",
20
20
  "@deterministic-code/generators-common": "0.0.1",
21
21
  "pluralize": "^8.0.0",
@@ -488,7 +488,10 @@ var isMap = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
488
488
  var isString = (v) => typeof v === "string";
489
489
  var isFiniteNumber = (v) => typeof v === "number" && Number.isFinite(v);
490
490
  var isFiniteInt = (v) => isFiniteNumber(v) && Number.isInteger(v);
491
+ var isEmptyList = (v) => Array.isArray(v) && v.length === 0;
492
+ var isEmptyMap = (v) => isMap(v) && Object.keys(v).length === 0;
491
493
  var isLiteral = (v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean";
494
+ var isFieldDefault = (v) => isLiteral(v) || isEmptyList(v) || isEmptyMap(v);
492
495
  var yamlNode = (value, path = "$") => {
493
496
  const record = isMap(value) ? value : void 0;
494
497
  const at = (key) => record?.[key];
@@ -509,6 +512,7 @@ var yamlNode = (value, path = "$") => {
509
512
  finiteNumber: pick(isFiniteNumber),
510
513
  finiteInt: pick(isFiniteInt),
511
514
  literal: pick(isLiteral),
515
+ fieldDefault: pick(isFieldDefault),
512
516
  strings: (key) => {
513
517
  const v = at(key);
514
518
  return Array.isArray(v) ? v.filter(isString) : [];
@@ -614,7 +618,7 @@ var Parser = class {
614
618
  constructor(reader) {
615
619
  this.#reader = reader;
616
620
  }
617
- async parse(settings, opts) {
621
+ async parse(_settings, opts) {
618
622
  const reader = this.#reader;
619
623
  const serviceClassName = opts?.serviceClassName ?? ((entity) => entity);
620
624
  const [hasTypes, hasDs, hasSeeds, hasServices, hasRoutes] = await Promise.all([
@@ -693,6 +697,7 @@ var Parser = class {
693
697
  const references = referencesOf(node);
694
698
  const size = sizeOf(node);
695
699
  const minSize = node.finiteInt("min_size");
700
+ const collectionDefault = parsed.isArray ? [] : parsed.isMap ? {} : void 0;
696
701
  return {
697
702
  name,
698
703
  type: rawType,
@@ -705,7 +710,7 @@ var Parser = class {
705
710
  ...size !== void 0 ? { size } : {},
706
711
  ...minSize !== void 0 ? { minSize } : {},
707
712
  ...references !== void 0 ? { references } : {},
708
- ...node.has("default_value") ? { hasDefault: true, defaultValue: node.literal("default_value") } : {}
713
+ ...node.has("default_value") ? { hasDefault: true, defaultValue: node.fieldDefault("default_value") } : collectionDefault !== void 0 ? { hasDefault: true, defaultValue: collectionDefault } : {}
709
714
  };
710
715
  }
711
716
  #parseDatasource(yaml, types) {
@@ -1105,7 +1110,7 @@ var Parser = class {
1105
1110
  }
1106
1111
  }
1107
1112
  }
1108
- #extractCustomRoutes(root, dsByName, typeByName) {
1113
+ #extractCustomRoutes(root, _dsByName, typeByName) {
1109
1114
  const customs = [];
1110
1115
  for (const entry of root.child("routes").items()) {
1111
1116
  if (entry.record === void 0) continue;
@@ -179,7 +179,7 @@ class Parser {
179
179
  }
180
180
 
181
181
  async parse(
182
- settings: Record<string, string>,
182
+ _settings: Record<string, string>,
183
183
  opts?: { serviceClassName?: (entity: string) => string },
184
184
  ): Promise<IDeterministic> {
185
185
  const reader = this.#reader;
@@ -285,6 +285,7 @@ class Parser {
285
285
  const references = referencesOf(node);
286
286
  const size = sizeOf(node);
287
287
  const minSize = node.finiteInt("min_size");
288
+ const collectionDefault = parsed.isArray ? [] : parsed.isMap ? {} : undefined;
288
289
  return {
289
290
  name,
290
291
  type: rawType,
@@ -298,8 +299,10 @@ class Parser {
298
299
  ...(minSize !== undefined ? { minSize } : {}),
299
300
  ...(references !== undefined ? { references } : {}),
300
301
  ...(node.has("default_value")
301
- ? { hasDefault: true, defaultValue: node.literal("default_value") }
302
- : {}),
302
+ ? { hasDefault: true, defaultValue: node.fieldDefault("default_value") }
303
+ : collectionDefault !== undefined
304
+ ? { hasDefault: true, defaultValue: collectionDefault }
305
+ : {}),
303
306
  };
304
307
  }
305
308
 
@@ -838,7 +841,7 @@ class Parser {
838
841
 
839
842
  #extractCustomRoutes(
840
843
  root: YamlNode,
841
- dsByName: Map<string, DatasourceTable>,
844
+ _dsByName: Map<string, DatasourceTable>,
842
845
  typeByName: Map<string, Type>,
843
846
  ): CustomRouteEntry[] {
844
847
  const customs: CustomRouteEntry[] = [];
@@ -21,7 +21,7 @@ export type TypeField = {
21
21
  minSize?: number;
22
22
  references?: string | [string, string];
23
23
  hasDefault?: boolean;
24
- defaultValue?: string | number | boolean | null;
24
+ defaultValue?: string | number | boolean | null | object;
25
25
  };
26
26
 
27
27
  /** Primary label. `inherit` may also carry `union` — those members compose. */
@@ -3,6 +3,7 @@ import { parse } from "yaml";
3
3
  type YamlLiteral = string | number | boolean | null;
4
4
  type YamlMap = { readonly [key: string]: YamlValue };
5
5
  type YamlValue = YamlLiteral | YamlValue[] | YamlMap;
6
+ type FieldDefault = YamlLiteral | YamlValue[] | YamlMap;
6
7
  type Named = { name: string; node: YamlNode };
7
8
 
8
9
  const isMap = (v: YamlValue | undefined): v is YamlMap =>
@@ -16,12 +17,21 @@ const isFiniteNumber = (v: YamlValue | undefined): v is number =>
16
17
  const isFiniteInt = (v: YamlValue | undefined): v is number =>
17
18
  isFiniteNumber(v) && Number.isInteger(v);
18
19
 
20
+ const isEmptyList = (v: YamlValue | undefined): v is YamlValue[] =>
21
+ Array.isArray(v) && v.length === 0;
22
+
23
+ const isEmptyMap = (v: YamlValue | undefined): v is YamlMap =>
24
+ isMap(v) && Object.keys(v).length === 0;
25
+
19
26
  const isLiteral = (v: YamlValue | undefined): v is YamlLiteral =>
20
27
  v === null ||
21
28
  typeof v === "string" ||
22
29
  typeof v === "number" ||
23
30
  typeof v === "boolean";
24
31
 
32
+ const isFieldDefault = (v: YamlValue | undefined): v is FieldDefault =>
33
+ isLiteral(v) || isEmptyList(v) || isEmptyMap(v);
34
+
25
35
  /** Typed cursor over a YAML value. Missing keys are empty nodes, not throws. */
26
36
  export type YamlNode = {
27
37
  readonly value: YamlValue | undefined;
@@ -34,6 +44,7 @@ export type YamlNode = {
34
44
  finiteNumber: (key: string) => number | undefined;
35
45
  finiteInt: (key: string) => number | undefined;
36
46
  literal: (key: string) => YamlLiteral | undefined;
47
+ fieldDefault: (key: string) => FieldDefault | undefined;
37
48
  strings: (key: string) => string[];
38
49
  items: () => YamlNode[];
39
50
  namedItems: () => Named[];
@@ -66,6 +77,7 @@ const yamlNode = (value: YamlValue | undefined, path = "$"): YamlNode => {
66
77
  finiteNumber: pick(isFiniteNumber),
67
78
  finiteInt: pick(isFiniteInt),
68
79
  literal: pick(isLiteral),
80
+ fieldDefault: pick(isFieldDefault),
69
81
  strings: (key) => {
70
82
  const v = at(key);
71
83
  return Array.isArray(v) ? v.filter(isString) : [];
@@ -32,6 +32,6 @@ export declare const dictionaryEntryFields: (dict: Type) => {
32
32
  value: TypeField;
33
33
  } | undefined;
34
34
  export declare const dictionaryOfField: (field: TypeField, byName: Map<string, Type>) => Type | undefined;
35
- export declare const persistedColumnFields: (type: Type, byName: Map<string, Type>) => TypeField[];
35
+ export declare const persistedColumnFields: (type: Type, _byName?: Map<string, Type>) => TypeField[];
36
36
  export declare const dictionaryUniqueColumns: (type: Type, byName: Map<string, Type>) => string[];
37
37
  export {};
@@ -112,23 +112,31 @@ const dictionaryOfField = (field, byName) => {
112
112
  const dict = byName.get(field.base);
113
113
  return isDictionaryType(dict) ? dict : void 0;
114
114
  };
115
- const persistedColumnFields = (type, byName) => {
116
- if (!isDictionaryType(type)) return columnFields(type.fields);
117
- const value = type.fields.find((f) => f.name === "value");
118
- if (value === void 0 || value.kind !== "type" || value.isArray || value.isMap === true) {
119
- return columnFields(type.fields);
115
+ const persistedColumnFields = (type, _byName) => columnFields(type.fields);
116
+ const roleColumn = (dict, role, tableName) => {
117
+ const field = dict.fields.find((item) => item.name === role);
118
+ const references = field?.references;
119
+ if (typeof references === "string") {
120
+ const [table, column] = references.split(".");
121
+ if (table === tableName && column !== void 0 && column.length > 0) {
122
+ return column;
123
+ }
120
124
  }
121
- const nested = byName.get(value.base);
122
- if (nested === void 0) return columnFields(type.fields);
123
- return [
124
- ...columnFields(type.fields.filter((f) => f.name !== "value")),
125
- ...columnFields(nested.fields)
126
- ];
125
+ return role;
127
126
  };
128
127
  const dictionaryUniqueColumns = (type, byName) => {
129
- if (!isDictionaryType(type)) return [];
130
- const owners = type.fields.filter((f) => isOwnerIdentityRef(f.references, type.name, byName)).map((f) => f.name);
131
- return type.fields.some((f) => f.name === "key") ? [...owners, "key"] : owners;
128
+ for (const candidate of byName.values()) {
129
+ for (const field of candidate.fields) {
130
+ if (field.isMap !== true) continue;
131
+ const dict = byName.get(field.base);
132
+ if (!isDictionaryType(dict) || dict === void 0) continue;
133
+ if (typeof field.references !== "string") continue;
134
+ const [table, owner] = field.references.split(".");
135
+ if (table !== type.name || owner === void 0 || owner.length === 0) continue;
136
+ return [owner, roleColumn(dict, "key", type.name)];
137
+ }
138
+ }
139
+ return [];
132
140
  };
133
141
  export {
134
142
  DATASOURCE_SEEDS_YAML,
@@ -202,33 +202,35 @@ export const dictionaryOfField = (
202
202
 
203
203
  export const persistedColumnFields = (
204
204
  type: Type,
205
- byName: Map<string, Type>,
206
- ): TypeField[] => {
207
- if (!isDictionaryType(type)) return columnFields(type.fields);
208
- const value = type.fields.find((f) => f.name === "value");
209
- if (
210
- value === undefined ||
211
- value.kind !== "type" ||
212
- value.isArray ||
213
- value.isMap === true
214
- ) {
215
- return columnFields(type.fields);
205
+ _byName?: Map<string, Type>,
206
+ ): TypeField[] => columnFields(type.fields);
207
+
208
+ const roleColumn = (dict: Type, role: string, tableName: string): string => {
209
+ const field = dict.fields.find((item) => item.name === role);
210
+ const references = field?.references;
211
+ if (typeof references === "string") {
212
+ const [table, column] = references.split(".");
213
+ if (table === tableName && column !== undefined && column.length > 0) {
214
+ return column;
215
+ }
216
216
  }
217
- const nested = byName.get(value.base);
218
- if (nested === undefined) return columnFields(type.fields);
219
- return [
220
- ...columnFields(type.fields.filter((f) => f.name !== "value")),
221
- ...columnFields(nested.fields),
222
- ];
217
+ return role;
223
218
  };
224
219
 
225
220
  export const dictionaryUniqueColumns = (
226
221
  type: Type,
227
222
  byName: Map<string, Type>,
228
223
  ): string[] => {
229
- if (!isDictionaryType(type)) return [];
230
- const owners = type.fields
231
- .filter((f) => isOwnerIdentityRef(f.references, type.name, byName))
232
- .map((f) => f.name);
233
- return type.fields.some((f) => f.name === "key") ? [...owners, "key"] : owners;
224
+ for (const candidate of byName.values()) {
225
+ for (const field of candidate.fields) {
226
+ if (field.isMap !== true) continue;
227
+ const dict = byName.get(field.base);
228
+ if (!isDictionaryType(dict) || dict === undefined) continue;
229
+ if (typeof field.references !== "string") continue;
230
+ const [table, owner] = field.references.split(".");
231
+ if (table !== type.name || owner === undefined || owner.length === 0) continue;
232
+ return [owner, roleColumn(dict, "key", type.name)];
233
+ }
234
+ }
235
+ return [];
234
236
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deterministic-code/datasources-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "datasources": "./bin/datasources.mjs"
@@ -13,7 +13,7 @@
13
13
  "access": "public"
14
14
  },
15
15
  "dependencies": {
16
- "@deterministic-code/datasources-code-generators": "0.1.3",
16
+ "@deterministic-code/datasources-code-generators": "0.1.5",
17
17
  "@deterministic-code/generators-common": "0.0.1",
18
18
  "@deterministic-code/deterministic-generators-common": "0.1.0",
19
19
  "@deterministic-code/typescript-generators": "0.0.1",
@@ -21,12 +21,12 @@
21
21
  "@deterministic-code/rust-generators": "0.0.1",
22
22
  "@deterministic-code/generators-openapi": "0.0.1",
23
23
  "@deterministic-code/patch-merger": "0.1.0",
24
- "@deterministic-code/datasources": "^0.1.3",
25
- "@deterministic-code/datasources-sqlite": "^0.1.3",
26
- "@deterministic-code/datasources-mysql": "^0.1.3",
27
- "@deterministic-code/datasources-postgres": "^0.1.3",
28
- "@deterministic-code/datasources-sqlserver": "^0.1.3",
29
- "@deterministic-code/datasources-oracle": "^0.1.3",
24
+ "@deterministic-code/datasources": "^0.1.5",
25
+ "@deterministic-code/datasources-sqlite": "^0.1.5",
26
+ "@deterministic-code/datasources-mysql": "^0.1.5",
27
+ "@deterministic-code/datasources-postgres": "^0.1.5",
28
+ "@deterministic-code/datasources-sqlserver": "^0.1.5",
29
+ "@deterministic-code/datasources-oracle": "^0.1.5",
30
30
  "@inquirer/prompts": "^7.8.0",
31
31
  "yaml": "^2.6.0",
32
32
  "mustache": "^4.2.0",