@fraym/crud 0.1.0 → 0.3.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.
package/README.md CHANGED
@@ -8,6 +8,24 @@ Client implementation in javascript for the CRUD service [streams](https://githu
8
8
  npm i @fraym/crud
9
9
  ```
10
10
 
11
+ ## CLI command
12
+
13
+ Use the `crud` cli command to automatically apply your crud schemas to the crud service.
14
+
15
+ The `--config ./path/crud.config.json` flag can be used to configure the path of your config file.
16
+
17
+ Your type schemas have to match the glob you specify in `schemaGlob` of he config file (default: `./src/**/*.graphql`).
18
+ You can specify the address (and port) of the crud service instance you use in `serverAddress` of the config file (default: `127.0.0.1:9000`).
19
+
20
+ ### CLI command config
21
+
22
+ ```json
23
+ {
24
+ "schemaGlob": "./src/crud/*.graphql", // path to your crud schema files
25
+ "serverAddress": "127.0.0.1:9000" // address of the crud service
26
+ }
27
+ ```
28
+
11
29
  ## Usage
12
30
 
13
31
  ### Create the clients
@@ -17,7 +35,6 @@ delivery client:
17
35
  ```typescript
18
36
  const deliveryClient = await newDeliveryClient({
19
37
  serverAddress: "127.0.0.1:9000",
20
- groupId: "your-services-group-identifier",
21
38
  });
22
39
  ```
23
40
 
@@ -26,7 +43,6 @@ management client:
26
43
  ```typescript
27
44
  const managementClient = await newManagementClient({
28
45
  serverAddress: "127.0.0.1:9000",
29
- groupId: "your-services-group-identifier",
30
46
  });
31
47
  ```
32
48
 
@@ -0,0 +1,2 @@
1
+ #! /usr/bin/env node
2
+ export {};
@@ -0,0 +1,218 @@
1
+ #! /usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const yargs_1 = __importDefault(require("yargs/yargs"));
9
+ const helpers_1 = require("yargs/helpers");
10
+ const client_1 = require("../management/client");
11
+ const load_1 = require("@graphql-tools/load");
12
+ const graphql_file_loader_1 = require("@graphql-tools/graphql-file-loader");
13
+ const graphql_1 = require("graphql");
14
+ const run = async () => {
15
+ const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
16
+ .config({ schemaGlob: "./src/**/*.graphql", serverAddress: "127.0.0.1:9000" })
17
+ .pkgConf("crud")
18
+ .config("config", "Path of your `crud.config.ts`, default: `./crud.config.ts`", configPath => JSON.parse(fs_1.default.readFileSync(configPath, "utf-8"))).argv;
19
+ const schemaGlob = argv.schemaGlob;
20
+ const serverAddress = argv.serverAddress;
21
+ const schema = await (0, load_1.loadSchema)(`${schemaGlob}`, {
22
+ loaders: [new graphql_file_loader_1.GraphQLFileLoader()],
23
+ });
24
+ const definitions = getTypeDefinition(schema);
25
+ await migrateSchemas(definitions, serverAddress);
26
+ };
27
+ run();
28
+ const getTypeDefinition = (schema) => {
29
+ const definitions = {};
30
+ schema.toConfig().types.forEach(t => {
31
+ var _a;
32
+ if (((_a = t.astNode) === null || _a === void 0 ? void 0 : _a.kind) !== graphql_1.Kind.OBJECT_TYPE_DEFINITION || !(t instanceof graphql_1.GraphQLObjectType)) {
33
+ return;
34
+ }
35
+ const name = t.toString();
36
+ if (definitions[name]) {
37
+ throw new Error(`duplicate definition for type "${name}" detected, try renaming one of them as they have to be uniquely named`);
38
+ }
39
+ definitions[name] = getTypeDefinitionFromGraphQLObjectType(t);
40
+ });
41
+ return definitions;
42
+ };
43
+ const getTypeDefinitionFromGraphQLObjectType = (t) => {
44
+ var _a, _b, _c, _d, _e, _f, _g;
45
+ const isCrudType = (_c = (((_a = t.astNode) === null || _a === void 0 ? void 0 : _a.directives) &&
46
+ ((_b = t.astNode) === null || _b === void 0 ? void 0 : _b.directives.length) > 0 &&
47
+ t.astNode.directives[0].name.value === "crudType")) !== null && _c !== void 0 ? _c : false;
48
+ const name = t.toString();
49
+ let objectDirectivesString = "";
50
+ let objectFieldsString = "";
51
+ let nestedTypes = [];
52
+ (_e = (_d = t.astNode) === null || _d === void 0 ? void 0 : _d.directives) === null || _e === void 0 ? void 0 : _e.forEach(d => {
53
+ objectDirectivesString += getDirectiveString(d);
54
+ });
55
+ (_g = (_f = t.astNode) === null || _f === void 0 ? void 0 : _f.fields) === null || _g === void 0 ? void 0 : _g.forEach(f => {
56
+ const { str, nestedTypes: newNestedTypes } = getFieldStringAndNestedTypes(f);
57
+ objectFieldsString += str;
58
+ newNestedTypes.forEach(nested => {
59
+ if (nestedTypes.indexOf(nested) === -1) {
60
+ nestedTypes.push(nested);
61
+ }
62
+ });
63
+ });
64
+ const schema = `type ${name}${objectDirectivesString} {${objectFieldsString}\n}`;
65
+ return {
66
+ isCrudType,
67
+ nestedTypes,
68
+ schema,
69
+ };
70
+ };
71
+ const getFieldStringAndNestedTypes = (f) => {
72
+ var _a;
73
+ let directivesString = "";
74
+ (_a = f.directives) === null || _a === void 0 ? void 0 : _a.forEach(d => {
75
+ directivesString += getDirectiveString(d);
76
+ });
77
+ const { nestedType, str: typeString } = getTypeData(f.type);
78
+ const nestedTypes = [];
79
+ if (nestedType) {
80
+ nestedTypes.push(nestedType);
81
+ }
82
+ return {
83
+ str: `\n${f.name.value}: ${typeString}${directivesString}`,
84
+ nestedTypes,
85
+ };
86
+ };
87
+ const getTypeData = (t) => {
88
+ switch (t.kind) {
89
+ case graphql_1.Kind.NAMED_TYPE:
90
+ const name = t.name.value;
91
+ return name === "String" ||
92
+ name === "Float" ||
93
+ name === "ID" ||
94
+ name === "Boolean" ||
95
+ name === "Int"
96
+ ? {
97
+ str: name,
98
+ }
99
+ : {
100
+ str: name,
101
+ nestedType: name,
102
+ };
103
+ case graphql_1.Kind.LIST_TYPE:
104
+ const { nestedType: listNestedType, str: listStr } = getTypeData(t.type);
105
+ return {
106
+ str: `[${listStr}]`,
107
+ nestedType: listNestedType,
108
+ };
109
+ case graphql_1.Kind.NON_NULL_TYPE:
110
+ const { nestedType: nonNullNestedType, str: nonNullStr } = getTypeData(t.type);
111
+ return {
112
+ str: `${nonNullStr}!`,
113
+ nestedType: nonNullNestedType,
114
+ };
115
+ }
116
+ };
117
+ const getDirectiveString = (d) => {
118
+ if (!d.arguments || d.arguments.length == 0) {
119
+ return ` @${d.name.value}`;
120
+ }
121
+ let argsString = "";
122
+ d.arguments.forEach(a => {
123
+ if (argsString !== "") {
124
+ argsString += ", ";
125
+ }
126
+ argsString += `${a.name.value}: ${getValueString(a.value)}`;
127
+ });
128
+ return ` @${d.name.value}(${argsString})`;
129
+ };
130
+ const getValueString = (v) => {
131
+ switch (v.kind) {
132
+ case graphql_1.Kind.LIST:
133
+ let valuesString = "";
134
+ v.values.forEach(el => {
135
+ if (valuesString !== "") {
136
+ valuesString += ", ";
137
+ }
138
+ valuesString += getValueString(el);
139
+ });
140
+ return `[${valuesString}]`;
141
+ case graphql_1.Kind.STRING:
142
+ return `"${v.value}"`;
143
+ case graphql_1.Kind.FLOAT:
144
+ case graphql_1.Kind.INT:
145
+ case graphql_1.Kind.BOOLEAN:
146
+ return `${v.value}`;
147
+ case graphql_1.Kind.NULL:
148
+ return `null`;
149
+ case graphql_1.Kind.OBJECT:
150
+ let objectString = "";
151
+ v.fields.forEach(f => {
152
+ if (objectString !== "") {
153
+ objectString += ", ";
154
+ }
155
+ objectString += `${f.name.value}: ${getValueString(f.value)}`;
156
+ });
157
+ return `{${objectString}}`;
158
+ default:
159
+ throw new Error(`values of kind ${v.kind} are currently not supported`);
160
+ }
161
+ };
162
+ const migrateSchemas = async (definitions, serverAddress) => {
163
+ const managementClient = await (0, client_1.newManagementClient)({ serverAddress });
164
+ const existingTypeNames = await managementClient.getAllTypes();
165
+ let createSchema = "";
166
+ let updateSchema = "";
167
+ const typesToCreate = [];
168
+ const nestedTypesToCreate = [];
169
+ const typesToUpdate = [];
170
+ const nestedTypesToUpdate = [];
171
+ const typesToRemove = [];
172
+ existingTypeNames.forEach(existingName => {
173
+ if (!definitions[existingName] || !definitions[existingName].isCrudType) {
174
+ typesToRemove.push(existingName);
175
+ }
176
+ else {
177
+ typesToUpdate.push(existingName);
178
+ updateSchema += `\n${definitions[existingName].schema}`;
179
+ definitions[existingName].nestedTypes.forEach(nestedTypeName => {
180
+ if (nestedTypesToUpdate.indexOf(nestedTypeName) !== -1) {
181
+ return;
182
+ }
183
+ updateSchema += `\n${definitions[nestedTypeName].schema}`;
184
+ nestedTypesToUpdate.push(nestedTypeName);
185
+ });
186
+ delete definitions[existingName];
187
+ }
188
+ });
189
+ Object.keys(definitions).forEach(newName => {
190
+ if (!definitions[newName].isCrudType) {
191
+ return;
192
+ }
193
+ typesToCreate.push(newName);
194
+ createSchema += `\n${definitions[newName].schema}`;
195
+ definitions[newName].nestedTypes.forEach(nestedTypeName => {
196
+ if (nestedTypesToCreate.indexOf(nestedTypeName) !== -1) {
197
+ return;
198
+ }
199
+ createSchema += `\n${definitions[nestedTypeName].schema}`;
200
+ nestedTypesToCreate.push(nestedTypeName);
201
+ });
202
+ });
203
+ if (typesToRemove.length > 0) {
204
+ console.log(`Removing ${typesToRemove.length} types: ${typesToRemove}...`);
205
+ await managementClient.removeTypes(typesToRemove).catch(console.log);
206
+ console.log(`Removed ${typesToRemove.length} types`);
207
+ }
208
+ if (typesToUpdate.length > 0) {
209
+ console.log(`Updating ${typesToUpdate.length} types: ${typesToUpdate}...`);
210
+ await managementClient.updateTypes(updateSchema).catch(console.log);
211
+ console.log(`Updated ${typesToUpdate.length} types`);
212
+ }
213
+ if (typesToCreate.length > 0) {
214
+ console.log(`Creating ${typesToCreate.length} types: ${typesToCreate}...`);
215
+ await managementClient.createTypes(createSchema).catch(console.log);
216
+ console.log(`Created ${typesToCreate.length} types`);
217
+ }
218
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraym/crud",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "license": "UNLICENSED",
5
5
  "homepage": "https://github.com/fraym/crud-nodejs",
6
6
  "repository": {
@@ -12,26 +12,37 @@
12
12
  "test": "echo \"Error: no test specified\" && exit 0",
13
13
  "format": "prettier --write \"**/*.{ts,tsx,json}\"",
14
14
  "lint": "prettier --check \"**/*.{ts,tsx,json}\"",
15
- "build": "npm run clean && tsc",
15
+ "build": "npm run clean && tsc && chmod +x dist/cmd/crud.js",
16
16
  "clean": "rm -rf dist",
17
17
  "prepublishOnly": "npm test && npm run lint && npm run build",
18
- "preversion": "npm run lint"
18
+ "preversion": "npm run lint",
19
+ "cmd": "dist/cmd/crud.js",
20
+ "cmd2": "dist/cmd/crud.js --config .tst/crud.config.json"
19
21
  },
20
22
  "files": [
21
23
  "dist/**/*"
22
24
  ],
23
25
  "main": "dist/index.js",
24
26
  "types": "dist/index.d.ts",
27
+ "bin": {
28
+ "crud": "dist/cmd/crud.js"
29
+ },
25
30
  "dependencies": {
26
31
  "@fraym/crud-proto": "^1.0.0-alpha.5",
32
+ "@graphql-tools/graphql-file-loader": "^7.5.11",
33
+ "@graphql-tools/load": "^7.8.6",
27
34
  "@grpc/grpc-js": "^1.7.2",
28
- "uuid": "^9.0.0"
35
+ "fs": "^0.0.1-security",
36
+ "graphql": "^16.6.0",
37
+ "yargs": "^17.6.2"
29
38
  },
30
39
  "devDependencies": {
31
40
  "@becklyn/prettier": "^1.0.2",
32
41
  "@types/uuid": "^8.3.4",
42
+ "@types/yargs": "^17.0.13",
33
43
  "prettier": "^2.7.1",
34
- "typescript": "^4.8.4"
44
+ "typescript": "^4.8.4",
45
+ "uuid": "^9.0.0"
35
46
  },
36
47
  "prettier": "@becklyn/prettier"
37
48
  }