@fraym/projections 0.3.0 → 0.4.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 +5 -2
- package/dist/cmd/projections.js +41 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,9 @@ You need to add the `Tenant-Id` header in order to use the graphQL Endpoint and
|
|
|
20
20
|
Use the `projections` cli command to automatically apply your projection schemas to the projections service.
|
|
21
21
|
|
|
22
22
|
Your type schemas have to match the glob you specify in the `PROJECTIONS_SCHEMA_GLOB` env variable (default: `./src/**/*.graphql`).
|
|
23
|
-
You can specify the address (and port) of the
|
|
23
|
+
You can specify the address (and port) of the projections service instance you use in the `PROJECTIONS_SERVER_ADDRESS` env variable (default: `127.0.0.1:9000`).
|
|
24
|
+
|
|
25
|
+
Use the `PROJECTIONS_NAMESPACE` env variable to restrict all migrations to your namespace. This is useful if multiple apps share the projections service. Note: You cannot name your projection or namespace by a `Fraym` prefix. This is a reserved prefix for fraym apps.
|
|
24
26
|
|
|
25
27
|
You need to add a file that contains all built-in directives to your type schemas. The latest version of this file can be found [here](default.graphql).
|
|
26
28
|
|
|
@@ -31,6 +33,7 @@ Use a `.env` file or env variables to configure cte clients and the command:
|
|
|
31
33
|
```env
|
|
32
34
|
PROJECTIONS_SERVER_ADDRESS=127.0.0.1:9000
|
|
33
35
|
PROJECTIONS_SCHEMA_GLOB=./src/projections/*.graphql
|
|
36
|
+
PROJECTIONS_NAMESPACE=
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
## Usage
|
|
@@ -94,7 +97,7 @@ You can specify a fourth parameter if you want to return a empty dataset instead
|
|
|
94
97
|
const data = await deliveryClient.getData("tenantId", "YourProjection", "id", true);
|
|
95
98
|
```
|
|
96
99
|
|
|
97
|
-
### Get (paginated) data
|
|
100
|
+
### Get (paginated / filtered) data
|
|
98
101
|
|
|
99
102
|
The name of `YourProjection` has to equal your type name in your schema (also in casing).
|
|
100
103
|
|
package/dist/cmd/projections.js
CHANGED
|
@@ -14,47 +14,60 @@ const client_1 = require("../management/client");
|
|
|
14
14
|
const run = async () => {
|
|
15
15
|
(0, dotenv_1.config)();
|
|
16
16
|
const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
17
|
-
.config({
|
|
17
|
+
.config({
|
|
18
|
+
schemaGlob: "./src/**/*.graphql",
|
|
19
|
+
serverAddress: "127.0.0.1:9000",
|
|
20
|
+
namespace: "",
|
|
21
|
+
})
|
|
18
22
|
.pkgConf("projections").argv;
|
|
19
23
|
let schemaGlob = argv.schemaGlob;
|
|
20
24
|
let serverAddress = argv.serverAddress;
|
|
25
|
+
let namespace = argv.namespace;
|
|
21
26
|
if (process.env.PROJECTIONS_SCHEMA_GLOB) {
|
|
22
27
|
schemaGlob = process.env.PROJECTIONS_SCHEMA_GLOB;
|
|
23
28
|
}
|
|
24
29
|
if (process.env.PROJECTIONS_SERVER_ADDRESS) {
|
|
25
30
|
serverAddress = process.env.PROJECTIONS_SERVER_ADDRESS;
|
|
26
31
|
}
|
|
32
|
+
if (process.env.PROJECTIONS_NAMESPACE) {
|
|
33
|
+
namespace = process.env.PROJECTIONS_NAMESPACE;
|
|
34
|
+
}
|
|
35
|
+
if (namespace === "Fraym") {
|
|
36
|
+
throw new Error("Cannot use Fraym as namespace as it is reserved for fraym apps");
|
|
37
|
+
}
|
|
27
38
|
const schema = await (0, load_1.loadSchema)(`${schemaGlob}`, {
|
|
28
39
|
loaders: [new graphql_file_loader_1.GraphQLFileLoader()],
|
|
29
40
|
});
|
|
30
|
-
const definitions = getTypeDefinition(schema);
|
|
31
|
-
await migrateSchemas(definitions, serverAddress);
|
|
41
|
+
const definitions = getTypeDefinition(schema, namespace);
|
|
42
|
+
await migrateSchemas(definitions, serverAddress, namespace);
|
|
32
43
|
};
|
|
33
44
|
run();
|
|
34
|
-
const getTypeDefinition = (schema) => {
|
|
45
|
+
const getTypeDefinition = (schema, namespace) => {
|
|
35
46
|
const definitions = {};
|
|
36
47
|
schema.toConfig().types.forEach(t => {
|
|
37
48
|
if (!(t instanceof graphql_1.GraphQLObjectType) && !(t instanceof graphql_1.GraphQLEnumType)) {
|
|
38
49
|
return;
|
|
39
50
|
}
|
|
40
|
-
const name = t.toString()
|
|
51
|
+
const name = `${namespace}${t.toString()}`;
|
|
52
|
+
ensureValidName(name);
|
|
41
53
|
if (definitions[name]) {
|
|
42
54
|
throw new Error(`duplicate definition for type "${name}" detected, try renaming one of them as they have to be uniquely named`);
|
|
43
55
|
}
|
|
44
56
|
if (t instanceof graphql_1.GraphQLObjectType) {
|
|
45
|
-
definitions[name] = getTypeDefinitionFromGraphQLObjectType(t);
|
|
57
|
+
definitions[name] = getTypeDefinitionFromGraphQLObjectType(t, namespace);
|
|
46
58
|
return;
|
|
47
59
|
}
|
|
48
60
|
if (t instanceof graphql_1.GraphQLEnumType) {
|
|
49
|
-
definitions[name] = getTypeDefinitionFromGraphQLEnumType(t);
|
|
61
|
+
definitions[name] = getTypeDefinitionFromGraphQLEnumType(t, namespace);
|
|
50
62
|
return;
|
|
51
63
|
}
|
|
52
64
|
});
|
|
53
65
|
return definitions;
|
|
54
66
|
};
|
|
55
|
-
const getTypeDefinitionFromGraphQLEnumType = (t) => {
|
|
67
|
+
const getTypeDefinitionFromGraphQLEnumType = (t, namespace) => {
|
|
56
68
|
var _a, _b;
|
|
57
|
-
const name = t.toString()
|
|
69
|
+
const name = `${namespace}${t.toString()}`;
|
|
70
|
+
ensureValidName(name);
|
|
58
71
|
let enumValuesString = "";
|
|
59
72
|
(_b = (_a = t.astNode) === null || _a === void 0 ? void 0 : _a.values) === null || _b === void 0 ? void 0 : _b.forEach(value => {
|
|
60
73
|
enumValuesString += `\n\t${value.name.value}`;
|
|
@@ -66,14 +79,15 @@ const getTypeDefinitionFromGraphQLEnumType = (t) => {
|
|
|
66
79
|
schema,
|
|
67
80
|
};
|
|
68
81
|
};
|
|
69
|
-
const getTypeDefinitionFromGraphQLObjectType = (t) => {
|
|
82
|
+
const getTypeDefinitionFromGraphQLObjectType = (t, namespace) => {
|
|
70
83
|
var _a, _b, _c, _d, _e, _f;
|
|
71
84
|
let isProjection = false;
|
|
72
85
|
if (((_a = t.astNode) === null || _a === void 0 ? void 0 : _a.directives) && ((_b = t.astNode) === null || _b === void 0 ? void 0 : _b.directives.length) > 0) {
|
|
73
86
|
const directiveNames = t.astNode.directives.map(directive => directive.name.value);
|
|
74
87
|
isProjection = directiveNames.includes("upsertOn");
|
|
75
88
|
}
|
|
76
|
-
const name = t.toString()
|
|
89
|
+
const name = `${namespace}${t.toString()}`;
|
|
90
|
+
ensureValidName(name);
|
|
77
91
|
let objectDirectivesString = "";
|
|
78
92
|
let objectFieldsString = "";
|
|
79
93
|
let nestedTypes = [];
|
|
@@ -81,7 +95,7 @@ const getTypeDefinitionFromGraphQLObjectType = (t) => {
|
|
|
81
95
|
objectDirectivesString += getDirectiveString(d);
|
|
82
96
|
});
|
|
83
97
|
(_f = (_e = t.astNode) === null || _e === void 0 ? void 0 : _e.fields) === null || _f === void 0 ? void 0 : _f.forEach(f => {
|
|
84
|
-
const { str, nestedTypes: newNestedTypes } = getFieldStringAndNestedTypes(f);
|
|
98
|
+
const { str, nestedTypes: newNestedTypes } = getFieldStringAndNestedTypes(f, namespace);
|
|
85
99
|
objectFieldsString += str;
|
|
86
100
|
newNestedTypes.forEach(nested => {
|
|
87
101
|
if (nestedTypes.indexOf(nested) === -1) {
|
|
@@ -96,13 +110,13 @@ const getTypeDefinitionFromGraphQLObjectType = (t) => {
|
|
|
96
110
|
schema,
|
|
97
111
|
};
|
|
98
112
|
};
|
|
99
|
-
const getFieldStringAndNestedTypes = (f) => {
|
|
113
|
+
const getFieldStringAndNestedTypes = (f, namespace) => {
|
|
100
114
|
var _a;
|
|
101
115
|
let directivesString = "";
|
|
102
116
|
(_a = f.directives) === null || _a === void 0 ? void 0 : _a.forEach(d => {
|
|
103
117
|
directivesString += getDirectiveString(d);
|
|
104
118
|
});
|
|
105
|
-
const { nestedType, str: typeString } = getTypeData(f.type);
|
|
119
|
+
const { nestedType, str: typeString } = getTypeData(f.type, namespace);
|
|
106
120
|
const nestedTypes = [];
|
|
107
121
|
if (nestedType) {
|
|
108
122
|
nestedTypes.push(nestedType);
|
|
@@ -112,10 +126,11 @@ const getFieldStringAndNestedTypes = (f) => {
|
|
|
112
126
|
nestedTypes,
|
|
113
127
|
};
|
|
114
128
|
};
|
|
115
|
-
const getTypeData = (t) => {
|
|
129
|
+
const getTypeData = (t, namespace) => {
|
|
116
130
|
switch (t.kind) {
|
|
117
131
|
case graphql_1.Kind.NAMED_TYPE:
|
|
118
132
|
const name = t.name.value;
|
|
133
|
+
ensureValidName(`${namespace}${name}`);
|
|
119
134
|
return name === "String" ||
|
|
120
135
|
name === "Float" ||
|
|
121
136
|
name === "ID" ||
|
|
@@ -127,17 +142,17 @@ const getTypeData = (t) => {
|
|
|
127
142
|
str: name,
|
|
128
143
|
}
|
|
129
144
|
: {
|
|
130
|
-
str: name
|
|
131
|
-
nestedType: name
|
|
145
|
+
str: `${namespace}${name}`,
|
|
146
|
+
nestedType: `${namespace}${name}`,
|
|
132
147
|
};
|
|
133
148
|
case graphql_1.Kind.LIST_TYPE:
|
|
134
|
-
const { nestedType: listNestedType, str: listStr } = getTypeData(t.type);
|
|
149
|
+
const { nestedType: listNestedType, str: listStr } = getTypeData(t.type, namespace);
|
|
135
150
|
return {
|
|
136
151
|
str: `[${listStr}]`,
|
|
137
152
|
nestedType: listNestedType,
|
|
138
153
|
};
|
|
139
154
|
case graphql_1.Kind.NON_NULL_TYPE:
|
|
140
|
-
const { nestedType: nonNullNestedType, str: nonNullStr } = getTypeData(t.type);
|
|
155
|
+
const { nestedType: nonNullNestedType, str: nonNullStr } = getTypeData(t.type, namespace);
|
|
141
156
|
return {
|
|
142
157
|
str: `${nonNullStr}!`,
|
|
143
158
|
nestedType: nonNullNestedType,
|
|
@@ -189,9 +204,9 @@ const getValueString = (v) => {
|
|
|
189
204
|
throw new Error(`values of kind ${v.kind} are currently not supported`);
|
|
190
205
|
}
|
|
191
206
|
};
|
|
192
|
-
const migrateSchemas = async (definitions, serverAddress) => {
|
|
207
|
+
const migrateSchemas = async (definitions, serverAddress, namespace) => {
|
|
193
208
|
const managementClient = await (0, client_1.newManagementClient)({ serverAddress });
|
|
194
|
-
let existingProjections = (await managementClient.getAll()).filter(projectionName => !projectionName.startsWith("Crud"));
|
|
209
|
+
let existingProjections = (await managementClient.getAll()).filter(projectionName => !projectionName.startsWith("Crud") && projectionName.startsWith(namespace));
|
|
195
210
|
let createSchema = "";
|
|
196
211
|
let updateSchema = "";
|
|
197
212
|
const projectionsToCreate = [];
|
|
@@ -247,3 +262,8 @@ const migrateSchemas = async (definitions, serverAddress) => {
|
|
|
247
262
|
console.log(`Removed ${projectionsToRemove.length} projections`);
|
|
248
263
|
}
|
|
249
264
|
};
|
|
265
|
+
const ensureValidName = (name) => {
|
|
266
|
+
if (name.startsWith("Fraym")) {
|
|
267
|
+
throw new Error(`Cannot use Fraym as projection name prefix as it is reserved for fraym apps, got ${name}`);
|
|
268
|
+
}
|
|
269
|
+
};
|