@axinom/mosaic-cli 0.14.2-rc.9 → 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,364 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable no-console */
3
+ import { diff, DiffOutputItem } from '@asyncapi/diff';
4
+ import { AsyncAPIDocument, Channel, parse } from '@asyncapi/parser';
5
+ import { green, red, white } from 'chalk';
6
+ import * as jsonDiff from 'diff';
7
+ import * as fs from 'fs';
8
+ import * as jsonSchemaDiff from 'json-schema-diff';
9
+ import * as path from 'path';
10
+ import { override } from './asyncapi-override';
11
+ import { GitCheckoutTmp } from './git-checkout-tmp';
12
+ import { MessageDiffOptions as MessageDiffOptions } from './message-diff-options';
13
+
14
+ /**
15
+ * Diff results. Each file (asyncapi document or payload) is classified to one of 'skipped', 'same', 'changed' or 'breaking'.
16
+ */
17
+ interface Results {
18
+ skipped: number;
19
+ same: number;
20
+ changed: number;
21
+ breaking: number;
22
+ }
23
+
24
+ /**
25
+ * Finds AsyncAPI documents found in git, and compares them with the current file system.
26
+ * The following changes are considered breaking:
27
+ * - Removed / renamed asyncapi document
28
+ * - Breaking changes in any asyncapi document
29
+ * - Breaking changes in any message payload
30
+ * Message payloads are referenced through asyncapi channel definitions. It is safe to rename payload files if
31
+ * file references in the asyncapi document are updated accordingly.
32
+ *
33
+ * @param options (object):
34
+ * schemaRoot Path to directory to scan. All files required to parse the schema must be inside this dir
35
+ * & subdirectories. This includes JSON Schema references.
36
+ * filePattern Regular expression that matches suitable input files.
37
+ * excludePattern Regular expression that matches suitable input files.
38
+ * branch Git branch to compare to.
39
+ * verbose Verbose output includes full diff for all files, not only where breaking changes were found.
40
+ */
41
+ export class MessageDiff {
42
+ private readonly schemaRoot: string;
43
+ private readonly filePattern: RegExp;
44
+ private readonly excludePattern: RegExp | undefined;
45
+ private readonly branch: string;
46
+ private readonly verbose: boolean;
47
+
48
+ public readonly results = {
49
+ skipped: 0,
50
+ same: 0,
51
+ changed: 0,
52
+ breaking: 0,
53
+ };
54
+
55
+ constructor(options: MessageDiffOptions) {
56
+ this.schemaRoot = path.resolve(options.inputDir);
57
+ this.branch = options.branch;
58
+ this.verbose = options.verbose;
59
+
60
+ try {
61
+ this.filePattern = new RegExp(options.filePattern);
62
+ } catch (error) {
63
+ console.error(
64
+ `${options.filePattern} is not a valid regular expression.`,
65
+ );
66
+ process.exit(2);
67
+ }
68
+ try {
69
+ this.excludePattern =
70
+ options.excludePattern === undefined
71
+ ? undefined
72
+ : new RegExp(options.excludePattern);
73
+ } catch (error) {
74
+ console.error(
75
+ `${options.excludePattern} is not a valid regular expression.`,
76
+ );
77
+ process.exit(2);
78
+ }
79
+ }
80
+
81
+ public async run(): Promise<void> {
82
+ // checkout branch to temp dir
83
+ const gitTmp = new GitCheckoutTmp();
84
+ gitTmp.checkout(this.schemaRoot, this.branch);
85
+ const rootDir1 = gitTmp.tmpDir;
86
+ const rootDir2 = gitTmp.gitRoot;
87
+ if (rootDir1 === undefined || rootDir2 === undefined) {
88
+ throw `Git checkout failed`;
89
+ }
90
+
91
+ // scan the checked out files
92
+ try {
93
+ const relPath = path.relative(rootDir2, this.schemaRoot);
94
+ await this.walk(
95
+ path.join(rootDir1, relPath),
96
+ path.join(rootDir2, relPath),
97
+ );
98
+ } finally {
99
+ // remove tmp files
100
+ gitTmp.cleanUp();
101
+ }
102
+
103
+ // check results
104
+ const totalFiles =
105
+ this.results.skipped +
106
+ this.results.same +
107
+ this.results.changed +
108
+ this.results.breaking;
109
+
110
+ if (totalFiles === 0) {
111
+ throw `No files found matching the given arguments`;
112
+ }
113
+
114
+ const color =
115
+ this.results.breaking > 0
116
+ ? red
117
+ : this.results.skipped > 0
118
+ ? white
119
+ : green;
120
+ console.log(
121
+ color(
122
+ `${totalFiles} file${totalFiles === 1 ? ' was' : 's were'} checked. ${
123
+ this.results.skipped
124
+ } ${this.results.skipped === 1 ? 'was' : 'were'} skipped. ${
125
+ this.results.same
126
+ } ${this.results.same === 1 ? 'is' : 'are'} the same. ${
127
+ this.results.changed
128
+ } ${
129
+ this.results.changed === 1 ? 'has' : 'have'
130
+ } non-breaking changes. ${this.results.breaking} ${
131
+ this.results.breaking === 1 ? 'has' : 'have'
132
+ } breaking changes.`,
133
+ ),
134
+ );
135
+
136
+ if (this.results.breaking > 0) {
137
+ process.exit(1);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Recursively walks a directory comparing matching files to another directory.
143
+ * @param dir1 - Root dir to scan for matching files.
144
+ * @param dir2 - Root dir for comparision.
145
+ */
146
+ public async walk(dir1: string, dir2: string): Promise<void> {
147
+ const items = await fs.promises.readdir(dir1);
148
+
149
+ const fullPathItems = items.map((i) => path.join(dir1, i));
150
+ const dirs = fullPathItems.filter((i) => fs.statSync(i).isDirectory());
151
+ const files = fullPathItems.filter(
152
+ (i) =>
153
+ fs.statSync(i).isFile() &&
154
+ this.filePattern.test(i) &&
155
+ (!this.excludePattern || !this.excludePattern.test(i)),
156
+ );
157
+
158
+ if ([...files, ...dirs].length === 0) {
159
+ return;
160
+ }
161
+
162
+ for (const file1 of files) {
163
+ const file2 = path.join(dir2, path.relative(dir1, file1));
164
+ await this.asyncApiDiff(file1, file2);
165
+ }
166
+
167
+ for (const subDir1 of dirs) {
168
+ const subDir2 = path.join(dir2, path.relative(dir1, subDir1));
169
+ await this.walk(subDir1, subDir2);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Full comparison of asyncapi documents. Each channel payload is also compared.
175
+ */
176
+ private async asyncApiDiff(file1: string, file2: string): Promise<void> {
177
+ console.log(
178
+ `Comparing asyncapi document '${file2}'. Changes from branch '${this.branch}':`,
179
+ );
180
+ let document1: AsyncAPIDocument;
181
+ let document2: AsyncAPIDocument;
182
+
183
+ // load asyncapi document from git
184
+ try {
185
+ const text = fs.readFileSync(file1, 'utf8');
186
+ document1 = await parse(text, { path: file1 });
187
+ } catch (e: any) {
188
+ throw `Error reading ${file1}: ${e}`;
189
+ }
190
+
191
+ // load local asyncapi document
192
+ try {
193
+ if (!fs.existsSync(file2)) {
194
+ console.log(
195
+ red(
196
+ `❌ File not found. This document may have been removed. Assuming this is a breaking change.`,
197
+ ),
198
+ );
199
+ this.results.breaking++;
200
+ return;
201
+ }
202
+ const text = fs.readFileSync(file2, 'utf8');
203
+ document2 = await parse(text, { path: file2 });
204
+ } catch (e: any) {
205
+ throw `Error reading ${file2}: ${e}`;
206
+ }
207
+
208
+ // diff document
209
+ const resultKey = await this.documentDiff(document1, document2);
210
+ this.results[resultKey]++;
211
+
212
+ const channels1 = document1.channels();
213
+ const channels2 = document2.channels();
214
+
215
+ // diff payloads for channels which exist in both documents
216
+ // removed / renamed channels are already marked as breaking
217
+ for (const [k, channel1] of Object.entries(channels1)) {
218
+ if (!(k in channels2)) {
219
+ continue;
220
+ }
221
+ console.log(
222
+ `Comparing payload for channel ${k} in document ${file2}. Changes from branch ${this.branch}`,
223
+ );
224
+ const channel2 = channels2[k];
225
+ const resultKey = await this.payloadDiff(channel1, channel2);
226
+ this.results[resultKey]++;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Compare asyncapi documents using AsyncAPI Diff: https://github.com/asyncapi/diff
232
+ * Note: non standard rules are defined in file: asyncapi-override.ts
233
+ */
234
+ public async documentDiff(
235
+ document1: AsyncAPIDocument,
236
+ document2: AsyncAPIDocument,
237
+ ): Promise<keyof Results> {
238
+ // generate diff
239
+ // overrides are applied through options here:
240
+ const output = diff(document1.json(), document2.json(), { override });
241
+ const breaking = output.breaking();
242
+ const nonBreaking = output.nonBreaking();
243
+ const unclassified = output.unclassified();
244
+
245
+ // log full results if breaking changes were found or verbose is set
246
+ const itemMsg = (change: string | DiffOutputItem): string =>
247
+ typeof change === 'string' ? change : `${change.action} ${change.path}`;
248
+
249
+ if (this.verbose) {
250
+ for (const item of unclassified) {
251
+ console.log(` ? ${itemMsg(item)}`);
252
+ }
253
+ }
254
+ if (breaking.length > 0 || this.verbose) {
255
+ for (const item of nonBreaking) {
256
+ console.log(` ✔ ${itemMsg(item)}`);
257
+ }
258
+ }
259
+ for (const item of breaking) {
260
+ console.log(` ✖ ${itemMsg(item)}`);
261
+ }
262
+
263
+ // log summary
264
+ const color = breaking.length > 0 ? red : green;
265
+ console.log(
266
+ color(
267
+ `${breaking.length > 0 ? '❌ ' : ''}${
268
+ nonBreaking.length
269
+ } non-breaking change${nonBreaking.length === 1 ? '' : 's'}, ${
270
+ breaking.length
271
+ } breaking change${
272
+ breaking.length === 1 ? '' : 's'
273
+ } in asyncapi document`,
274
+ ),
275
+ );
276
+
277
+ return breaking.length > 0
278
+ ? 'breaking'
279
+ : nonBreaking.length > 0
280
+ ? 'changed'
281
+ : 'same';
282
+ }
283
+
284
+ /**
285
+ * Compare payload schemas using JsonSchema Diff: https://www.npmjs.com/package/json-schema-diff
286
+ * NOTE: It might be possible to define rules for asyncapi-diff to compare properties in message schemas but
287
+ * it would not have the ability to properly evaluate breaking changes as json-schema-diff does.
288
+ * e.g. adding an existing property to the list of required properties is a breaking change.
289
+ *
290
+ * Only schema version http://json-schema.org/draft-07/schema# is supported.
291
+ * If any other version is used (in local file or git) then the comparison result will be 'skipped'.
292
+ */
293
+ public async payloadDiff(
294
+ channel1: Channel,
295
+ channel2: Channel,
296
+ ): Promise<keyof Results> {
297
+ const getChannelPayload = (channel: Channel): any => {
298
+ const json = channel.json();
299
+ return (json.subscribe ?? json.publish)?.message?.payload;
300
+ };
301
+ const schema1 = getChannelPayload(channel1);
302
+ const schema2 = getChannelPayload(channel2);
303
+ if (schema1 === undefined) {
304
+ throw `Could not find payload schema in ${this.branch}`;
305
+ }
306
+ if (schema2 === undefined) {
307
+ throw `Could not find payload schema`;
308
+ }
309
+
310
+ let result: jsonSchemaDiff.DiffResult;
311
+ try {
312
+ result = await jsonSchemaDiff.diffSchemas({
313
+ sourceSchema: schema1,
314
+ destinationSchema: schema2,
315
+ });
316
+ } catch (e: any) {
317
+ // Skip if unsupported schema version is used by either payload
318
+ if (
319
+ e instanceof Error &&
320
+ e.message.startsWith('no schema with key or ref')
321
+ ) {
322
+ console.log(
323
+ `WARNING: Unsupported JsonSchema version. This payload will be skipped. Both versions of the file must use $schema: "http://json-schema.org/draft-07/schema#".`,
324
+ );
325
+ return 'skipped';
326
+ }
327
+ throw e;
328
+ }
329
+
330
+ if (result.removalsFound || this.verbose) {
331
+ // json-schema-diff does not give a useful report of what are the breaking changes. See:
332
+ // https://bitbucket.org/atlassian/json-schema-diff/issues/6/is-it-supposed-to-report-only-what-has
333
+ // So we display a line-by-line diff of the schemas..its not targeted to what is breaking, but its more useful
334
+ // than just logging both versions in full which is the observed behavior of json-schema-diff.
335
+ const diffResult = jsonDiff.diffJson(schema1, schema2);
336
+ diffResult.forEach((r) => {
337
+ for (const line of r.value.split(/\r?\n/)) {
338
+ // strip blank lines and annotations added by asyncapi parser
339
+ if (!line || line.match(/^\s+"x-parser-schema/)) {
340
+ continue;
341
+ }
342
+ console.log(`${r.removed ? ' -' : r.added ? ' +' : ' '} ${line}`);
343
+ }
344
+ });
345
+ }
346
+
347
+ const color = result.removalsFound ? red : green;
348
+ console.log(
349
+ color(
350
+ result.removalsFound
351
+ ? '❌ Breaking changes in payload'
352
+ : result.additionsFound
353
+ ? 'No breaking changes in payload'
354
+ : 'No changes in payload',
355
+ ),
356
+ );
357
+
358
+ return result.removalsFound
359
+ ? 'breaking'
360
+ : result.additionsFound
361
+ ? 'changed'
362
+ : 'same';
363
+ }
364
+ }
@@ -0,0 +1,38 @@
1
+ asyncapi: 2.0.0
2
+ info:
3
+ title: Service 1
4
+ version: '1.0.0'
5
+ description: |
6
+ Testing 1
7
+ # AsyncAPI extension, used to define service id. If not defined, as service id will be used info.title in lower-kebab-case
8
+ x-service-id: ax-service-template
9
+
10
+ channels:
11
+ # commands
12
+ 'cmd-channel':
13
+ bindings:
14
+ amqp:
15
+ queue:
16
+ name: example_command
17
+ publish:
18
+ message:
19
+ $ref: '#/components/messages/command-ref'
20
+ # events
21
+ 'evt-channel':
22
+ bindings:
23
+ amqp:
24
+ queue:
25
+ name: example_event
26
+ publish:
27
+ message:
28
+ $ref: '#/components/messages/event-ref'
29
+ components:
30
+ messages:
31
+ command-ref:
32
+ contentType: application/json
33
+ payload:
34
+ $ref: 'command.json'
35
+ event-ref:
36
+ contentType: application/json
37
+ payload:
38
+ $ref: 'event.json'
@@ -0,0 +1,36 @@
1
+ asyncapi: 2.0.0
2
+ info:
3
+ title: Service 2
4
+ version: '1.0.0'
5
+ description: |
6
+ Testing 2
7
+
8
+ channels:
9
+ # commands
10
+ 'cmd-channel':
11
+ bindings:
12
+ amqp:
13
+ queue:
14
+ name: example_command
15
+ publish:
16
+ message:
17
+ $ref: '#/components/messages/command-ref'
18
+ # events
19
+ 'evt-channel':
20
+ bindings:
21
+ amqp:
22
+ queue:
23
+ name: example_event
24
+ publish:
25
+ message:
26
+ $ref: '#/components/messages/event-ref'
27
+ components:
28
+ messages:
29
+ command-ref:
30
+ contentType: application/json
31
+ payload:
32
+ $ref: 'command.json'
33
+ event-ref:
34
+ contentType: application/json
35
+ payload:
36
+ $ref: 'event.json'
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type":"object",
4
+ "title": "synchronize_claim_definitions_start_command",
5
+ "description": "Synchronize claim definitions start command schema.",
6
+ "additionalProperties": false,
7
+ "required": ["claim_definition_groups"],
8
+ "properties": {
9
+ "claim_definition_groups": {
10
+ "type": "array",
11
+ "description": "An array of claim definition groups to be registered.",
12
+ "items": {
13
+ "$ref": "#/definitions/claim_definition_group",
14
+ "description": "Defines a group of related claim definitions"
15
+ },
16
+ "minItems": 1
17
+ }
18
+ },
19
+ "definitions": {
20
+ "claim_definition_group": {
21
+ "type": "object",
22
+ "title": "claim_definition_group",
23
+ "additionalProperties": false,
24
+ "required": [
25
+ "title",
26
+ "selection_mode",
27
+ "claim_definitions"
28
+ ],
29
+ "properties": {
30
+ "title": {
31
+ "$ref": "../common.json#/definitions/non_empty_string",
32
+ "description": "Unique claim definition group title."
33
+ },
34
+ "selection_mode": {
35
+ "type": "string",
36
+ "title": "claim_selection_mode",
37
+ "description": "Selection options for a claim definition group.",
38
+ "enum": [
39
+ "SINGLE",
40
+ "MULTIPLE"
41
+ ]
42
+ },
43
+ "claim_definitions": {
44
+ "type": "array",
45
+ "description": "An array of claim definitions.",
46
+ "items": {
47
+ "$ref": "#/definitions/claim_definition",
48
+ "description": "Definition of a claim to be included in a claim set."
49
+ },
50
+ "minItems": 1
51
+ }
52
+ }
53
+ },
54
+ "claim_definition": {
55
+ "type": "object",
56
+ "title": "claim_definition",
57
+ "additionalProperties": false,
58
+ "required": [
59
+ "claim",
60
+ "title"
61
+ ],
62
+ "properties": {
63
+ "claim": {
64
+ "$ref": "../common.json#/definitions/non_empty_string",
65
+ "description": "The claim."
66
+ },
67
+ "title": {
68
+ "$ref": "../common.json#/definitions/non_empty_string",
69
+ "description": "Display name for the claim."
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type":"object",
4
+ "title": "example_post_created_event",
5
+ "description": "New post created event.",
6
+ "properties": {
7
+ "title": {
8
+ "description": "Title of the post.",
9
+ "type": "string"
10
+ },
11
+ "content": {
12
+ "description": "Post body, actual content.",
13
+ "type": "string"
14
+ },
15
+ "is_public": {
16
+ "description": "Indicates whether the post is public.",
17
+ "type": "boolean"
18
+ }
19
+ },
20
+ "additionalProperties": false,
21
+ "required": [
22
+ "title",
23
+ "content"
24
+ ]
25
+ }
@@ -0,0 +1,25 @@
1
+ asyncapi: 2.0.0
2
+ info:
3
+ title: Template Service
4
+ version: '1.0.0'
5
+ description: |
6
+ Template Management
7
+ # AsyncAPI extension, used to define service id. If not defined, as service id will be used info.title in lower-kebab-case
8
+ x-service-id: ax-service-template
9
+
10
+ channels:
11
+ # events
12
+ 'evt-channel':
13
+ bindings:
14
+ amqp:
15
+ queue:
16
+ name: example_event
17
+ publish:
18
+ message:
19
+ $ref: '#/components/messages/event-ref'
20
+ components:
21
+ messages:
22
+ event-ref:
23
+ contentType: application/json
24
+ payload:
25
+ $ref: 'moved-event.json'
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type":"object",
4
+ "title": "example_post_created_event",
5
+ "description": "New post created event.",
6
+ "properties": {
7
+ "title": {
8
+ "description": "Title of the post.",
9
+ "type": "string"
10
+ },
11
+ "content": {
12
+ "description": "Post body, actual content.",
13
+ "type": "string"
14
+ },
15
+ "is_public": {
16
+ "description": "Indicates whether the post is public.",
17
+ "type": "boolean"
18
+ }
19
+ },
20
+ "additionalProperties": false,
21
+ "required": [
22
+ "title",
23
+ "content"
24
+ ]
25
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "common",
4
+ "description": "Common definitions.",
5
+ "definitions": {
6
+ "non_empty_string": {
7
+ "type": "string",
8
+ "minLength": 1,
9
+ "pattern": "^$|.*\\S.*",
10
+ "description": "The string has a minimum length of one character and it cannot consist of only whitespace characters."
11
+ },
12
+ "non_empty_uuid": {
13
+ "type": "string",
14
+ "minLength": 32,
15
+ "maxLength": 36,
16
+ "format": "uuid",
17
+ "description": "A UUID."
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,21 @@
1
+ # Overview
2
+
3
+ Development command to create a database schema dump (using current service
4
+ config) and put it into `src/generated/db/schema.sql` file of the current
5
+ project.
6
+
7
+ Environment variables must be pre-loaded so that a database connection string
8
+ could be constructed.
9
+
10
+ Shadow database is used as a target to provide a clean schema dump. Shadow
11
+ database is re-created on each migration commit, migration uncommit, and
12
+ database reset in development as a testing ground for migrations, so it always
13
+ has up-to-date schema without unexpected changes.
14
+
15
+ Example call with preload can look like this:
16
+ `dotenv -- mosaic pg-dump -c scripts/infra`, where `dotenv` is a cli command to
17
+ load environment variables using `dotenv-cli` npm package. Alternatively,
18
+ `env-cmd` or some other tool can be used instead of `dotenv`
19
+
20
+ Example call without preload can look like this:
21
+ `mosaic pg-dump -c scripts/infra -s postgres://username:password@localhost:5432/database_name`