@fraym/crud 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -8,19 +8,25 @@ Client implementation in javascript for the CRUD service [streams](https://githu
8
8
  npm i @fraym/crud
9
9
  ```
10
10
 
11
+ ## GraphQL
12
+
13
+ You can access the graphQL api at `http://crud:3000/delivery/graphql`.
14
+ There is a sandbox available at `http://crud:3000/delivery/graphql/sandbox`.
15
+
11
16
  ## CLI command
12
17
 
13
18
  Use the `crud` cli command to automatically apply your crud schemas to the crud service.
14
19
 
15
- The `--config ./path/crud.config.json` flag can be used to configure the pat to your config file.
20
+ The `--config ./path/crud.config.json` flag can be used to configure the path of your config file.
16
21
 
17
- Your type schemas have to live directly below the path that you specified in `schemaPath` of your config file.
22
+ Your type schemas have to match the glob you specify in `schemaGlob` of he config file (default: `./src/**/*.graphql`).
23
+ 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`).
18
24
 
19
25
  ### CLI command config
20
26
 
21
27
  ```json
22
28
  {
23
- "schemaPath": "./src/crud", // path to your crud schema files
29
+ "schemaGlob": "./src/crud/*.graphql", // path to your crud schema files
24
30
  "serverAddress": "127.0.0.1:9000" // address of the crud service
25
31
  }
26
32
  ```
package/dist/cmd/crud.js CHANGED
@@ -7,78 +7,212 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const yargs_1 = __importDefault(require("yargs/yargs"));
9
9
  const helpers_1 = require("yargs/helpers");
10
- const utilities_1 = require("graphql/utilities");
11
- const kinds_1 = require("graphql/language/kinds");
12
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");
13
14
  const run = async () => {
14
15
  const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
15
- .config({ schemaPath: "./src", serverAddress: "127.0.0.1:9000" })
16
+ .config({ schemaGlob: "./src/**/*.graphql", serverAddress: "127.0.0.1:9000" })
16
17
  .pkgConf("crud")
17
18
  .config("config", "Path of your `crud.config.ts`, default: `./crud.config.ts`", configPath => JSON.parse(fs_1.default.readFileSync(configPath, "utf-8"))).argv;
18
- const schemaPath = argv.schemaPath;
19
+ const schemaGlob = argv.schemaGlob;
19
20
  const serverAddress = argv.serverAddress;
20
- const schemas = getSchemas(schemaPath);
21
- await migrateSchemas(schemas, 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);
22
26
  };
23
27
  run();
24
- const getSchemas = (schemaPath) => {
25
- const schemaFiles = fs_1.default.readdirSync(schemaPath);
26
- const schemas = {};
27
- schemaFiles.forEach(fileName => {
28
- const astSchema = (0, utilities_1.buildSchema)(fs_1.default.readFileSync(schemaPath + "/" + fileName, "utf-8"));
29
- astSchema.toConfig().types.forEach(t => {
30
- var _a;
31
- if (!((_a = t.astNode) === null || _a === void 0 ? void 0 : _a.kind)) {
32
- return;
33
- }
34
- const name = t.toString();
35
- const typeSchema = (0, utilities_1.buildASTSchema)({
36
- definitions: [t.astNode],
37
- kind: kinds_1.Kind.DOCUMENT,
38
- });
39
- if (schemas[name]) {
40
- throw new Error(`duplicate schema for CRUD type "${name}" detected, try renaming one of them as they have to be unique`);
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);
41
61
  }
42
- schemas[name] = (0, utilities_1.printSchema)(typeSchema);
43
62
  });
44
63
  });
45
- return schemas;
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})`;
46
129
  };
47
- const migrateSchemas = async (schemas, serverAddress) => {
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) => {
48
163
  const managementClient = await (0, client_1.newManagementClient)({ serverAddress });
49
164
  const existingTypeNames = await managementClient.getAllTypes();
50
165
  let createSchema = "";
51
166
  let updateSchema = "";
52
167
  const typesToCreate = [];
168
+ const nestedTypesToCreate = [];
53
169
  const typesToUpdate = [];
170
+ const nestedTypesToUpdate = [];
54
171
  const typesToRemove = [];
55
172
  existingTypeNames.forEach(existingName => {
56
- if (!schemas[existingName]) {
173
+ if (!definitions[existingName] || !definitions[existingName].isCrudType) {
57
174
  typesToRemove.push(existingName);
58
175
  }
59
176
  else {
60
177
  typesToUpdate.push(existingName);
61
- updateSchema += `\n${schemas[existingName]}`;
62
- delete schemas[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];
63
187
  }
64
188
  });
65
- Object.keys(schemas).forEach(newName => {
189
+ Object.keys(definitions).forEach(newName => {
190
+ if (!definitions[newName].isCrudType) {
191
+ return;
192
+ }
66
193
  typesToCreate.push(newName);
67
- createSchema += `\n${schemas[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
+ });
68
202
  });
69
- if (typesToRemove.length > 0) {
70
- console.log(`Removing ${typesToRemove.length} types: ${typesToRemove}...`);
71
- await managementClient.removeTypes(typesToRemove);
72
- console.log(`Removed ${typesToRemove.length} types`);
203
+ if (typesToCreate.length > 0) {
204
+ console.log(`Creating ${typesToCreate.length} types: ${typesToCreate}...`);
205
+ await managementClient.createTypes(createSchema).catch(console.log);
206
+ console.log(`Created ${typesToCreate.length} types`);
73
207
  }
74
208
  if (typesToUpdate.length > 0) {
75
209
  console.log(`Updating ${typesToUpdate.length} types: ${typesToUpdate}...`);
76
- await managementClient.updateTypes(updateSchema);
210
+ await managementClient.updateTypes(updateSchema).catch(console.log);
77
211
  console.log(`Updated ${typesToUpdate.length} types`);
78
212
  }
79
- if (typesToCreate.length > 0) {
80
- console.log(`Creating ${typesToCreate.length} types: ${typesToCreate}...`);
81
- await managementClient.createTypes(createSchema);
82
- console.log(`Created ${typesToCreate.length} types`);
213
+ if (typesToRemove.length > 0) {
214
+ console.log(`Removing ${typesToRemove.length} types: ${typesToRemove}...`);
215
+ await managementClient.removeTypes(typesToRemove).catch(console.log);
216
+ console.log(`Removed ${typesToRemove.length} types`);
83
217
  }
84
218
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraym/crud",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "license": "UNLICENSED",
5
5
  "homepage": "https://github.com/fraym/crud-nodejs",
6
6
  "repository": {
@@ -29,6 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
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",
32
34
  "@grpc/grpc-js": "^1.7.2",
33
35
  "fs": "^0.0.1-security",
34
36
  "graphql": "^16.6.0",
@@ -39,8 +41,8 @@
39
41
  "@types/uuid": "^8.3.4",
40
42
  "@types/yargs": "^17.0.13",
41
43
  "prettier": "^2.7.1",
42
- "uuid": "^9.0.0",
43
- "typescript": "^4.8.4"
44
+ "typescript": "^4.8.4",
45
+ "uuid": "^9.0.0"
44
46
  },
45
47
  "prettier": "@becklyn/prettier"
46
48
  }