@weclapp/sdk 2.0.0-dev.42 → 2.0.0-dev.44
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 +71 -72
- package/dist/cli.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# weclapp SDK Generator
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<h1>weclapp sdk generator</h1>
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
<br/>
|
|
8
|
-
|
|
9
|
-
# Introduction
|
|
3
|
+
## Introduction
|
|
10
4
|
|
|
11
5
|
This is an SDK generator, it will take an [`openapi.json`](https://swagger.io/specification/) from [weclapp](https://weclapp.com/) and build services and typescript types according to the entities defined in it. Each service is responsible for a _single_ entity. Every service contains all functions available for this
|
|
12
6
|
entity, this may include functions such as `update`, `remove`, `some` and many more. With these functions you can send requests to your weclapp system to get data or manipulate them.
|
|
@@ -17,7 +11,7 @@ Check out [generated types and utilities](#generated-types-and-utilities) for mo
|
|
|
17
11
|
|
|
18
12
|
What's being generated depends on the weclapp version you're using.
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
## Getting started
|
|
21
15
|
|
|
22
16
|
The SDK generator requires the current or LTS version of nodejs, as well as npm v10.
|
|
23
17
|
|
|
@@ -46,7 +40,7 @@ This way, every time someone installs or updates dependencies, the SDK is genera
|
|
|
46
40
|
}
|
|
47
41
|
```
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
### Available flags
|
|
50
44
|
|
|
51
45
|
| Flag | Description | Value / Type |
|
|
52
46
|
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
@@ -64,12 +58,12 @@ This way, every time someone installs or updates dependencies, the SDK is genera
|
|
|
64
58
|
After that, you can import the sdk via `@weclapp/sdk`.
|
|
65
59
|
Check out the [docs](docs) for how the generated SDK looks like and how to use it!
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
## Initialization
|
|
68
62
|
|
|
69
63
|
To initialize a service a `ServiceConfig` is needed, you can specify a global config in case you don't want to pass the config every time to the service you
|
|
70
64
|
want to use manually. If you pass an empty object as ServiceConfig the [location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) will be used to get the domain and the protocol (secure config option).
|
|
71
65
|
|
|
72
|
-
|
|
66
|
+
### Service config
|
|
73
67
|
|
|
74
68
|
The configuration looks like the following (taken from [globalConfig.ts](/src/generator/01-base/static/globalConfig.ts.txt)):
|
|
75
69
|
|
|
@@ -111,11 +105,11 @@ interface ServiceConfig {
|
|
|
111
105
|
}
|
|
112
106
|
```
|
|
113
107
|
|
|
114
|
-
###
|
|
108
|
+
### Using the config
|
|
115
109
|
|
|
116
110
|
There are three ways of accessing a service through the SDK:
|
|
117
111
|
|
|
118
|
-
#### Using
|
|
112
|
+
#### Using the global config
|
|
119
113
|
|
|
120
114
|
```ts
|
|
121
115
|
import { setGlobalConfig, partyService } from '@weclapp/sdk';
|
|
@@ -130,7 +124,7 @@ const party = partyService();
|
|
|
130
124
|
console.log(`Total amount of parties: ${await party.count()}`);
|
|
131
125
|
```
|
|
132
126
|
|
|
133
|
-
#### Using a
|
|
127
|
+
#### Using a config per service
|
|
134
128
|
|
|
135
129
|
```ts
|
|
136
130
|
import { partyService } from '@weclapp/sdk';
|
|
@@ -175,53 +169,20 @@ interface RequestPayload {
|
|
|
175
169
|
forceBlob?: boolean;
|
|
176
170
|
}
|
|
177
171
|
```
|
|
172
|
+
|
|
178
173
|
and `RequestOptions` looks like this:
|
|
174
|
+
|
|
179
175
|
```ts
|
|
180
176
|
interface RequestOptions {
|
|
181
|
-
|
|
177
|
+
signal?: AbortSignal;
|
|
182
178
|
}
|
|
183
|
-
````
|
|
184
|
-
|
|
185
|
-
#### Aborting a request
|
|
186
|
-
To abort a request an AbortController has to be instantiated and its signal has to be passed to the request. The controller can
|
|
187
|
-
abort the request when needed and the case can be handled with a catch.
|
|
188
|
-
```ts
|
|
189
|
-
import { wServices } from "@sdk/dist";
|
|
190
|
-
|
|
191
|
-
const controller = new AbortController();
|
|
192
|
-
let count = 0;
|
|
193
|
-
|
|
194
|
-
wServices.article
|
|
195
|
-
.count(
|
|
196
|
-
{
|
|
197
|
-
where: {
|
|
198
|
-
active: { EQ: true },
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
{ signal: controller.signal }
|
|
202
|
-
)
|
|
203
|
-
.then((c) => (count = c))
|
|
204
|
-
.catch((err) => {
|
|
205
|
-
if (controller.signal.aborted) {
|
|
206
|
-
if (controller.signal.reason) {
|
|
207
|
-
console.log(`Request aborted with reason: ${controller.signal.reason}`);
|
|
208
|
-
} else {
|
|
209
|
-
console.log('Request aborted but no reason was given.');
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
console.log(err);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
controller.abort('Abort article count request');
|
|
217
179
|
```
|
|
218
180
|
|
|
219
|
-
|
|
220
|
-
# Generated types and utilities
|
|
181
|
+
## Generated types and utilities
|
|
221
182
|
|
|
222
183
|
The generator generates various utilities that can be used to integrate it in a generic way into your app.
|
|
223
184
|
|
|
224
|
-
|
|
185
|
+
### Exported constants
|
|
225
186
|
|
|
226
187
|
| Constant | Description |
|
|
227
188
|
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -232,7 +193,7 @@ The generator generates various utilities that can be used to integrate it in a
|
|
|
232
193
|
| `wServices` | Object with all services where the name is the key and the value the service (that is using the global config). |
|
|
233
194
|
| `wEntityProperties` | Object with all entity names as key and properties including the type and format as value. |
|
|
234
195
|
|
|
235
|
-
|
|
196
|
+
### Exported types
|
|
236
197
|
|
|
237
198
|
| Type | Description | Type guards available? |
|
|
238
199
|
| ----------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
@@ -247,7 +208,7 @@ The generator generates various utilities that can be used to integrate it in a
|
|
|
247
208
|
| `WServices` | Type of `wServices`. | |
|
|
248
209
|
| `WEntityProperties` | Generalized type of `wEntityProperties`. | |
|
|
249
210
|
|
|
250
|
-
|
|
211
|
+
## Services and raw-function in depth
|
|
251
212
|
|
|
252
213
|
As already described above, the api endpoints can be requested via services or the raw function. The advantage of wServices over the raw function is that all endpoints of the entities are available as functions and these functions are typed. This makes it easier to work with the data provided via the weclapp API.
|
|
253
214
|
|
|
@@ -259,7 +220,7 @@ A service of an entity has in general the following base function:
|
|
|
259
220
|
remove: // deletes a entity
|
|
260
221
|
update: // updates a entity
|
|
261
222
|
|
|
262
|
-
In addition there are some custom endpoint functions. The generated PartyService is shown below as an example:
|
|
223
|
+
In addition, there are some custom endpoint functions. The generated PartyService is shown below as an example:
|
|
263
224
|
|
|
264
225
|
```ts
|
|
265
226
|
interface PartyService {
|
|
@@ -276,7 +237,7 @@ interface PartyService {
|
|
|
276
237
|
}
|
|
277
238
|
```
|
|
278
239
|
|
|
279
|
-
|
|
240
|
+
### Example
|
|
280
241
|
|
|
281
242
|
```ts
|
|
282
243
|
import { PartyType, setGlobalConfig, wServices } from '@weclapp/sdk';
|
|
@@ -322,9 +283,9 @@ if (contactRaw && typeof contactRaw.id === 'string') {
|
|
|
322
283
|
}
|
|
323
284
|
```
|
|
324
285
|
|
|
325
|
-
|
|
286
|
+
### Service request params
|
|
326
287
|
|
|
327
|
-
|
|
288
|
+
#### Filtering
|
|
328
289
|
|
|
329
290
|
With the some and count functions you can filter the requested data.
|
|
330
291
|
|
|
@@ -377,9 +338,9 @@ wServices['article'].some({
|
|
|
377
338
|
This is evaluated to:
|
|
378
339
|
(name EQ 'toy 1' OR articleNumber EQ '12345') AND batchNumberRequired EQ true
|
|
379
340
|
|
|
380
|
-
|
|
341
|
+
#### Where filter
|
|
381
342
|
|
|
382
|
-
|
|
343
|
+
> Warning: This is still a beta feature
|
|
383
344
|
|
|
384
345
|
It is also possible to specify complex filter expressions that can combine multiple conditions and express relations between properties:
|
|
385
346
|
|
|
@@ -398,7 +359,21 @@ wServices['article'].some({
|
|
|
398
359
|
|
|
399
360
|
"where" parameters are ANDed with other filter parameters.
|
|
400
361
|
|
|
401
|
-
|
|
362
|
+
It is also possible to set an empty list within an IN-query:
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
wServices['article'].some({
|
|
366
|
+
where: {
|
|
367
|
+
id: {
|
|
368
|
+
IN: []
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
This actually evaluates to `filter = 1 = 0`. The API does not accept filtering for empty lists. Therefore, in this case you have to send a falsy expression. You cannot send `false` directly, though.
|
|
375
|
+
|
|
376
|
+
#### Sort
|
|
402
377
|
|
|
403
378
|
You can sort your requested data with an array properties.
|
|
404
379
|
|
|
@@ -410,7 +385,7 @@ wServices['article'].some({
|
|
|
410
385
|
|
|
411
386
|
Sort by name (ascending) and then minimumPurchaseQuantity descending.
|
|
412
387
|
|
|
413
|
-
|
|
388
|
+
#### Pagination
|
|
414
389
|
|
|
415
390
|
By default the API returns only the first 100 entities. You can increase the size of one response to the maximum of 1000. To get the next 1000 entities you have increase the page number.
|
|
416
391
|
|
|
@@ -425,7 +400,7 @@ wServices['article'].some({
|
|
|
425
400
|
|
|
426
401
|
This returns the first 10 articles of the second page.
|
|
427
402
|
|
|
428
|
-
|
|
403
|
+
#### Select
|
|
429
404
|
|
|
430
405
|
With the select option you can fetch specific subset of properties:
|
|
431
406
|
|
|
@@ -437,18 +412,42 @@ wServices['article'].some({
|
|
|
437
412
|
|
|
438
413
|
This only returns the articleNumber property of all articles.
|
|
439
414
|
|
|
440
|
-
|
|
415
|
+
### Aborting a request
|
|
441
416
|
|
|
442
|
-
|
|
417
|
+
To abort a request an AbortController has to be instantiated and its signal has to be passed to the request. The controller can
|
|
418
|
+
abort the request when needed and the case can be handled with a catch.
|
|
443
419
|
|
|
444
420
|
```ts
|
|
445
|
-
wServices
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
421
|
+
import { wServices } from '@sdk/dist';
|
|
422
|
+
|
|
423
|
+
const controller = new AbortController();
|
|
424
|
+
let count = 0;
|
|
425
|
+
|
|
426
|
+
wServices.article
|
|
427
|
+
.count(
|
|
428
|
+
{
|
|
429
|
+
where: {
|
|
430
|
+
active: { EQ: true }
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{ signal: controller.signal }
|
|
434
|
+
)
|
|
435
|
+
.then((c) => (count = c))
|
|
436
|
+
.catch((err) => {
|
|
437
|
+
if (controller.signal.aborted) {
|
|
438
|
+
if (controller.signal.reason) {
|
|
439
|
+
console.log(`Request aborted with reason: ${controller.signal.reason}`);
|
|
440
|
+
} else {
|
|
441
|
+
console.log('Request aborted but no reason was given.');
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
console.log(err);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
controller.abort('Abort article count request');
|
|
450
449
|
```
|
|
451
450
|
|
|
452
|
-
|
|
451
|
+
## Contributing
|
|
453
452
|
|
|
454
453
|
Check out the [contributing guidelines](.github/CONTRIBUTING.md).
|
package/dist/cli.js
CHANGED
|
@@ -136,9 +136,9 @@ var globalConfig = "export type RequestPayloadMethod =\n | 'GET'\n | 'HEAD'\n
|
|
|
136
136
|
|
|
137
137
|
var multiRequest = "type RequestTask = {\n uri: string;\n resolve: (result: unknown) => void;\n reject: (error: unknown) => void;\n};\n\ntype BatchRequestTask = RequestTask & {\n settled: boolean;\n};\n\ntype MultiRequestResponse = {\n status: number;\n body: object;\n};\n\nlet microtaskQueued: boolean = false;\nconst tasksSet: Set<RequestTask> = new Set<RequestTask>();\n\nconst SQUARE_BRACKET_OPEN = '['.charCodeAt(0);\nconst COMMA = ','.charCodeAt(0);\nconst DECODER = new TextDecoder();\n\nconst readNextResponse = (bytes: Uint8Array) => {\n let headerStart: number | undefined = undefined;\n let commasSeen = 0;\n\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i];\n if (headerStart === undefined) {\n if (byte === SQUARE_BRACKET_OPEN || byte === COMMA) {\n headerStart = i + 1;\n }\n } else {\n if (byte === COMMA) {\n commasSeen++;\n }\n if (commasSeen === 2) {\n const headerArrayString = `[${DECODER.decode(bytes.subarray(headerStart, i))}]`;\n const [index, jsonLength] = JSON.parse(headerArrayString);\n if (!(typeof index === 'number') || !(typeof jsonLength === 'number')) {\n throw new Error(`unexpected header: ${headerArrayString}`);\n }\n\n const endIndex = i + 1 + jsonLength;\n if (endIndex > bytes.length) {\n // not all bytes available yet\n return undefined;\n }\n const jsonString = DECODER.decode(bytes.subarray(i + 1, endIndex));\n const data = JSON.parse(jsonString) as MultiRequestResponse;\n return {\n index,\n data,\n remainingBytes: bytes.subarray(endIndex)\n };\n }\n }\n }\n return undefined;\n};\n\nconst fetchMultiRequest = async (requests: string[]) => {\n const cfg = getGlobalConfig();\n\n if (!cfg) {\n throw new Error(`ServiceConfig missing.`);\n }\n\n const host = getHost(cfg);\n const protocol = getProtocol(cfg);\n\n return await fetch(`${protocol}//${host}/webapp/api/v2/batch/query`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(cfg.key && { AuthenticationToken: cfg.key })\n },\n body: JSON.stringify({ requests })\n });\n};\n\nconst rejectTasks = (tasks: BatchRequestTask[], error: unknown) => {\n for (const task of tasks) {\n if (!task.settled) {\n task.reject(error);\n }\n }\n};\n\nconst processStream = (\n { value: chunk, done }: ReadableStreamReadResult<Uint8Array>,\n remainingBytes: Uint8Array,\n reader: ReadableStreamDefaultReader<Uint8Array>,\n tasks: BatchRequestTask[]\n) => {\n if (done) {\n return;\n }\n if (chunk) {\n let bytes = new Uint8Array(remainingBytes.length + chunk.length);\n bytes.set(remainingBytes);\n bytes.set(chunk, remainingBytes.length);\n\n while (bytes.length) {\n const result = readNextResponse(bytes);\n if (!result) {\n break;\n }\n const task = tasks[result.index];\n if (result.data.status >= 100 && result.data.status < 400) {\n task.resolve({\n ...result.data.body\n });\n } else {\n task.reject({\n ...result.data.body\n });\n }\n task.settled = true;\n bytes = result.remainingBytes;\n }\n reader\n .read()\n .then((readResult) => processStream(readResult, bytes, reader, tasks))\n .catch((error) => rejectTasks(tasks, error));\n }\n};\n\nconst batch = async (tasks: BatchRequestTask[]) => {\n try {\n const requests = tasks.map(({ uri }) => uri);\n const resp = await fetchMultiRequest(requests);\n const reader = resp.body?.getReader();\n\n if (!reader) {\n throw new Error('Stream reader is undefined');\n }\n reader\n .read()\n .then((readResult) => processStream(readResult, new Uint8Array(0), reader, tasks))\n .catch((error) => rejectTasks(tasks, error));\n } catch (e) {\n rejectTasks(tasks, e);\n throw e;\n }\n};\n\nconst addTask = (task: RequestTask) => {\n tasksSet.add(task);\n\n if (!microtaskQueued) {\n queueMicrotask(() => {\n microtaskQueued = false;\n if (tasksSet.size > 0) {\n const batchTasks = Array.from(tasksSet).map((task) => ({ ...task, settled: false }));\n void batch(batchTasks);\n tasksSet.clear();\n }\n });\n microtaskQueued = true;\n }\n};\n\nconst addRequest = (uri: string) => new Promise((resolve, reject) => addTask({ uri, resolve, reject }));\n";
|
|
138
138
|
|
|
139
|
-
var queriesWithFilter = "export type EqualityOperator = 'EQ' | 'NE';\n\nexport type ComparisonOperator =\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE'\n | 'ILIKE'\n | 'NOT_LIKE'\n | 'NOT_ILIKE'\n | 'IEQ'\n | 'NOT_IEQ';\n\nexport type ArrayOperator = 'IN' | 'NOT_IN';\n\nexport type Operator = EqualityOperator | ComparisonOperator | ArrayOperator;\n\nexport type
|
|
139
|
+
var queriesWithFilter = "export type EqualityOperator = 'EQ' | 'NE';\n\nexport type ComparisonOperator =\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE'\n | 'ILIKE'\n | 'NOT_LIKE'\n | 'NOT_ILIKE'\n | 'IEQ'\n | 'NOT_IEQ';\n\nexport type ArrayOperator = 'IN' | 'NOT_IN';\n\nexport type Operator = EqualityOperator | ComparisonOperator | ArrayOperator;\n\nexport type MapOperators<T> = { [K in EqualityOperator]?: T | null } & { [K in ComparisonOperator]?: T } & {\n [K in ArrayOperator]?: T[];\n};\n\nexport type QueryFilter<T> = {\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\n ? U extends Record<any, any>\n ? QueryFilter<U>\n : MapOperators<U>\n : T[P] extends Record<any, any> | undefined\n ? QueryFilter<T[P]>\n : MapOperators<T[P]>;\n};\n\nexport type CountQuery<F> = {\n filter?: QueryFilter<F>;\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\n};\n\nexport type SomeQuery<E, F, I, P> = {\n serializeNulls?: boolean;\n include?: QuerySelect<I>;\n properties?: P;\n filter?: QueryFilter<F> & CustomAttributeFilter;\n select?: QuerySelect<E>;\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\n sort?: Sort<E>[];\n pagination?: Pagination;\n};\n\nconst equality: string[] = ['EQ', 'NE', 'IEQ', 'NOT_IEQ'];\n\nconst simple: string[] = [...equality, 'LT', 'GT', 'LE', 'GE', 'LIKE', 'NOT_LIKE', 'ILIKE', 'NOT_ILIKE'];\n\nconst array: string[] = ['IN', 'NOT_IN'];\n\nconst filterMap: Record<Operator, string> = {\n EQ: 'eq',\n NE: 'ne',\n LT: 'lt',\n GT: 'gt',\n LE: 'le',\n GE: 'ge',\n LIKE: 'like',\n NOT_LIKE: 'notlike',\n ILIKE: 'ilike',\n NOT_ILIKE: 'notilike',\n IN: 'in',\n NOT_IN: 'notin',\n IEQ: 'ieq',\n NOT_IEQ: 'notieq'\n};\n\nconst flattenCustomAttributes = (obj: CustomAttributeFilter = {}): [string, string][] => {\n const entries: [string, string][] = [];\n\n for (const [id, filter] of Object.entries(obj)) {\n const key = `customAttribute${id}`;\n\n if (typeof filter === 'object') {\n for (const [prop, value] of Object.entries(filter)) {\n entries.push([`${key}.${prop}-eq`, String(value)]);\n }\n } else if (filter !== undefined) {\n entries.push([`${key}-eq`, String(filter)]);\n }\n }\n\n return entries;\n};\n\nconst flatten = (obj: QueryFilter<any> = {}): [string, string][] => {\n const entries: [string, string][] = [];\n\n for (const [prop, propValue] of Object.entries(obj)) {\n for (const [filter, value] of Object.entries(propValue as object)) {\n if (value === undefined) continue;\n\n if (simple.includes(filter) || array.includes(filter)) {\n if (value === null && equality.includes(filter)) {\n entries.push([`${prop}-${filter === 'EQ' ? 'null' : 'notnull'}`, '']);\n } else {\n entries.push([`${prop}-${filterMap[filter as Operator]}`, value]);\n }\n } else {\n entries.push(\n ...(flatten(propValue as QueryFilter<any>).map((v) => [`${prop}.${v[0]}`, v[1]]) as [string, string][])\n );\n break;\n }\n }\n }\n\n return entries;\n};\n\nconst flattenFilter = (obj: QueryFilter<any> = {}): Record<string, string> => {\n const filter: [string, any][] = [],\n customAttributes: [string, any][] = [];\n\n Object.entries(obj).forEach((value) => {\n (value[0].match(/^\\d+$/) ? customAttributes : filter).push(value);\n });\n\n return Object.fromEntries([\n ...flatten(Object.fromEntries(filter)),\n ...flattenCustomAttributes(Object.fromEntries(customAttributes) as CustomAttributeFilter)\n ]);\n};\n\nconst flattenOrFilter = (obj: QueryFilter<any>[] = []): Record<string, string> => {\n const entries: [string, any][] = [];\n\n for (let i = 0; i < obj.length; i++) {\n entries.push(...(flatten(obj[i]).map((v) => [`or${i || ''}-${v[0]}`, v[1]]) as [string, string][]));\n }\n\n return Object.fromEntries(entries);\n};\n\nconst _count = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: CountQuery<any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n{\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n ...flattenFilter(query?.filter),\n ...flattenOrFilter(query?.or),\n ...query?.params\n }\n\n return wrapResponse(() =>\n raw(cfg, endpoint, {\n method: usePost ? 'POST' : 'GET',\n unwrap: true,\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions)\n )\n };\n\nconst _some = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n{\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n serializeNulls: query?.serializeNulls,\n additionalProperties: query?.properties?.join(','),\n properties: query?.select ? flattenSelect(query.select).join(',') : undefined,\n includeReferencedEntities: query?.include ? Object.keys(query.include).join(',') : undefined,\n ...flattenOrFilter(query?.or),\n ...flattenFilter(query?.filter),\n ...flattenSort(query?.sort),\n ...query?.params,\n ...query?.pagination\n }\n\n return wrapResponse(() =>\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions).then((data) => ({\n entities: data.result,\n references: data.referencedEntities ?? {},\n properties: data.additionalProperties ?? {}\n }))\n )\n };\n";
|
|
140
140
|
|
|
141
|
-
var queriesWithQueryLanguage = "export type ComparisonOperator =\n | 'EQ'\n | 'NE'\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE';\n\nexport type ArrayOperator = 'IN';\n\nexport type NullOperator = 'NULL';\n\nexport type Operator = ComparisonOperator | ArrayOperator | NullOperator;\n\nexport type ModifierFunction = 'lower';\n\nexport type
|
|
141
|
+
var queriesWithQueryLanguage = "export type ComparisonOperator =\n | 'EQ'\n | 'NE'\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE';\n\nexport type ArrayOperator = 'IN';\n\nexport type NullOperator = 'NULL';\n\nexport type Operator = ComparisonOperator | ArrayOperator | NullOperator;\n\nexport type ModifierFunction = 'lower';\n\nexport type MapOperators<T> =\n | ({ [K in ComparisonOperator]?: T } & { [K in ArrayOperator]?: T[] } & {\n [K in NullOperator]?: never } & {\n [K in ModifierFunction]?: boolean\n })\n | ({ [K in ComparisonOperator]?: T } & { [K in ArrayOperator]?: T[] } & {\n [K in NullOperator]?: boolean } & {\n [K in ModifierFunction]?: never\n });\n\nexport type SingleFilterExpr<T> = {\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\n ? U extends Record<any, any>\n ? SingleFilterExpr<U> | { NOT?: SingleFilterExpr<U> }\n : MapOperators<U>\n : T[P] extends Record<any, any> | undefined\n ? SingleFilterExpr<T[P]> | { NOT?: SingleFilterExpr<T[P]> }\n : MapOperators<T[P]>;\n};\n\nexport type QueryFilter<T> = SingleFilterExpr<T> & {\n OR?: QueryFilter<T>[];\n AND?: QueryFilter<T>[];\n NOT?: QueryFilter<T>;\n};\n\nexport type CountQuery<F> = {\n where?: QueryFilter<F>;\n};\n\nexport type SomeQuery<E, F, I, P> = {\n serializeNulls?: boolean;\n include?: QuerySelect<I>;\n properties?: P;\n where?: QueryFilter<F>;\n select?: QuerySelect<E>;\n sort?: Sort<E>[];\n pagination?: Pagination;\n};\n\nconst comparisonOperatorList: ComparisonOperator[] = [\n 'EQ',\n 'NE',\n 'LT',\n 'GT',\n 'LE',\n 'GE',\n 'LIKE'\n];\n\nconst comparisonOperatorMap: Record<Operator, string> = {\n EQ: '=',\n NE: '!=',\n LT: '<',\n GT: '>',\n LE: '<=',\n GE: '>=',\n LIKE: '~',\n IN: 'in',\n NULL: 'null'\n};\n\nconst modifierFunctionList: ModifierFunction[] = ['lower'];\n\nconst flattenWhere = (\n obj: QueryFilter<any> = {},\n nestedPaths: string[]\n): string[] => {\n const entries: string[] = [];\n for (const [prop, propValue] of Object.entries(obj)) {\n const setModifiers = findAllModifierFunctions(propValue ?? {}, modifierFunctionList).filter(\n (modifier) => modifier[1]\n );\n if (prop === 'OR') {\n const flattedOr: string[][] = [];\n for (let i = 0; i < (obj.OR?.length ?? 0); i++) {\n flattedOr.push(flattenWhere(obj.OR?.[i], nestedPaths));\n }\n entries.push(\n `(${flattedOr\n .map((x) => {\n const joined = x.join(' and ');\n\n if (x.length > 1) {\n return `(${joined})`;\n } else {\n return joined;\n }\n })\n .join(' or ')})`\n );\n } else if (prop === 'AND') {\n const flattedAnd: string[][] = [];\n for (let i = 0; i < (obj.AND?.length ?? 0); i++) {\n flattedAnd.push(flattenWhere(obj.AND?.[i], nestedPaths));\n }\n entries.push(\n `(${flattedAnd\n .map((x) => {\n const joined = x.join(' and ');\n\n if (x.length > 1) {\n return `(${joined})`;\n } else {\n return joined;\n }\n })\n .join(' and ')})`\n );\n } else if (prop === 'NOT') {\n const flattedNot = flattenWhere(obj.NOT, nestedPaths);\n entries.push(\n `not ${flattedNot.length > 1 ? '(' : ''}${flattedNot.join(' and ')}${flattedNot.length > 1 ? ')' : ''}`\n );\n } else if (propValue) {\n for (const [operator, value] of Object.entries(propValue)) {\n if (value === undefined) continue;\n if (comparisonOperatorList.includes(operator as ComparisonOperator)) {\n entries.push(\n `${setModifiers.reduce(\n (acc, [first]) => `${first}(${acc})`,\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\n )} ${comparisonOperatorMap[operator as Operator]} ${\n typeof value === 'string'\n ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(value))\n : value\n }`\n );\n } else if ((operator as Operator) === 'NULL') {\n entries.push(\n `${!value ? 'not ' : ''}${nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')} ${comparisonOperatorMap[operator as Operator]}`\n );\n } else if ((operator as Operator) === 'IN') {\n if(value.length === 0) {\n entries.push('1 = 0')\n } else {\n entries.push(\n `${setModifiers.reduce(\n (acc, [first]) => `${first}(${acc})`,\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\n )} ${comparisonOperatorMap[operator as Operator]} [${value.map((v: string | number) =>\n typeof v === 'string' ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(v)) : v\n )}]`\n );\n }\n } else if (\n !modifierFunctionList.includes(operator as ModifierFunction)\n ) {\n entries.push(\n ...flattenWhere(propValue as QueryFilter<any>, [\n ...nestedPaths,\n prop\n ])\n );\n break;\n }\n }\n }\n }\n return entries;\n};\n\nconst assembleFilterParam = (\n obj: QueryFilter<any> = {}\n): Record<string, string> => {\n const flattedFilter = flattenWhere(obj, []);\n return flattedFilter.length ? { filter: flattedFilter.join(' and ') } : {};\n};\n\nconst findAllModifierFunctions = (\n obj: Record<string, any>,\n types: ModifierFunction[]\n) => {\n const result: Record<string, any> = {};\n for (const key in obj) {\n if (types.includes(key as ModifierFunction)) {\n result[key] = obj[key];\n }\n }\n return Object.entries(result);\n};\n\nconst _count = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: CountQuery<any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n {\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n ...assembleFilterParam(query?.where),\n ...query?.params\n }\n\n return wrapResponse(() =>\n raw(cfg, endpoint, {\n unwrap: true,\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions)\n )\n };\n\nconst _some = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n {\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n serializeNulls: query?.serializeNulls,\n additionalProperties: query?.properties?.join(','),\n properties: query?.select\n ? flattenSelect(query.select).join(',')\n : undefined,\n includeReferencedEntities: query?.include\n ? Object.keys(query.include).join(',')\n : undefined,\n ...assembleFilterParam(query?.where),\n ...flattenSort(query?.sort),\n ...query?.params,\n ...query?.pagination\n }\n\n return wrapResponse(() =>\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions).then((data) => ({\n entities: data.result,\n references: data.referencedEntities ?? {},\n properties: data.additionalProperties ?? {}\n }))\n )\n };\n";
|
|
142
142
|
|
|
143
143
|
var root = "export const raw = async (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n payload: RequestPayload = {},\n requestOptions?: RequestOptions\n): Promise<any> => {\n if (!cfg && !globalConfig) {\n throw new Error(`ServiceConfig missing.`);\n }\n\n const localCfg = {\n ...globalConfig,\n ...cfg,\n interceptors: { ...globalConfig?.interceptors, ...cfg?.interceptors }\n };\n\n const isBinaryData = payload.body instanceof resolveBinaryObject();\n const params = new URLSearchParams(Object.entries(payload.query ?? {}).filter((v) => v[1] !== undefined)\n .map(([key, value]) => [key, typeof value === 'string' ? value : JSON.stringify(value)])\n );\n\n const protocol = getProtocol(localCfg);\n\n const interceptRequest = localCfg.interceptors?.request ?? ((v) => v);\n const interceptResponse = localCfg.interceptors?.response ?? ((v) => v);\n\n const host = getHost(localCfg);\n\n let data;\n if (!cfg && localCfg.multiRequest) {\n let ep = endpoint;\n if (endpoint.startsWith('/')) {\n ep = endpoint.replace('/', '');\n }\n data = await addRequest(`${ep}?${params}`);\n } else {\n const request = new Request(`${protocol}//${host}/webapp/api/v${apiVersion}${endpoint}?${params}`, {\n ...(payload.body && {\n body: isBinaryData\n ? payload.body\n : JSON.stringify(payload.body, (_key, value) => (value === undefined ? null : value))\n }),\n ...(!localCfg.key && { credentials: 'same-origin' }),\n method: payload.method ?? 'get',\n headers: {\n Accept: 'application/json',\n ...(localCfg.key && { AuthenticationToken: localCfg.key }),\n ...(!isBinaryData && { 'Content-Type': 'application/json' })\n }\n });\n let res = (await interceptRequest(request, payload)) ?? request;\n if (!(res instanceof Response)) {\n res = requestOptions?.signal ? await fetch(res, { signal: requestOptions.signal } ) : await fetch(res);\n }\n res = (await interceptResponse(res)) ?? res;\n data =\n (!payload.forceBlob || !res.ok) && res.headers?.get('content-type')?.includes('application/json')\n ? await res.json()\n : await res.blob();\n\n // Check if response was successful\n if (!res.ok) {\n return Promise.reject(data);\n }\n }\n\n return payload.unwrap ? data.result : data;\n};\n\nconst _remove = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n endpoint: string,\n { dryRun = false }: RemoveQuery = {},\n requestOptions?: RequestOptions\n) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'DELETE',\n query: { dryRun }\n }, requestOptions).then(() => undefined)\n );\n\nconst _create = (cfg: ServiceConfigWithoutMultiRequest | undefined, endpoint: string, data: any, requestOptions?: RequestOptions) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'POST',\n body: data\n }, requestOptions)\n );\n\nconst _update = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n endpoint: string,\n data: any,\n { ignoreMissingProperties, dryRun = false }: UpdateQuery = {},\n requestOptions?: RequestOptions\n) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'PUT',\n body: data,\n query: {\n ignoreMissingProperties:\n ignoreMissingProperties ?? cfg?.ignoreMissingProperties ?? globalConfig?.ignoreMissingProperties,\n dryRun\n }\n }, requestOptions)\n );\n\nconst _generic = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n method: RequestPayloadMethod,\n endpoint: string,\n payload?: GenericQuery<any, any>,\n forceBlob?: boolean,\n requestOptions?: RequestOptions\n) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method,\n forceBlob,\n body: payload?.body,\n query: payload?.params\n }, requestOptions)\n);\n";
|
|
144
144
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weclapp/sdk",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0-dev.44",
|
|
4
|
+
"description": "weclapp SDK Generator",
|
|
5
5
|
"author": "weclapp",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"bugs": "https://github.com/weclapp/sdk/issues",
|