@axinom/mosaic-cli 0.14.2-rc.8 → 0.15.0-rc.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.
Files changed (76) hide show
  1. package/package.json +6 -5
  2. package/src/cli/README.md +60 -0
  3. package/src/cli/index.ts +47 -0
  4. package/src/commands/apply-templates/apply-templates.spec.ts +623 -0
  5. package/src/commands/apply-templates/apply-templates.ts +494 -0
  6. package/src/commands/apply-templates/bitwarden-vault.ts +130 -0
  7. package/src/commands/apply-templates/index.ts +1 -0
  8. package/src/commands/create-extension-config/create-extension-config.ts +92 -0
  9. package/src/commands/create-extension-config/index.ts +23 -0
  10. package/src/commands/get-access-token/get-access-token-options.ts +9 -0
  11. package/src/commands/get-access-token/get-dev-access-token.ts +32 -0
  12. package/src/commands/get-access-token/index.ts +66 -0
  13. package/src/commands/graphql-diff.ts +143 -0
  14. package/src/commands/msg-codegen/codegen.ts +891 -0
  15. package/src/commands/msg-codegen/index.ts +48 -0
  16. package/src/commands/msg-codegen/lint.ts +84 -0
  17. package/src/commands/msg-codegen/message-codegen-options.ts +7 -0
  18. package/src/commands/msg-diff/asyncapi-override.ts +31 -0
  19. package/src/commands/msg-diff/git-checkout-tmp.ts +73 -0
  20. package/src/commands/msg-diff/index.ts +53 -0
  21. package/src/commands/msg-diff/message-diff-options.ts +7 -0
  22. package/src/commands/msg-diff/msg-diff.spec.ts +412 -0
  23. package/src/commands/msg-diff/msg-diff.ts +364 -0
  24. package/src/commands/msg-diff/test-resources/0/1-asyncapi.yml +38 -0
  25. package/src/commands/msg-diff/test-resources/0/2-asyncapi.yml +36 -0
  26. package/src/commands/msg-diff/test-resources/0/command.json +74 -0
  27. package/src/commands/msg-diff/test-resources/0/event.json +25 -0
  28. package/src/commands/msg-diff/test-resources/1/1-asyncapi.yml +25 -0
  29. package/src/commands/msg-diff/test-resources/1/moved-event.json +25 -0
  30. package/src/commands/msg-diff/test-resources/common.json +20 -0
  31. package/src/commands/pg-dump/README.md +21 -0
  32. package/src/commands/pg-dump/generate.ts +146 -0
  33. package/src/commands/pg-dump/index.ts +39 -0
  34. package/src/commands/pg-dump/pg-dump-options.ts +6 -0
  35. package/src/commands/publish-schema-to-db/README.md +130 -0
  36. package/src/commands/publish-schema-to-db/abstractions/base-smart-tags.ts +6 -0
  37. package/src/commands/publish-schema-to-db/abstractions/index.ts +5 -0
  38. package/src/commands/publish-schema-to-db/abstractions/pg-column.ts +31 -0
  39. package/src/commands/publish-schema-to-db/abstractions/pg-fk-column.ts +6 -0
  40. package/src/commands/publish-schema-to-db/abstractions/pg-table.ts +55 -0
  41. package/src/commands/publish-schema-to-db/abstractions/pg-type.ts +8 -0
  42. package/src/commands/publish-schema-to-db/content-entity-model.ts +93 -0
  43. package/src/commands/publish-schema-to-db/generate.ts +82 -0
  44. package/src/commands/publish-schema-to-db/index.ts +49 -0
  45. package/src/commands/publish-schema-to-db/jest.config.js +9 -0
  46. package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.spec.ts +42 -0
  47. package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.ts +41 -0
  48. package/src/commands/publish-schema-to-db/pg-models/columns/index.ts +4 -0
  49. package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.spec.ts +47 -0
  50. package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.ts +34 -0
  51. package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.spec.ts +65 -0
  52. package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.ts +62 -0
  53. package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.spec.ts +24 -0
  54. package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.ts +34 -0
  55. package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.spec.ts +182 -0
  56. package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.ts +166 -0
  57. package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.spec.ts +19 -0
  58. package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.ts +237 -0
  59. package/src/commands/publish-schema-to-db/pg-models/pgl-utils.spec.ts +19 -0
  60. package/src/commands/publish-schema-to-db/pg-models/pgl-utils.ts +115 -0
  61. package/src/commands/publish-schema-to-db/pg-models/tables/content-entity-table.ts +104 -0
  62. package/src/commands/publish-schema-to-db/pg-models/tables/index.ts +3 -0
  63. package/src/commands/publish-schema-to-db/pg-models/tables/object-property-table.ts +113 -0
  64. package/src/commands/publish-schema-to-db/pg-models/tables/relations-table.ts +115 -0
  65. package/src/commands/publish-schema-to-db/postprocessors/collection-postprocessor.ts +33 -0
  66. package/src/commands/publish-schema-to-db/postprocessors/content-entity-model-postprocessor.ts +13 -0
  67. package/src/commands/publish-schema-to-db/postprocessors/episode-postprocessor.ts +37 -0
  68. package/src/commands/publish-schema-to-db/postprocessors/index.ts +6 -0
  69. package/src/commands/publish-schema-to-db/postprocessors/movie-postprocessor.ts +30 -0
  70. package/src/commands/publish-schema-to-db/postprocessors/postprocessing-utils.ts +21 -0
  71. package/src/commands/publish-schema-to-db/postprocessors/season-postprocessor.ts +37 -0
  72. package/src/commands/publish-schema-to-db/postprocessors/tvshow-postprocessor.ts +30 -0
  73. package/src/commands/publish-schema-to-db/publish-schema-to-db-options.ts +15 -0
  74. package/src/commands/publish-schema-to-db/types/sql-formatter.d.ts +10 -0
  75. package/src/exports.ts +2 -0
  76. package/src/index.ts +1 -0
@@ -0,0 +1,42 @@
1
+ import { PgColumn, PgTable, PgType } from '../../abstractions';
2
+ import { FkColumn } from './fk-column';
3
+
4
+ interface FkColumnTestInput {
5
+ pkType: PgType;
6
+ expectedExpression: string;
7
+ }
8
+
9
+ const testData: [string, FkColumnTestInput][] = [
10
+ [
11
+ 'FK for TEXT PK',
12
+ {
13
+ pkType: 'TEXT',
14
+ expectedExpression: 'entity_id TEXT REFERENCES entity ON DELETE CASCADE',
15
+ },
16
+ ],
17
+ [
18
+ 'FK for INTEGER PK',
19
+ {
20
+ pkType: 'INTEGER',
21
+ expectedExpression:
22
+ 'entity_id INTEGER REFERENCES entity ON DELETE CASCADE',
23
+ },
24
+ ],
25
+ ];
26
+ describe('FkColumn', () => {
27
+ test.each(testData)('%s', (description: string, input: FkColumnTestInput) => {
28
+ // Arrange
29
+ const entityTablePk: PgColumn = {
30
+ name: 'id',
31
+ type: input.pkType,
32
+ table: { name: 'entity' } as PgTable,
33
+ } as PgColumn;
34
+ const propertyTable: PgTable = { name: 'object' } as PgTable;
35
+ const fk = new FkColumn(entityTablePk, propertyTable);
36
+ const expectedFkName = `${fk.table.name}_${fk.name}_fkey`;
37
+
38
+ // Act & Assert
39
+ expect(fk.buildExpression()).toBe(input.expectedExpression);
40
+ expect(fk.fkName).toBe(expectedFkName);
41
+ });
42
+ });
@@ -0,0 +1,41 @@
1
+ import {
2
+ BaseSmartTags,
3
+ PgColumn,
4
+ PgFkColumn,
5
+ PgTable,
6
+ PgType,
7
+ } from '../../abstractions';
8
+ import { buildName } from '../pg-sql-gen-utils';
9
+
10
+ export class FkColumn implements PgFkColumn {
11
+ name: string;
12
+ readonly table: PgTable;
13
+ readonly type: PgType;
14
+ readonly referencedPk: PgColumn;
15
+ readonly targetPk: PgColumn;
16
+ readonly fkName: string;
17
+
18
+ /**
19
+ * Constructor for FkColumn.
20
+ * @param targetPk - PK to the 'target' table.
21
+ * @param table - Reference to the parent table.
22
+ */
23
+ constructor(targetPk: PgColumn, table: PgTable) {
24
+ this.targetPk = targetPk;
25
+ this.name = buildName(targetPk.table.name, targetPk.name);
26
+ this.table = table;
27
+ this.fkName = buildName(table.name, this.name, 'fkey');
28
+ this.type = targetPk.type;
29
+ this.referencedPk = targetPk;
30
+ }
31
+ buildSmartTags(): BaseSmartTags {
32
+ return {};
33
+ }
34
+
35
+ buildExpression(): string {
36
+ return `${this.name} ${this.type} REFERENCES ${this.referencedPk.table.name} ON DELETE CASCADE`;
37
+ }
38
+ buildAdditionalStatements(): string[] {
39
+ return [`CREATE INDEX ON ${this.table.buildFullName()} (${this.name})`];
40
+ }
41
+ }
@@ -0,0 +1,4 @@
1
+ export * from './fk-column';
2
+ export * from './pk-column';
3
+ export * from './primitive-column';
4
+ export * from './virtual-fk-column';
@@ -0,0 +1,47 @@
1
+ import { PgTable, PgType } from '../../abstractions';
2
+ import { PkColumn } from './pk-column';
3
+
4
+ interface PkColumnTestInput {
5
+ type: PgType;
6
+ expectedExpression: string;
7
+ }
8
+
9
+ const dummyTable: PgTable = {} as PgTable;
10
+
11
+ const testData: [string, PkColumnTestInput][] = [
12
+ [
13
+ 'PK with TEXT type',
14
+ { type: 'TEXT', expectedExpression: 'id TEXT PRIMARY KEY' },
15
+ ],
16
+ [
17
+ 'PK with INTEGER type',
18
+ {
19
+ type: 'INTEGER',
20
+ expectedExpression:
21
+ 'id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY',
22
+ },
23
+ ],
24
+ ];
25
+
26
+ describe('PkColumn', () => {
27
+ test.each(testData)('%s', (description: string, input: PkColumnTestInput) => {
28
+ // Arrange
29
+ const pkColumn = new PkColumn(dummyTable, input.type);
30
+
31
+ // Act & Assert
32
+ expect(pkColumn.buildExpression()).toBe(input.expectedExpression);
33
+ });
34
+
35
+ test('PK column with unsupported type throws', () => {
36
+ // Arrange
37
+ const unsupportedType: PgType = 'BOOLEAN';
38
+
39
+ // Act
40
+ const action = (): void => {
41
+ new PkColumn(dummyTable, unsupportedType);
42
+ };
43
+
44
+ // Assert
45
+ expect(action).toThrow(TypeError);
46
+ });
47
+ });
@@ -0,0 +1,34 @@
1
+ import { BaseSmartTags, PgColumn, PgTable, PgType } from '../../abstractions';
2
+
3
+ export class PkColumn implements PgColumn {
4
+ name: string;
5
+ readonly table: PgTable;
6
+ readonly type: PgType;
7
+
8
+ constructor(table: PgTable, type: PgType) {
9
+ if (type !== 'INTEGER' && type !== 'TEXT') {
10
+ throw new TypeError(`Type ${type} not supported as primary key.`);
11
+ }
12
+
13
+ this.name = 'id';
14
+ this.table = table;
15
+ this.type = type;
16
+ }
17
+ buildSmartTags(): BaseSmartTags {
18
+ return {};
19
+ }
20
+
21
+ buildAdditionalStatements(): string[] {
22
+ return [];
23
+ }
24
+
25
+ buildExpression(): string {
26
+ let sql = `${this.name} ${this.type} PRIMARY KEY`;
27
+
28
+ if (this.type === 'INTEGER') {
29
+ sql = `${sql} GENERATED BY DEFAULT AS IDENTITY`;
30
+ }
31
+
32
+ return sql;
33
+ }
34
+ }
@@ -0,0 +1,65 @@
1
+ import { PgTable } from '../../abstractions';
2
+ import { PrimitiveColumn } from './primitive-column';
3
+
4
+ const dummyTable: PgTable = {
5
+ name: 'some_table',
6
+ buildFullName: () => 'schema.some_table',
7
+ } as PgTable;
8
+
9
+ describe('PrimitiveColumn', () => {
10
+ test('Default constructor', () => {
11
+ // Arrange & Act
12
+ const column = new PrimitiveColumn('some_column', 'TEXT', dummyTable);
13
+
14
+ // Assert
15
+ expect(column.buildExpression()).toBe('some_column TEXT');
16
+ });
17
+
18
+ test('Options with extraParams', () => {
19
+ // Arrange & Act
20
+ const column = new PrimitiveColumn('some_column', 'TEXT', dummyTable, {
21
+ extraParams: 'NOT NULL',
22
+ });
23
+
24
+ // Assert
25
+ expect(column.buildExpression()).toBe('some_column TEXT NOT NULL');
26
+ });
27
+
28
+ test('Options with indexable', () => {
29
+ // Arrange & Act
30
+ const column = new PrimitiveColumn('some_column', 'TEXT', dummyTable, {
31
+ indexable: true,
32
+ });
33
+
34
+ // Assert
35
+ expect(column.buildAdditionalStatements()).toEqual([
36
+ 'CREATE INDEX ON schema.some_table (some_column)',
37
+ ]);
38
+ });
39
+
40
+ test('Options with description', () => {
41
+ // Arrange & Act
42
+ const column = new PrimitiveColumn('some_column', 'TEXT', dummyTable, {
43
+ description: 'some description',
44
+ });
45
+
46
+ // Assert
47
+ expect(column.buildSmartTags()).toEqual({
48
+ description: 'some description',
49
+ });
50
+ });
51
+
52
+ test('Setting a display name', () => {
53
+ // Arrange
54
+ const column = new PrimitiveColumn('some_column', 'TEXT', dummyTable);
55
+
56
+ // Act
57
+ column.displayName = 'column';
58
+
59
+ // Assert
60
+ expect(column.buildSmartTags()).toEqual({
61
+ description: undefined,
62
+ tags: { name: 'column' },
63
+ });
64
+ });
65
+ });
@@ -0,0 +1,62 @@
1
+ import { BaseSmartTags, PgColumn, PgTable, PgType } from '../../abstractions';
2
+
3
+ export interface PrimitiveColumnOptions {
4
+ description?: string;
5
+ indexable?: boolean;
6
+ extraParams?: string;
7
+ }
8
+
9
+ /**
10
+ * Database column of primitive type.
11
+ */
12
+ export class PrimitiveColumn implements PgColumn {
13
+ name: string;
14
+ displayName?: string;
15
+ readonly description?: string;
16
+ readonly table: PgTable;
17
+ readonly type: PgType;
18
+ private columnOptions?: PrimitiveColumnOptions;
19
+
20
+ constructor(
21
+ name: string,
22
+ type: PgType,
23
+ table: PgTable,
24
+ options?: PrimitiveColumnOptions,
25
+ ) {
26
+ this.name = name;
27
+ this.description = options?.description;
28
+ this.table = table;
29
+ this.type = type;
30
+ this.columnOptions = options;
31
+ }
32
+
33
+ buildExpression(): string {
34
+ const baseExpression = `${this.name} ${this.type}`;
35
+ if (this.columnOptions?.extraParams) {
36
+ return `${baseExpression} ${this.columnOptions.extraParams}`;
37
+ }
38
+
39
+ return baseExpression;
40
+ }
41
+
42
+ buildAdditionalStatements(): string[] {
43
+ if (this.columnOptions?.indexable) {
44
+ return [`CREATE INDEX ON ${this.table.buildFullName()} (${this.name})`];
45
+ }
46
+ return [];
47
+ }
48
+
49
+ buildSmartTags(): BaseSmartTags {
50
+ const tags: BaseSmartTags = {
51
+ description: this.description,
52
+ };
53
+
54
+ if (this.displayName) {
55
+ tags.tags = {
56
+ name: this.displayName,
57
+ };
58
+ }
59
+
60
+ return tags;
61
+ }
62
+ }
@@ -0,0 +1,24 @@
1
+ import { PgColumn, PgTable } from '../../abstractions';
2
+ import { VirtualFkColumn } from './virtual-fk-column';
3
+
4
+ describe('VirtualFkColumn', () => {
5
+ test('Virtual FK is created with correct references', () => {
6
+ // Arrange & Act
7
+ const entityTablePk: PgColumn = {
8
+ name: 'id',
9
+ type: 'TEXT',
10
+ table: { name: 'entity' } as PgTable,
11
+ } as PgColumn;
12
+ const relationsTable: PgTable = {
13
+ name: 'entity_relation',
14
+ buildFullName: () => 'schema.entity_relation',
15
+ } as PgTable;
16
+ const virtualFkColumn = new VirtualFkColumn(entityTablePk, relationsTable);
17
+
18
+ // Assert
19
+ expect(virtualFkColumn.buildExpression()).toBe('entity_id TEXT');
20
+ expect(virtualFkColumn.buildAdditionalStatements()).toEqual([
21
+ 'CREATE INDEX ON schema.entity_relation (entity_id)',
22
+ ]);
23
+ });
24
+ });
@@ -0,0 +1,34 @@
1
+ import {
2
+ BaseSmartTags,
3
+ PgColumn,
4
+ PgFkColumn,
5
+ PgTable,
6
+ PgType,
7
+ } from '../../abstractions';
8
+ import { buildName } from '../pg-sql-gen-utils';
9
+
10
+ export class VirtualFkColumn implements PgFkColumn {
11
+ name: string;
12
+ readonly table: PgTable;
13
+ readonly type: PgType;
14
+ readonly additionalStatements: string[] = [];
15
+ readonly targetPk: PgColumn;
16
+
17
+ constructor(targetPk: PgColumn, table: PgTable) {
18
+ this.targetPk = targetPk;
19
+ this.name = buildName(targetPk.table.name, targetPk.name);
20
+ // Right now we just assume that all content types have the same PK type.
21
+ this.type = targetPk.type;
22
+ this.table = table;
23
+ }
24
+ buildSmartTags(): BaseSmartTags {
25
+ return {};
26
+ }
27
+ buildExpression(): string {
28
+ return `${this.name} ${this.type}`;
29
+ }
30
+
31
+ buildAdditionalStatements(): string[] {
32
+ return [`CREATE INDEX ON ${this.table.buildFullName()} (${this.name})`];
33
+ }
34
+ }
@@ -0,0 +1,182 @@
1
+ import { JSONSchema4 } from 'json-schema';
2
+ import { PgType } from '../abstractions';
3
+ import { getPropertySchema, mapToPgType } from './json-schema-parse-utils';
4
+
5
+ describe('mapToPgType', () => {
6
+ interface TestInput {
7
+ schemaJson: string;
8
+ expectedPgType: PgType;
9
+ }
10
+
11
+ // I wish there was a better way - https://github.com/facebook/jest/issues/6413
12
+ const testData: [string, TestInput][] = [
13
+ [
14
+ 'parse integer',
15
+ {
16
+ schemaJson: `
17
+ {
18
+ "$schema": "http://json-schema.org/draft-04/schema",
19
+ "properties": {
20
+ "prop":{
21
+ "type": "integer"
22
+ }
23
+ }
24
+ }
25
+ `,
26
+ expectedPgType: 'INTEGER',
27
+ },
28
+ ],
29
+ [
30
+ 'parse integer array',
31
+ {
32
+ schemaJson: `
33
+ {
34
+ "$schema": "http://json-schema.org/draft-04/schema",
35
+ "properties": {
36
+ "prop": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "integer"
40
+ }
41
+ }
42
+ }
43
+ }
44
+ `,
45
+ expectedPgType: 'INTEGER[]',
46
+ },
47
+ ],
48
+ [
49
+ 'parse string',
50
+ {
51
+ schemaJson: `
52
+ {
53
+ "$schema": "http://json-schema.org/draft-04/schema",
54
+ "properties": {
55
+ "prop": {
56
+ "type": "string"
57
+ }
58
+ }
59
+ }
60
+ `,
61
+ expectedPgType: 'TEXT',
62
+ },
63
+ ],
64
+ [
65
+ 'parse string array',
66
+ {
67
+ schemaJson: `
68
+ {
69
+ "$schema": "http://json-schema.org/draft-04/schema",
70
+ "properties": {
71
+ "prop": {
72
+ "type": "array",
73
+ "items": {
74
+ "type": "string"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ `,
80
+ expectedPgType: 'TEXT[]',
81
+ },
82
+ ],
83
+ [
84
+ 'parse boolean',
85
+ {
86
+ schemaJson: `
87
+ {
88
+ "$schema": "http://json-schema.org/draft-04/schema",
89
+ "properties": {
90
+ "prop": {
91
+ "type": "boolean"
92
+ }
93
+ }
94
+ }
95
+ `,
96
+ expectedPgType: 'BOOLEAN',
97
+ },
98
+ ],
99
+ [
100
+ 'parse date',
101
+ {
102
+ schemaJson: `
103
+ {
104
+ "$schema": "http://json-schema.org/draft-04/schema",
105
+ "properties": {
106
+ "prop": {
107
+ "type": "string",
108
+ "format": "date-time"
109
+ }
110
+ }
111
+ }
112
+ `,
113
+ expectedPgType: 'TIMESTAMPTZ',
114
+ },
115
+ ],
116
+ ];
117
+
118
+ test.each(testData)('%s', (description: string, input: TestInput) => {
119
+ // Arrange
120
+ const schema = JSON.parse(input.schemaJson) as JSONSchema4;
121
+
122
+ // Act
123
+ const pgType = mapToPgType(getPropertySchema(schema, 'prop'));
124
+
125
+ // Assert
126
+ expect(pgType).toBe(input.expectedPgType);
127
+ });
128
+ });
129
+
130
+ describe('getPropertySchema', () => {
131
+ test('Returns existing property', () => {
132
+ // Arrange
133
+ const schema = JSON.parse(`
134
+ {
135
+ "$schema": "http://json-schema.org/draft-04/schema",
136
+ "properties": {
137
+ "prop":{
138
+ "type": "integer"
139
+ }
140
+ }
141
+ }`) as JSONSchema4;
142
+
143
+ // Act
144
+ const propertySchema = getPropertySchema(schema, 'prop');
145
+
146
+ // Assert
147
+ expect(propertySchema).toBeDefined();
148
+ });
149
+
150
+ test('Throws if properties are not defined', () => {
151
+ // Arrange
152
+ const schema = JSON.parse(`
153
+ {
154
+ "$schema": "http://json-schema.org/draft-04/schema"
155
+ }`) as JSONSchema4;
156
+
157
+ // Act
158
+ const action = () => getPropertySchema(schema, 'prop');
159
+
160
+ // Assert
161
+ expect(action).toThrow(Error);
162
+ });
163
+
164
+ test('Returns undefined if property does not exist', () => {
165
+ // Arrange
166
+ const schema = JSON.parse(`
167
+ {
168
+ "$schema": "http://json-schema.org/draft-04/schema",
169
+ "properties": {
170
+ "prop":{
171
+ "type": "integer"
172
+ }
173
+ }
174
+ }`) as JSONSchema4;
175
+
176
+ // Act
177
+ const propertySchema = getPropertySchema(schema, 'does_not_exist');
178
+
179
+ // Assert
180
+ expect(propertySchema).toBeUndefined();
181
+ });
182
+ });