@hotmeshio/hotmesh 0.0.51 → 0.0.53
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 +13 -9
- package/build/index.d.ts +1 -2
- package/build/index.js +1 -3
- package/build/modules/enums.d.ts +8 -3
- package/build/modules/enums.js +16 -8
- package/build/modules/errors.d.ts +98 -18
- package/build/modules/errors.js +90 -33
- package/build/package.json +7 -2
- package/build/services/activities/activity.d.ts +8 -0
- package/build/services/activities/activity.js +65 -16
- package/build/services/activities/await.js +6 -6
- package/build/services/activities/cycle.d.ts +2 -2
- package/build/services/activities/cycle.js +5 -5
- package/build/services/activities/hook.js +4 -4
- package/build/services/activities/interrupt.d.ts +3 -3
- package/build/services/activities/interrupt.js +15 -6
- package/build/services/activities/signal.d.ts +2 -2
- package/build/services/activities/signal.js +4 -4
- package/build/services/activities/trigger.js +12 -3
- package/build/services/activities/worker.js +6 -6
- package/build/services/compiler/deployer.js +33 -5
- package/build/services/compiler/validator.d.ts +2 -0
- package/build/services/compiler/validator.js +5 -1
- package/build/services/durable/client.d.ts +7 -1
- package/build/services/durable/client.js +56 -30
- package/build/services/durable/exporter.d.ts +7 -72
- package/build/services/durable/exporter.js +105 -295
- package/build/services/durable/handle.d.ts +11 -6
- package/build/services/durable/handle.js +59 -46
- package/build/services/durable/index.d.ts +0 -2
- package/build/services/durable/index.js +0 -2
- package/build/services/durable/schemas/factory.d.ts +33 -0
- package/build/services/durable/schemas/factory.js +2356 -0
- package/build/services/durable/search.js +8 -8
- package/build/services/durable/worker.js +117 -25
- package/build/services/durable/workflow.d.ts +46 -43
- package/build/services/durable/workflow.js +273 -277
- package/build/services/engine/index.js +3 -0
- package/build/services/exporter/index.d.ts +2 -4
- package/build/services/exporter/index.js +4 -5
- package/build/services/mapper/index.d.ts +6 -2
- package/build/services/mapper/index.js +6 -2
- package/build/services/pipe/functions/array.d.ts +2 -10
- package/build/services/pipe/functions/array.js +30 -28
- package/build/services/pipe/functions/conditional.d.ts +1 -0
- package/build/services/pipe/functions/conditional.js +3 -0
- package/build/services/pipe/functions/date.d.ts +1 -0
- package/build/services/pipe/functions/date.js +4 -0
- package/build/services/pipe/functions/index.d.ts +2 -0
- package/build/services/pipe/functions/index.js +2 -0
- package/build/services/pipe/functions/logical.d.ts +5 -0
- package/build/services/pipe/functions/logical.js +12 -0
- package/build/services/pipe/functions/object.d.ts +3 -0
- package/build/services/pipe/functions/object.js +25 -7
- package/build/services/pipe/index.d.ts +20 -3
- package/build/services/pipe/index.js +82 -16
- package/build/services/router/index.js +14 -3
- package/build/services/serializer/index.d.ts +3 -2
- package/build/services/serializer/index.js +11 -4
- package/build/services/store/clients/ioredis.js +6 -6
- package/build/services/store/clients/redis.js +7 -7
- package/build/services/store/index.d.ts +2 -0
- package/build/services/store/index.js +4 -1
- package/build/services/stream/clients/ioredis.js +8 -8
- package/build/services/stream/clients/redis.js +1 -1
- package/build/types/activity.d.ts +60 -5
- package/build/types/durable.d.ts +168 -33
- package/build/types/exporter.d.ts +26 -4
- package/build/types/index.d.ts +2 -2
- package/build/types/job.d.ts +69 -5
- package/build/types/pipe.d.ts +81 -3
- package/build/types/stream.d.ts +61 -1
- package/build/types/stream.js +4 -0
- package/index.ts +1 -2
- package/modules/enums.ts +16 -8
- package/modules/errors.ts +174 -32
- package/package.json +7 -2
- package/services/activities/activity.ts +67 -18
- package/services/activities/await.ts +6 -6
- package/services/activities/cycle.ts +7 -6
- package/services/activities/hook.ts +4 -4
- package/services/activities/interrupt.ts +19 -9
- package/services/activities/signal.ts +6 -5
- package/services/activities/trigger.ts +16 -4
- package/services/activities/worker.ts +7 -7
- package/services/compiler/deployer.ts +33 -6
- package/services/compiler/validator.ts +7 -3
- package/services/durable/client.ts +47 -14
- package/services/durable/exporter.ts +110 -318
- package/services/durable/handle.ts +63 -50
- package/services/durable/index.ts +0 -2
- package/services/durable/schemas/factory.ts +2358 -0
- package/services/durable/search.ts +8 -8
- package/services/durable/worker.ts +128 -29
- package/services/durable/workflow.ts +304 -288
- package/services/engine/index.ts +4 -0
- package/services/exporter/index.ts +10 -12
- package/services/mapper/index.ts +6 -2
- package/services/pipe/functions/array.ts +24 -37
- package/services/pipe/functions/conditional.ts +4 -0
- package/services/pipe/functions/date.ts +6 -0
- package/services/pipe/functions/index.ts +7 -5
- package/services/pipe/functions/logical.ts +11 -0
- package/services/pipe/functions/object.ts +26 -7
- package/services/pipe/index.ts +99 -21
- package/services/quorum/index.ts +1 -3
- package/services/router/index.ts +14 -3
- package/services/serializer/index.ts +12 -5
- package/services/store/clients/ioredis.ts +6 -6
- package/services/store/clients/redis.ts +7 -7
- package/services/store/index.ts +4 -1
- package/services/stream/clients/ioredis.ts +8 -8
- package/services/stream/clients/redis.ts +1 -1
- package/types/activity.ts +87 -15
- package/types/durable.ts +246 -73
- package/types/exporter.ts +31 -5
- package/types/index.ts +6 -7
- package/types/job.ts +130 -36
- package/types/pipe.ts +84 -3
- package/types/stream.ts +82 -23
- package/build/services/durable/factory.d.ts +0 -17
- package/build/services/durable/factory.js +0 -817
- package/build/services/durable/meshos.d.ts +0 -127
- package/build/services/durable/meshos.js +0 -380
- package/services/durable/factory.ts +0 -818
- package/services/durable/meshos.ts +0 -441
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { WorkflowHandleService } from './handle';
|
|
2
|
-
import { WorkflowService } from './workflow';
|
|
3
|
-
import { FindOptions, FindWhereOptions, FindWhereQuery, MeshOSActivityOptions, MeshOSConfig, MeshOSOptions, MeshOSWorkerOptions, WorkflowSearchOptions } from '../../types/durable';
|
|
4
|
-
import { RedisOptions, RedisClass } from '../../types/redis';
|
|
5
|
-
import { StringAnyType } from '../../types/serializer';
|
|
6
|
-
/**
|
|
7
|
-
* The base class for running MeshOS workflows.
|
|
8
|
-
* Extend this class, add your Redis config, and add functions to
|
|
9
|
-
* execute as durable `hooks`, `workflows`, and `activities`.
|
|
10
|
-
*/
|
|
11
|
-
export declare class MeshOSService {
|
|
12
|
-
/**
|
|
13
|
-
* The top-level Redis isolation. All workflow data is
|
|
14
|
-
* isolated within this namespace. Values should be
|
|
15
|
-
* lower-case with no spaces (e.g, 'staging', 'prod', 'test',
|
|
16
|
-
* 'routing-stagig', 'reporting-prod', etc.).
|
|
17
|
-
* 1) only url-safe values are allowed;
|
|
18
|
-
* 2) the 'a' symbol is reserved by HotMesh for indexing apps
|
|
19
|
-
*/
|
|
20
|
-
namespace: string;
|
|
21
|
-
/**
|
|
22
|
-
* Data is routed to workers that specify this task queue.
|
|
23
|
-
* Setting the task queue when the worker is created will
|
|
24
|
-
* ensure that the worker only receives messages destined
|
|
25
|
-
* for the queue. Callers can specify the taskQue to when
|
|
26
|
-
* starting a job to call those workers.
|
|
27
|
-
*/
|
|
28
|
-
taskQueue: string;
|
|
29
|
-
/**
|
|
30
|
-
* These methods run as durable workflows
|
|
31
|
-
*/
|
|
32
|
-
workflowFunctions: Array<MeshOSOptions | string>;
|
|
33
|
-
/**
|
|
34
|
-
* These methods run as hooks (hook into a running workflow)
|
|
35
|
-
*/
|
|
36
|
-
hookFunctions: Array<MeshOSOptions | string>;
|
|
37
|
-
/**
|
|
38
|
-
* These methods run as proxied activities (and are safely memoized)
|
|
39
|
-
*/
|
|
40
|
-
proxyFunctions: Array<MeshOSActivityOptions | string>;
|
|
41
|
-
/**
|
|
42
|
-
* The workflow GUID. Workflows will be persisted to
|
|
43
|
-
* Redis using the pattern hmsh:<namespace>:j:<id>.
|
|
44
|
-
*/
|
|
45
|
-
id: string;
|
|
46
|
-
/**
|
|
47
|
-
* The Redis connection options. NOTE: Redis and IORedis
|
|
48
|
-
* use different formats for their connection config.
|
|
49
|
-
*/
|
|
50
|
-
redisOptions: RedisOptions;
|
|
51
|
-
/**
|
|
52
|
-
* The Redis connection class.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* import Redis from 'ioredis';
|
|
56
|
-
* import * as Redis from 'redis';
|
|
57
|
-
*/
|
|
58
|
-
redisClass: RedisClass;
|
|
59
|
-
/**
|
|
60
|
-
* Optional model declaration (custom workflow state)
|
|
61
|
-
*/
|
|
62
|
-
model: StringAnyType;
|
|
63
|
-
/**
|
|
64
|
-
* Optional configuration for Redis FT search
|
|
65
|
-
*/
|
|
66
|
-
search: WorkflowSearchOptions;
|
|
67
|
-
static MeshOS: typeof WorkflowService;
|
|
68
|
-
static getHotMeshClient(redisClass: RedisClass, redisOptions: RedisOptions, namespace: string, taskQueue: string): Promise<import("../hotmesh").HotMeshService>;
|
|
69
|
-
/**
|
|
70
|
-
* mints a workflow ID, using the search prefix.
|
|
71
|
-
* NOTE: The prefix is necesary when indexing
|
|
72
|
-
* HASHes when FT search is enabled.
|
|
73
|
-
* @returns {string}
|
|
74
|
-
*/
|
|
75
|
-
static mintGuid(): string;
|
|
76
|
-
/**
|
|
77
|
-
* Creates an FT search index
|
|
78
|
-
*/
|
|
79
|
-
static createIndex(): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* Lists FT search indexes
|
|
82
|
-
*/
|
|
83
|
-
static listIndexes(): Promise<string[]>;
|
|
84
|
-
/**
|
|
85
|
-
* stop the workers
|
|
86
|
-
* @returns {Promise<void>}
|
|
87
|
-
*/
|
|
88
|
-
static stopWorkers(): Promise<void>;
|
|
89
|
-
/**
|
|
90
|
-
* Initializes the worker(s). This is a static
|
|
91
|
-
* method that allows for optional task Queue targeting.
|
|
92
|
-
* An `allowList` may be optionally provided to start
|
|
93
|
-
* specific `worker` and `hook` methods.
|
|
94
|
-
* @param {MeshOSWorkerOptions} [options]
|
|
95
|
-
*/
|
|
96
|
-
static startWorkers(options?: MeshOSWorkerOptions): Promise<void>;
|
|
97
|
-
/**
|
|
98
|
-
* executes the redis FT search query; optionally specify other commands
|
|
99
|
-
* @example '@_quantity:[89 89]'
|
|
100
|
-
* @example '@_quantity:[89 89] @_name:"John"'
|
|
101
|
-
* @example 'FT.search my-index @_quantity:[89 89]'
|
|
102
|
-
* @param {FindOptions} options
|
|
103
|
-
* @param {any[]} args
|
|
104
|
-
* @returns {Promise<string[] | [number] | Array<number, string | number | string[]>>}
|
|
105
|
-
*/
|
|
106
|
-
static find(options: FindOptions, ...args: string[]): Promise<string[] | [number] | Array<string | number | string[]>>;
|
|
107
|
-
/**
|
|
108
|
-
* Provides a JSON abstraction for the Redis FT.search command
|
|
109
|
-
* (e.g, `count`, `query`, `return`, `limit`)
|
|
110
|
-
* @param {FindWhereOptions} options
|
|
111
|
-
* @returns {Promise<string[] | [number] | Array<string | number | string[]>>}
|
|
112
|
-
*/
|
|
113
|
-
static findWhere(options: FindWhereOptions): Promise<string[] | [number] | Array<string | number | string[]>>;
|
|
114
|
-
static generateSearchQuery(query: FindWhereQuery[]): string;
|
|
115
|
-
/**
|
|
116
|
-
* returns the workflow handle. The handle can then be
|
|
117
|
-
* used to query for status, state, custom state, etc.
|
|
118
|
-
* @param {string} id
|
|
119
|
-
* @returns {Promise<WorkflowHandleService>}
|
|
120
|
-
*/
|
|
121
|
-
static get(id: string): Promise<WorkflowHandleService>;
|
|
122
|
-
/**
|
|
123
|
-
* Optionally include a target taskQueue to exec the
|
|
124
|
-
* workflow's call on a specific worker queue.
|
|
125
|
-
*/
|
|
126
|
-
constructor(id?: string | MeshOSConfig, options?: MeshOSConfig);
|
|
127
|
-
}
|
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MeshOSService = void 0;
|
|
4
|
-
const _1 = require(".");
|
|
5
|
-
const storage_1 = require("../../modules/storage");
|
|
6
|
-
const client_1 = require("./client");
|
|
7
|
-
const search_1 = require("./search");
|
|
8
|
-
const worker_1 = require("./worker");
|
|
9
|
-
const workflow_1 = require("./workflow");
|
|
10
|
-
const utils_1 = require("../../modules/utils");
|
|
11
|
-
/**
|
|
12
|
-
* The base class for running MeshOS workflows.
|
|
13
|
-
* Extend this class, add your Redis config, and add functions to
|
|
14
|
-
* execute as durable `hooks`, `workflows`, and `activities`.
|
|
15
|
-
*/
|
|
16
|
-
class MeshOSService {
|
|
17
|
-
static async getHotMeshClient(redisClass, redisOptions, namespace, taskQueue) {
|
|
18
|
-
const client = new client_1.ClientService({
|
|
19
|
-
connection: {
|
|
20
|
-
class: redisClass,
|
|
21
|
-
options: redisOptions,
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return await client.getHotMeshClient(taskQueue, namespace);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* mints a workflow ID, using the search prefix.
|
|
28
|
-
* NOTE: The prefix is necesary when indexing
|
|
29
|
-
* HASHes when FT search is enabled.
|
|
30
|
-
* @returns {string}
|
|
31
|
-
*/
|
|
32
|
-
static mintGuid() {
|
|
33
|
-
const my = new this();
|
|
34
|
-
return `${my.search?.prefix?.[0]}${(0, utils_1.guid)()}`;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Creates an FT search index
|
|
38
|
-
*/
|
|
39
|
-
static async createIndex() {
|
|
40
|
-
const my = new this();
|
|
41
|
-
const hmClient = await MeshOSService.getHotMeshClient(my.redisClass, my.redisOptions, my.namespace, my.taskQueue);
|
|
42
|
-
await search_1.Search.configureSearchIndex(hmClient, my.search);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Lists FT search indexes
|
|
46
|
-
*/
|
|
47
|
-
static async listIndexes() {
|
|
48
|
-
const my = new this();
|
|
49
|
-
const hmClient = await MeshOSService.getHotMeshClient(my.redisClass, my.redisOptions, my.namespace, my.taskQueue);
|
|
50
|
-
return await search_1.Search.listSearchIndexes(hmClient);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* stop the workers
|
|
54
|
-
* @returns {Promise<void>}
|
|
55
|
-
*/
|
|
56
|
-
static async stopWorkers() {
|
|
57
|
-
await _1.Durable.shutdown();
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Initializes the worker(s). This is a static
|
|
61
|
-
* method that allows for optional task Queue targeting.
|
|
62
|
-
* An `allowList` may be optionally provided to start
|
|
63
|
-
* specific `worker` and `hook` methods.
|
|
64
|
-
* @param {MeshOSWorkerOptions} [options]
|
|
65
|
-
*/
|
|
66
|
-
static async startWorkers(options) {
|
|
67
|
-
const taskQueue = options && options.taskQueue;
|
|
68
|
-
const allowList = options && options.allowList || [];
|
|
69
|
-
const my = new this();
|
|
70
|
-
//helper functions
|
|
71
|
-
const resolveFunctionNames = (arr) => arr.map(item => typeof item === 'string' ? item : item.name);
|
|
72
|
-
const belongsTo = (name, target) => {
|
|
73
|
-
const isWorkflow = target.find((item) => {
|
|
74
|
-
return typeof item === 'string' ? item === name : item.name === name;
|
|
75
|
-
});
|
|
76
|
-
return isWorkflow !== undefined;
|
|
77
|
-
};
|
|
78
|
-
// proxy registered activities
|
|
79
|
-
const proxyFunctionNames = resolveFunctionNames([...my.proxyFunctions]);
|
|
80
|
-
if (proxyFunctionNames.length) {
|
|
81
|
-
const proxyActivities = proxyFunctionNames.reduce((acc, funcName) => {
|
|
82
|
-
let originalMethod = my[funcName];
|
|
83
|
-
if (typeof originalMethod === 'function') {
|
|
84
|
-
acc[funcName] = async (...args) => {
|
|
85
|
-
return await originalMethod.apply(my, args);
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return acc;
|
|
89
|
-
}, {});
|
|
90
|
-
const proxiedActivities = _1.Durable.workflow.proxyActivities({
|
|
91
|
-
activities: proxyActivities
|
|
92
|
-
});
|
|
93
|
-
Object.assign(my, proxiedActivities);
|
|
94
|
-
}
|
|
95
|
-
const functionsToIterate = allowList.length ? resolveFunctionNames(allowList) : resolveFunctionNames([...my.workflowFunctions, ...my.hookFunctions]);
|
|
96
|
-
// Iterating through the functions sequentially
|
|
97
|
-
for (const funcName of functionsToIterate) {
|
|
98
|
-
const originalMethod = my[funcName];
|
|
99
|
-
if (typeof originalMethod === 'function') {
|
|
100
|
-
//wrap the function to return
|
|
101
|
-
const wrappedFunction = {
|
|
102
|
-
[funcName]: async (...args) => {
|
|
103
|
-
const store = storage_1.asyncLocalStorage.getStore();
|
|
104
|
-
const workflowId = store.get('workflowId');
|
|
105
|
-
//use a Proxy to wrap hook methods
|
|
106
|
-
const context = new Proxy(my, {
|
|
107
|
-
get: (target, prop, receiver) => {
|
|
108
|
-
if (prop === 'id') {
|
|
109
|
-
return workflowId;
|
|
110
|
-
}
|
|
111
|
-
else if (typeof target[prop] === 'function') {
|
|
112
|
-
return (...args) => {
|
|
113
|
-
return new Promise(async (resolve, reject) => {
|
|
114
|
-
if (belongsTo(prop, my.hookFunctions)) {
|
|
115
|
-
return workflow_1.WorkflowService.hook({
|
|
116
|
-
namespace: my.namespace,
|
|
117
|
-
taskQueue: my.taskQueue,
|
|
118
|
-
workflowName: prop,
|
|
119
|
-
workflowId,
|
|
120
|
-
args,
|
|
121
|
-
}).then(resolve).catch(reject);
|
|
122
|
-
}
|
|
123
|
-
//otherwise, call the method as a standard instance method.
|
|
124
|
-
target[prop].apply(this, args).then(resolve).catch(reject);
|
|
125
|
-
});
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return Reflect.get(target, prop, receiver);
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
return await originalMethod.apply(context, args);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
//start the worker
|
|
135
|
-
await worker_1.WorkerService.create({
|
|
136
|
-
namespace: my.namespace,
|
|
137
|
-
connection: {
|
|
138
|
-
class: my.redisClass,
|
|
139
|
-
options: my.redisOptions,
|
|
140
|
-
},
|
|
141
|
-
taskQueue: taskQueue ?? my.taskQueue,
|
|
142
|
-
workflow: wrappedFunction,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* executes the redis FT search query; optionally specify other commands
|
|
149
|
-
* @example '@_quantity:[89 89]'
|
|
150
|
-
* @example '@_quantity:[89 89] @_name:"John"'
|
|
151
|
-
* @example 'FT.search my-index @_quantity:[89 89]'
|
|
152
|
-
* @param {FindOptions} options
|
|
153
|
-
* @param {any[]} args
|
|
154
|
-
* @returns {Promise<string[] | [number] | Array<number, string | number | string[]>>}
|
|
155
|
-
*/
|
|
156
|
-
static async find(options, ...args) {
|
|
157
|
-
const my = new this();
|
|
158
|
-
const client = new client_1.ClientService({ connection: {
|
|
159
|
-
class: my.redisClass,
|
|
160
|
-
options: my.redisOptions
|
|
161
|
-
} });
|
|
162
|
-
let workflowName;
|
|
163
|
-
if (options.workflowName) {
|
|
164
|
-
workflowName = options?.workflowName;
|
|
165
|
-
}
|
|
166
|
-
else if (my.workflowFunctions?.length) {
|
|
167
|
-
let target = my.workflowFunctions[0];
|
|
168
|
-
if (typeof target === 'string') {
|
|
169
|
-
workflowName = target;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
workflowName = target.name;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return await client.workflow.search(options.taskQueue ?? my.taskQueue, workflowName, options.namespace ?? my.namespace, options.index ?? my.search.index, ...args); //[count, [id, fields[]], [id, fields[]], [id, fields[]], ...]]
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Provides a JSON abstraction for the Redis FT.search command
|
|
179
|
-
* (e.g, `count`, `query`, `return`, `limit`)
|
|
180
|
-
* @param {FindWhereOptions} options
|
|
181
|
-
* @returns {Promise<string[] | [number] | Array<string | number | string[]>>}
|
|
182
|
-
*/
|
|
183
|
-
static async findWhere(options) {
|
|
184
|
-
const args = [this.generateSearchQuery(options.query)];
|
|
185
|
-
if (options.count) {
|
|
186
|
-
args.push('LIMIT', '0', '0');
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
//limit which hash fields to return
|
|
190
|
-
args.push('RETURN');
|
|
191
|
-
args.push(((options.return?.length ?? 0) + 1).toString());
|
|
192
|
-
args.push('$');
|
|
193
|
-
options.return?.forEach(returnField => {
|
|
194
|
-
if (returnField.startsWith('"')) {
|
|
195
|
-
//allow literal values to be requested
|
|
196
|
-
args.push(returnField.slice(1, -1));
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
args.push(`_${returnField}`);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
//paginate
|
|
203
|
-
if (options.limit) {
|
|
204
|
-
args.push('LIMIT', options.limit.start.toString(), options.limit.size.toString());
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return await this.find(options.options ?? {}, ...args);
|
|
208
|
-
}
|
|
209
|
-
static generateSearchQuery(query) {
|
|
210
|
-
if (!Array.isArray(query) || query.length === 0) {
|
|
211
|
-
return '*';
|
|
212
|
-
}
|
|
213
|
-
const my = new this();
|
|
214
|
-
let queryString = query.map(q => {
|
|
215
|
-
const { field, is, value, type } = q;
|
|
216
|
-
const prefixedFieldName = my.search?.schema && field in my.search.schema ? `@_${field}` : `@${field}`;
|
|
217
|
-
const fieldType = my.search?.schema[field]?.type ?? type ?? 'TEXT';
|
|
218
|
-
switch (fieldType) {
|
|
219
|
-
case 'TAG':
|
|
220
|
-
return `${prefixedFieldName}:{${value}}`;
|
|
221
|
-
case 'TEXT':
|
|
222
|
-
return `${prefixedFieldName}:"${value}"`;
|
|
223
|
-
case 'NUMERIC':
|
|
224
|
-
let range = '';
|
|
225
|
-
if (is.startsWith('=')) { //equal
|
|
226
|
-
range = `[${value} ${value}]`;
|
|
227
|
-
}
|
|
228
|
-
else if (is.startsWith('<')) { //less than or equal
|
|
229
|
-
range = `[-inf ${value}]`;
|
|
230
|
-
}
|
|
231
|
-
else if (is.startsWith('>')) { //greater than or equal
|
|
232
|
-
range = `[${value} +inf]`;
|
|
233
|
-
}
|
|
234
|
-
else if (is === '[]') { //between
|
|
235
|
-
range = `[${value[0]} ${value[1]}]`;
|
|
236
|
-
}
|
|
237
|
-
return `${prefixedFieldName}:${range}`;
|
|
238
|
-
default:
|
|
239
|
-
return '';
|
|
240
|
-
}
|
|
241
|
-
}).join(' ');
|
|
242
|
-
return queryString;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* returns the workflow handle. The handle can then be
|
|
246
|
-
* used to query for status, state, custom state, etc.
|
|
247
|
-
* @param {string} id
|
|
248
|
-
* @returns {Promise<WorkflowHandleService>}
|
|
249
|
-
*/
|
|
250
|
-
static async get(id) {
|
|
251
|
-
const my = new this();
|
|
252
|
-
const client = new client_1.ClientService({ connection: {
|
|
253
|
-
class: my.redisClass,
|
|
254
|
-
options: my.redisOptions
|
|
255
|
-
} });
|
|
256
|
-
let workflowName;
|
|
257
|
-
let target = my.workflowFunctions[0];
|
|
258
|
-
if (typeof target === 'string') {
|
|
259
|
-
workflowName = target;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
workflowName = target.name;
|
|
263
|
-
}
|
|
264
|
-
return await client.workflow.getHandle(my.taskQueue, workflowName, id, my.namespace);
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Optionally include a target taskQueue to exec the
|
|
268
|
-
* workflow's call on a specific worker queue.
|
|
269
|
-
*/
|
|
270
|
-
constructor(id, options) {
|
|
271
|
-
/**
|
|
272
|
-
* The top-level Redis isolation. All workflow data is
|
|
273
|
-
* isolated within this namespace. Values should be
|
|
274
|
-
* lower-case with no spaces (e.g, 'staging', 'prod', 'test',
|
|
275
|
-
* 'routing-stagig', 'reporting-prod', etc.).
|
|
276
|
-
* 1) only url-safe values are allowed;
|
|
277
|
-
* 2) the 'a' symbol is reserved by HotMesh for indexing apps
|
|
278
|
-
*/
|
|
279
|
-
this.namespace = 'durable';
|
|
280
|
-
/**
|
|
281
|
-
* Data is routed to workers that specify this task queue.
|
|
282
|
-
* Setting the task queue when the worker is created will
|
|
283
|
-
* ensure that the worker only receives messages destined
|
|
284
|
-
* for the queue. Callers can specify the taskQue to when
|
|
285
|
-
* starting a job to call those workers.
|
|
286
|
-
*/
|
|
287
|
-
this.taskQueue = 'default';
|
|
288
|
-
/**
|
|
289
|
-
* These methods run as durable workflows
|
|
290
|
-
*/
|
|
291
|
-
this.workflowFunctions = [];
|
|
292
|
-
/**
|
|
293
|
-
* These methods run as hooks (hook into a running workflow)
|
|
294
|
-
*/
|
|
295
|
-
this.hookFunctions = [];
|
|
296
|
-
/**
|
|
297
|
-
* These methods run as proxied activities (and are safely memoized)
|
|
298
|
-
*/
|
|
299
|
-
this.proxyFunctions = [];
|
|
300
|
-
/**
|
|
301
|
-
* The Redis connection options. NOTE: Redis and IORedis
|
|
302
|
-
* use different formats for their connection config.
|
|
303
|
-
*/
|
|
304
|
-
this.redisOptions = {
|
|
305
|
-
host: 'localhost',
|
|
306
|
-
port: 6379,
|
|
307
|
-
password: '',
|
|
308
|
-
db: 0,
|
|
309
|
-
};
|
|
310
|
-
if (typeof (id) === 'string') {
|
|
311
|
-
this.id = id;
|
|
312
|
-
}
|
|
313
|
-
else if (id?.id) {
|
|
314
|
-
this.id = id.id;
|
|
315
|
-
options = id;
|
|
316
|
-
id = undefined;
|
|
317
|
-
}
|
|
318
|
-
;
|
|
319
|
-
if (options?.taskQueue) {
|
|
320
|
-
this.taskQueue = options.taskQueue;
|
|
321
|
-
}
|
|
322
|
-
else if (!id && !options?.taskQueue) {
|
|
323
|
-
return this;
|
|
324
|
-
}
|
|
325
|
-
function belongsTo(name, target) {
|
|
326
|
-
const isWorkflow = target.find((item) => {
|
|
327
|
-
return typeof item === 'string' ? item === name : item.name === name;
|
|
328
|
-
});
|
|
329
|
-
return isWorkflow !== undefined;
|
|
330
|
-
}
|
|
331
|
-
return new Proxy(this, {
|
|
332
|
-
get: (target, prop, receiver) => {
|
|
333
|
-
if (typeof target[prop] === 'function') {
|
|
334
|
-
return (...args) => {
|
|
335
|
-
return new Promise(async (resolve, reject) => {
|
|
336
|
-
const client = new client_1.ClientService({ connection: {
|
|
337
|
-
class: this.redisClass,
|
|
338
|
-
options: this.redisOptions
|
|
339
|
-
} });
|
|
340
|
-
if (belongsTo(prop, this.workflowFunctions)) {
|
|
341
|
-
//start a new workflow
|
|
342
|
-
const handle = await client.workflow.start({
|
|
343
|
-
namespace: this.namespace,
|
|
344
|
-
args,
|
|
345
|
-
taskQueue: this.taskQueue,
|
|
346
|
-
workflowName: prop,
|
|
347
|
-
workflowId: this.id,
|
|
348
|
-
});
|
|
349
|
-
if (options?.await) {
|
|
350
|
-
//wait for the workflow to complete
|
|
351
|
-
const result = await handle.result();
|
|
352
|
-
return resolve(result);
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
//return the workflow handle
|
|
356
|
-
return resolve(handle);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
else if (belongsTo(prop, this.hookFunctions)) {
|
|
360
|
-
//hook into a running workflow
|
|
361
|
-
return client.workflow.hook({
|
|
362
|
-
namespace: this.namespace,
|
|
363
|
-
taskQueue: this.taskQueue,
|
|
364
|
-
workflowName: prop,
|
|
365
|
-
workflowId: this.id,
|
|
366
|
-
args,
|
|
367
|
-
}).then(resolve).catch(reject);
|
|
368
|
-
}
|
|
369
|
-
//otherwise, call the method as a standard instance method.
|
|
370
|
-
target[prop].apply(this, args).then(resolve).catch(reject);
|
|
371
|
-
});
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
return Reflect.get(target, prop, receiver);
|
|
375
|
-
},
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
MeshOSService.MeshOS = workflow_1.WorkflowService;
|
|
380
|
-
exports.MeshOSService = MeshOSService;
|