@fraym/projections 0.12.1 → 0.14.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 +38 -3
- package/dist/cmd/projections.js +19 -2
- package/dist/delivery/client.d.ts +4 -3
- package/dist/delivery/client.js +6 -6
- package/dist/delivery/delete.d.ts +2 -1
- package/dist/delivery/delete.js +2 -1
- package/dist/delivery/eventMetadata.d.ts +4 -0
- package/dist/delivery/eventMetadata.js +2 -0
- package/dist/delivery/upsert.d.ts +2 -1
- package/dist/delivery/upsert.js +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -44,6 +44,29 @@ PERMISSIONS_SCHEMA_GLOB=
|
|
|
44
44
|
PROJECTIONS_NAMESPACE=
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
## Env variable placeholders in migrations
|
|
48
|
+
|
|
49
|
+
You can use placeholders that match environment variables in argument strings in your schema definitions:
|
|
50
|
+
|
|
51
|
+
In the following example the `{{env.BACKEND_HOSTNAME}}` part will be replaced by the value of the `BACKEND_HOSTNAME` environment variable.
|
|
52
|
+
Please add your used env variables to the `.env` file that is used to [configure the migration command](#config).
|
|
53
|
+
|
|
54
|
+
```graphql
|
|
55
|
+
type TestType {
|
|
56
|
+
value: String
|
|
57
|
+
@webhook(
|
|
58
|
+
url: "http://{{env.BACKEND_HOSTNAME}}/event-organizing/contingent/projections/frontend/contingent-management/webhook"
|
|
59
|
+
method: "GET"
|
|
60
|
+
header: [{ key: "Content-Type", value: "'application/json'" }]
|
|
61
|
+
body: [
|
|
62
|
+
{ key: "metadata", value: "metadata" }
|
|
63
|
+
{ key: "payload", value: "payload" }
|
|
64
|
+
{ key: "projection", value: "projection" }
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
47
70
|
## Usage
|
|
48
71
|
|
|
49
72
|
### Create the clients
|
|
@@ -103,6 +126,17 @@ Fields:
|
|
|
103
126
|
- `scopes`: Slice of scopes to use for the action
|
|
104
127
|
- `data`: Data that is used in directives like `@filterFromJwtData`
|
|
105
128
|
|
|
129
|
+
### Event Metadata
|
|
130
|
+
|
|
131
|
+
You can specify the correlation and causation IDs for the upsert and delete functions. The `eventMetadata` parameter is optional for all these functions and has the following structure:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const eventMetadata = {
|
|
135
|
+
correlationId: "some-correlation-id",
|
|
136
|
+
causationId: "some-causation-id",
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
106
140
|
### Upsert data in projection
|
|
107
141
|
|
|
108
142
|
In general you upsert data by publishing events on the event stream.
|
|
@@ -115,7 +149,8 @@ const response = await client.upsertData<{ fieldName: string }>(
|
|
|
115
149
|
"dataId",
|
|
116
150
|
{
|
|
117
151
|
fieldName: "value",
|
|
118
|
-
}
|
|
152
|
+
},
|
|
153
|
+
eventMetadata
|
|
119
154
|
);
|
|
120
155
|
```
|
|
121
156
|
|
|
@@ -138,13 +173,13 @@ There are cases where you want to improve performance and get detailed validatio
|
|
|
138
173
|
Delete by Id:
|
|
139
174
|
|
|
140
175
|
```go
|
|
141
|
-
const numberOfDeletedEntries = await client.deleteDataById("ProjectionName", authData, "dataId")
|
|
176
|
+
const numberOfDeletedEntries = await client.deleteDataById("ProjectionName", authData, "dataId", eventMetadata)
|
|
142
177
|
```
|
|
143
178
|
|
|
144
179
|
Delete by filter:
|
|
145
180
|
|
|
146
181
|
```go
|
|
147
|
-
const numberOfDeletedEntries = client.deleteDataByFilter("ProjectionName", authData, filter)
|
|
182
|
+
const numberOfDeletedEntries = client.deleteDataByFilter("ProjectionName", authData, filter, eventMetadata)
|
|
148
183
|
```
|
|
149
184
|
|
|
150
185
|
### Get a single projection element
|
package/dist/cmd/projections.js
CHANGED
|
@@ -302,12 +302,12 @@ const migrateSchemas = async (definitions, serverAddress, apiToken, namespace) =
|
|
|
302
302
|
});
|
|
303
303
|
if (projectionsToCreate.length > 0) {
|
|
304
304
|
console.log(`Creating ${projectionsToCreate.length} projections: ${projectionsToCreate}...`);
|
|
305
|
-
await managementClient.upsert(createSchema);
|
|
305
|
+
await managementClient.upsert(replaceWithEnvData(createSchema));
|
|
306
306
|
console.log(`Created ${projectionsToCreate.length} projections`);
|
|
307
307
|
}
|
|
308
308
|
if (projectionsToUpdate.length > 0) {
|
|
309
309
|
console.log(`Updating ${projectionsToUpdate.length} projections: ${projectionsToUpdate}...`);
|
|
310
|
-
await managementClient.upsert(updateSchema);
|
|
310
|
+
await managementClient.upsert(replaceWithEnvData(updateSchema));
|
|
311
311
|
console.log(`Updated ${projectionsToUpdate.length} projections`);
|
|
312
312
|
}
|
|
313
313
|
if (projectionsToRemove.length > 0) {
|
|
@@ -316,6 +316,23 @@ const migrateSchemas = async (definitions, serverAddress, apiToken, namespace) =
|
|
|
316
316
|
console.log(`Removed ${projectionsToRemove.length} projections`);
|
|
317
317
|
}
|
|
318
318
|
};
|
|
319
|
+
const replaceWithEnvData = (str) => {
|
|
320
|
+
const regex = /{{env\.([a-zA-Z_]+)}}/g;
|
|
321
|
+
const matches = str.match(regex);
|
|
322
|
+
const envData = {};
|
|
323
|
+
matches === null || matches === void 0 ? void 0 : matches.forEach(match => {
|
|
324
|
+
var _a;
|
|
325
|
+
const variable = match.replace("{{env.", "").replace("}}", "");
|
|
326
|
+
if (!envData[variable]) {
|
|
327
|
+
envData[variable] = (_a = process.env[variable]) !== null && _a !== void 0 ? _a : "";
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
let outputStr = str;
|
|
331
|
+
Object.keys(envData).forEach(key => {
|
|
332
|
+
outputStr = outputStr.replaceAll(`{{env.${key}}}`, envData[key]);
|
|
333
|
+
});
|
|
334
|
+
return outputStr;
|
|
335
|
+
};
|
|
319
336
|
const ensureValidName = (name) => {
|
|
320
337
|
if (name.startsWith("Fraym")) {
|
|
321
338
|
throw new Error(`Cannot use Fraym as projection name prefix as it is reserved for fraym apps, got ${name}`);
|
|
@@ -4,12 +4,13 @@ import { GetProjectionDataList } from "./getDataList";
|
|
|
4
4
|
import { Order } from "./order";
|
|
5
5
|
import { AuthData } from "./auth";
|
|
6
6
|
import { UpsertResponse } from "./upsert";
|
|
7
|
+
import { EventMetadata } from "./eventMetadata";
|
|
7
8
|
export interface DeliveryClient {
|
|
8
9
|
getData: <T extends {}>(projection: string, authData: AuthData, id: string, filter?: Filter, returnEmptyDataIfNotFound?: boolean) => Promise<T | null>;
|
|
9
10
|
getDataList: <T extends {}>(projection: string, authData: AuthData, limit?: number, page?: number, filter?: Filter, order?: Order[]) => Promise<GetProjectionDataList<T> | null>;
|
|
10
|
-
upsertData: <T extends {}>(projection: string, authData: AuthData, dataId: string, payload: T) => Promise<UpsertResponse<T>>;
|
|
11
|
-
deleteDataById: (projection: string, authData: AuthData, dataId: string) => Promise<number>;
|
|
12
|
-
deleteDataByFilter: (projection: string, authData: AuthData, filter?: Filter) => Promise<number>;
|
|
11
|
+
upsertData: <T extends {}>(projection: string, authData: AuthData, dataId: string, payload: T, eventMetadata?: EventMetadata) => Promise<UpsertResponse<T>>;
|
|
12
|
+
deleteDataById: (projection: string, authData: AuthData, dataId: string, eventMetadata?: EventMetadata) => Promise<number>;
|
|
13
|
+
deleteDataByFilter: (projection: string, authData: AuthData, filter?: Filter, eventMetadata?: EventMetadata) => Promise<number>;
|
|
13
14
|
close: () => Promise<void>;
|
|
14
15
|
}
|
|
15
16
|
export declare const newDeliveryClient: (config?: DeliveryClientConfig) => Promise<DeliveryClient>;
|
package/dist/delivery/client.js
CHANGED
|
@@ -21,14 +21,14 @@ const newDeliveryClient = async (config) => {
|
|
|
21
21
|
const getDataList = async (projection, auth, limit = 0, page = 1, filter = { fields: {}, and: [], or: [] }, order = []) => {
|
|
22
22
|
return await (0, getDataList_1.getProjectionDataList)(projection, auth, limit, page, filter, order, serviceClient);
|
|
23
23
|
};
|
|
24
|
-
const upsertData = async (projection, authData, dataId, payload) => {
|
|
25
|
-
return (0, upsert_1.upsertProjectionData)(projection, authData, dataId, payload, serviceClient);
|
|
24
|
+
const upsertData = async (projection, authData, dataId, payload, eventMetadata = { causationId: "", correlationId: "" }) => {
|
|
25
|
+
return (0, upsert_1.upsertProjectionData)(projection, authData, dataId, payload, eventMetadata, serviceClient);
|
|
26
26
|
};
|
|
27
|
-
const deleteDataById = async (projection, authData, dataId) => {
|
|
28
|
-
return (0, delete_1.deleteProjectionData)(projection, authData, dataId, { fields: {}, and: [], or: [] }, serviceClient);
|
|
27
|
+
const deleteDataById = async (projection, authData, dataId, eventMetadata = { causationId: "", correlationId: "" }) => {
|
|
28
|
+
return (0, delete_1.deleteProjectionData)(projection, authData, dataId, { fields: {}, and: [], or: [] }, eventMetadata, serviceClient);
|
|
29
29
|
};
|
|
30
|
-
const deleteDataByFilter = async (projection, authData, filter = { fields: {}, and: [], or: [] }) => {
|
|
31
|
-
return (0, delete_1.deleteProjectionData)(projection, authData, "", filter, serviceClient);
|
|
30
|
+
const deleteDataByFilter = async (projection, authData, filter = { fields: {}, and: [], or: [] }, eventMetadata = { causationId: "", correlationId: "" }) => {
|
|
31
|
+
return (0, delete_1.deleteProjectionData)(projection, authData, "", filter, eventMetadata, serviceClient);
|
|
32
32
|
};
|
|
33
33
|
const close = async () => {
|
|
34
34
|
serviceClient.close();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DeliveryServiceClient } from "@fraym/projections-proto";
|
|
2
2
|
import { AuthData } from "./auth";
|
|
3
|
+
import { EventMetadata } from "./eventMetadata";
|
|
3
4
|
import { Filter } from "./filter";
|
|
4
|
-
export declare const deleteProjectionData: (projection: string, auth: AuthData, dataId: string, filter: Filter, serviceClient: DeliveryServiceClient) => Promise<number>;
|
|
5
|
+
export declare const deleteProjectionData: (projection: string, auth: AuthData, dataId: string, filter: Filter, eventMetadata: EventMetadata, serviceClient: DeliveryServiceClient) => Promise<number>;
|
package/dist/delivery/delete.js
CHANGED
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.deleteProjectionData = void 0;
|
|
4
4
|
const auth_1 = require("./auth");
|
|
5
5
|
const filter_1 = require("./filter");
|
|
6
|
-
const deleteProjectionData = async (projection, auth, dataId, filter, serviceClient) => {
|
|
6
|
+
const deleteProjectionData = async (projection, auth, dataId, filter, eventMetadata, serviceClient) => {
|
|
7
7
|
return new Promise((resolve, reject) => {
|
|
8
8
|
serviceClient.deleteData({
|
|
9
9
|
projection,
|
|
10
10
|
auth: (0, auth_1.getProtobufAuthData)(auth),
|
|
11
11
|
dataId,
|
|
12
12
|
filter: (0, filter_1.getProtobufDataFilter)(filter),
|
|
13
|
+
eventMetadata,
|
|
13
14
|
}, (error, response) => {
|
|
14
15
|
if (error) {
|
|
15
16
|
reject(error.message);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DeliveryServiceClient } from "@fraym/projections-proto";
|
|
2
2
|
import { AuthData } from "./auth";
|
|
3
|
+
import { EventMetadata } from "./eventMetadata";
|
|
3
4
|
export type UpsertResponse<T extends {}> = UpsertSuccessResponse<T> | UpsertValidationResponse;
|
|
4
5
|
export interface UpsertSuccessResponse<T extends {}> {
|
|
5
6
|
data: T;
|
|
@@ -10,4 +11,4 @@ export interface UpsertValidationResponse {
|
|
|
10
11
|
}
|
|
11
12
|
export declare const isUpsertSuccessResponse: <T extends {}>(response: UpsertResponse<T>) => response is UpsertSuccessResponse<T>;
|
|
12
13
|
export declare const isUpsertValidationResponse: <T extends {}>(response: UpsertResponse<T>) => response is UpsertValidationResponse;
|
|
13
|
-
export declare const upsertProjectionData: <T extends {}>(projection: string, auth: AuthData, dataId: string, payload: T, serviceClient: DeliveryServiceClient) => Promise<UpsertResponse<T>>;
|
|
14
|
+
export declare const upsertProjectionData: <T extends {}>(projection: string, auth: AuthData, dataId: string, payload: T, eventMetadata: EventMetadata, serviceClient: DeliveryServiceClient) => Promise<UpsertResponse<T>>;
|
package/dist/delivery/upsert.js
CHANGED
|
@@ -10,13 +10,14 @@ const isUpsertValidationResponse = (response) => {
|
|
|
10
10
|
return !response.hasOwnProperty("data");
|
|
11
11
|
};
|
|
12
12
|
exports.isUpsertValidationResponse = isUpsertValidationResponse;
|
|
13
|
-
const upsertProjectionData = async (projection, auth, dataId, payload, serviceClient) => {
|
|
13
|
+
const upsertProjectionData = async (projection, auth, dataId, payload, eventMetadata, serviceClient) => {
|
|
14
14
|
return new Promise((resolve, reject) => {
|
|
15
15
|
serviceClient.upsertData({
|
|
16
16
|
projection,
|
|
17
17
|
auth: (0, auth_1.getProtobufAuthData)(auth),
|
|
18
18
|
dataId,
|
|
19
19
|
payload,
|
|
20
|
+
eventMetadata,
|
|
20
21
|
}, (error, response) => {
|
|
21
22
|
if (error) {
|
|
22
23
|
reject(error.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraym/projections",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"homepage": "https://github.com/fraym/projections-nodejs",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"projections": "dist/cmd/projections.js"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@fraym/projections-proto": "^1.0.0-alpha.
|
|
30
|
+
"@fraym/projections-proto": "^1.0.0-alpha.16",
|
|
31
31
|
"@graphql-tools/graphql-file-loader": "^7.5.16",
|
|
32
32
|
"@graphql-tools/load": "^7.8.13",
|
|
33
33
|
"@grpc/grpc-js": "^1.8.12",
|