@tstdl/base 0.90.85 → 0.90.89
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/api/client/client.js +2 -8
- package/data-structures/collection.d.ts +22 -22
- package/data-structures/collection.js +18 -18
- package/data-structures/iterable-weak-map.d.ts +2 -2
- package/data-structures/iterable-weak-map.js +2 -2
- package/database/query.d.ts +4 -4
- package/dom/observation/intersection-observer.d.ts +4 -9
- package/dom/observation/intersection-observer.js +20 -25
- package/dom/observation/resize-observer.d.ts +4 -8
- package/dom/observation/resize-observer.js +25 -31
- package/http/client/adapters/undici.adapter.js +13 -9
- package/http/client/http-client-request.d.ts +7 -8
- package/http/client/http-client-request.js +25 -1
- package/http/client/http-client.js +7 -5
- package/memory/observable-finalization-registry.d.ts +1 -1
- package/orm/entity.d.ts +16 -0
- package/orm/entity.js +49 -0
- package/orm/index.d.ts +3 -0
- package/orm/index.js +3 -0
- package/orm/query.d.ts +112 -0
- package/orm/query.js +7 -0
- package/orm/repository.d.ts +50 -0
- package/orm/repository.js +4 -0
- package/package.json +3 -3
- package/schema/schemas/record.d.ts +1 -1
- package/utils/async-iterable-helpers/group-to-map.js +10 -5
- package/utils/async-iterable-helpers/parallel/group.js +5 -3
- package/utils/factory-map.d.ts +10 -4
- package/utils/factory-map.js +25 -14
- package/utils/iterable-helpers/group-to-map.js +5 -3
package/api/client/client.js
CHANGED
|
@@ -93,14 +93,8 @@ function getRequestBody(body) {
|
|
|
93
93
|
if (isUndefined(body)) {
|
|
94
94
|
return undefined;
|
|
95
95
|
}
|
|
96
|
-
if (isUint8Array(body)) {
|
|
97
|
-
return {
|
|
98
|
-
}
|
|
99
|
-
if (isReadableStream(body)) {
|
|
100
|
-
return { stream: body };
|
|
101
|
-
}
|
|
102
|
-
if (isBlob(body)) {
|
|
103
|
-
return { blob: body };
|
|
96
|
+
if (isUint8Array(body) || isReadableStream(body) || isBlob(body)) {
|
|
97
|
+
return { binary: body };
|
|
104
98
|
}
|
|
105
99
|
if (isString(body)) {
|
|
106
100
|
return { text: body };
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
import type { ToJson } from '../interfaces.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type Observable } from 'rxjs';
|
|
3
3
|
export declare abstract class Collection<T, TThis extends Collection<T, TThis> = Collection<T, any>> implements Iterable<T>, ToJson {
|
|
4
4
|
private readonly sizeSubject;
|
|
5
5
|
private readonly changeSubject;
|
|
6
6
|
private readonly clearSubject;
|
|
7
|
-
/**
|
|
7
|
+
/** Emits collection on subscribe and change */
|
|
8
8
|
readonly observe$: Observable<TThis>;
|
|
9
|
-
/**
|
|
9
|
+
/** Emits size of collection */
|
|
10
10
|
readonly size$: Observable<number>;
|
|
11
|
-
/**
|
|
11
|
+
/** Emits collection on change */
|
|
12
12
|
readonly change$: Observable<TThis>;
|
|
13
13
|
readonly clear$: Observable<TThis>;
|
|
14
|
-
/**
|
|
14
|
+
/** Emits when the collection is empty */
|
|
15
15
|
readonly onEmpty$: Observable<void>;
|
|
16
|
-
/**
|
|
16
|
+
/** Emits when the collection has items */
|
|
17
17
|
readonly onItems$: Observable<void>;
|
|
18
|
-
/**
|
|
18
|
+
/** Emits whether the collection is empty */
|
|
19
19
|
readonly isEmpty$: Observable<boolean>;
|
|
20
|
-
/**
|
|
20
|
+
/** Emits whether the collection has items */
|
|
21
21
|
readonly hasItems$: Observable<boolean>;
|
|
22
|
-
/**
|
|
22
|
+
/** Resolves when the collection is empty */
|
|
23
23
|
get $onEmpty(): Promise<void>;
|
|
24
|
-
/**
|
|
24
|
+
/** Resolves when the collection has items */
|
|
25
25
|
get $onItems(): Promise<void>;
|
|
26
|
-
/**
|
|
26
|
+
/** Size of collection */
|
|
27
27
|
get size(): number;
|
|
28
|
-
/**
|
|
28
|
+
/** Whether the collection is empty */
|
|
29
29
|
get isEmpty(): boolean;
|
|
30
|
-
/**
|
|
30
|
+
/** Whether the collection has items */
|
|
31
31
|
get hasItems(): boolean;
|
|
32
32
|
constructor();
|
|
33
33
|
[Symbol.iterator](): IterableIterator<T>;
|
|
34
34
|
toArray(): T[];
|
|
35
35
|
toJSON(): T[];
|
|
36
|
-
/**
|
|
36
|
+
/** Remove all items */
|
|
37
37
|
clear(): void;
|
|
38
|
-
/**
|
|
38
|
+
/** Sets collection size */
|
|
39
39
|
protected setSize(size: number): void;
|
|
40
|
-
/**
|
|
40
|
+
/** Increment collection size by amount (default 1) */
|
|
41
41
|
protected incrementSize(amount?: number): void;
|
|
42
|
-
/**
|
|
42
|
+
/** Decrement collection size by amount (default 1) */
|
|
43
43
|
protected decrementSize(amount?: number): void;
|
|
44
44
|
protected emitChange(): void;
|
|
45
45
|
abstract includes(item: T): boolean;
|
|
46
|
-
/**
|
|
46
|
+
/** Add item to collection */
|
|
47
47
|
abstract add(item: T): void;
|
|
48
|
-
/**
|
|
48
|
+
/** Add many items to collection */
|
|
49
49
|
abstract addMany(items: Iterable<T>): void;
|
|
50
|
-
/**
|
|
50
|
+
/** Clone collection */
|
|
51
51
|
abstract clone(): TThis;
|
|
52
|
-
/**
|
|
52
|
+
/** Yields all items from the collection */
|
|
53
53
|
abstract items(): IterableIterator<T>;
|
|
54
|
-
/**
|
|
54
|
+
/** Clear all data - size is set to 0 automatically */
|
|
55
55
|
protected abstract _clear(): void;
|
|
56
56
|
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { BehaviorSubject, distinctUntilChanged, filter, firstValueFrom, map, startWith
|
|
1
|
+
import { BehaviorSubject, Subject, distinctUntilChanged, filter, firstValueFrom, map, startWith } from 'rxjs';
|
|
2
2
|
export class Collection {
|
|
3
3
|
sizeSubject;
|
|
4
4
|
changeSubject;
|
|
5
5
|
clearSubject;
|
|
6
|
-
/**
|
|
6
|
+
/** Emits collection on subscribe and change */
|
|
7
7
|
observe$;
|
|
8
|
-
/**
|
|
8
|
+
/** Emits size of collection */
|
|
9
9
|
size$;
|
|
10
|
-
/**
|
|
10
|
+
/** Emits collection on change */
|
|
11
11
|
change$;
|
|
12
|
-
/*
|
|
12
|
+
/* Emits collection on clear */
|
|
13
13
|
clear$;
|
|
14
|
-
/**
|
|
14
|
+
/** Emits when the collection is empty */
|
|
15
15
|
onEmpty$;
|
|
16
|
-
/**
|
|
16
|
+
/** Emits when the collection has items */
|
|
17
17
|
onItems$;
|
|
18
|
-
/**
|
|
18
|
+
/** Emits whether the collection is empty */
|
|
19
19
|
isEmpty$;
|
|
20
|
-
/**
|
|
20
|
+
/** Emits whether the collection has items */
|
|
21
21
|
hasItems$;
|
|
22
|
-
/**
|
|
22
|
+
/** Resolves when the collection is empty */
|
|
23
23
|
get $onEmpty() {
|
|
24
24
|
return firstValueFrom(this.onEmpty$);
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
26
|
+
/** Resolves when the collection has items */
|
|
27
27
|
get $onItems() {
|
|
28
28
|
return firstValueFrom(this.onItems$);
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
30
|
+
/** Size of collection */
|
|
31
31
|
get size() {
|
|
32
32
|
return this.sizeSubject.value;
|
|
33
33
|
}
|
|
34
|
-
/**
|
|
34
|
+
/** Whether the collection is empty */
|
|
35
35
|
get isEmpty() {
|
|
36
36
|
return this.size == 0;
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
38
|
+
/** Whether the collection has items */
|
|
39
39
|
get hasItems() {
|
|
40
40
|
return this.size > 0;
|
|
41
41
|
}
|
|
@@ -61,24 +61,24 @@ export class Collection {
|
|
|
61
61
|
toJSON() {
|
|
62
62
|
return this.toArray();
|
|
63
63
|
}
|
|
64
|
-
/**
|
|
64
|
+
/** Remove all items */
|
|
65
65
|
clear() {
|
|
66
66
|
this._clear();
|
|
67
67
|
this.clearSubject.next(this);
|
|
68
68
|
this.setSize(0);
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
70
|
+
/** Sets collection size */
|
|
71
71
|
setSize(size) {
|
|
72
72
|
if (size != this.size) {
|
|
73
73
|
this.sizeSubject.next(size);
|
|
74
74
|
this.emitChange();
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
/**
|
|
77
|
+
/** Increment collection size by amount (default 1) */
|
|
78
78
|
incrementSize(amount = 1) {
|
|
79
79
|
this.setSize(this.size + amount);
|
|
80
80
|
}
|
|
81
|
-
/**
|
|
81
|
+
/** Decrement collection size by amount (default 1) */
|
|
82
82
|
decrementSize(amount = 1) {
|
|
83
83
|
this.setSize(this.size - amount);
|
|
84
84
|
}
|
|
@@ -5,7 +5,7 @@ export declare class IterableWeakMap<K extends object, V> extends Collection<[K,
|
|
|
5
5
|
private finalizationRegistry;
|
|
6
6
|
readonly [Symbol.toStringTag] = "IterableWeakMap";
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Provides the real size. This is slow because it requires a cleanup iteration
|
|
9
9
|
*/
|
|
10
10
|
get realSize(): number;
|
|
11
11
|
static get supported(): boolean;
|
|
@@ -17,7 +17,7 @@ export declare class IterableWeakMap<K extends object, V> extends Collection<[K,
|
|
|
17
17
|
addMany(values: Iterable<readonly [K, V]>): void;
|
|
18
18
|
set(key: K, value: V): this;
|
|
19
19
|
delete(key: K): boolean;
|
|
20
|
-
/**
|
|
20
|
+
/** Prune garbage collected entries */
|
|
21
21
|
cleanup(): void;
|
|
22
22
|
clone(): IterableWeakMap<K, V>;
|
|
23
23
|
forEach(callback: (value: V, key: K, map: IterableWeakMap<K, V>) => void, thisArg?: any): void;
|
|
@@ -9,7 +9,7 @@ export class IterableWeakMap extends Collection {
|
|
|
9
9
|
finalizationRegistry;
|
|
10
10
|
[Symbol.toStringTag] = 'IterableWeakMap';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Provides the real size. This is slow because it requires a cleanup iteration
|
|
13
13
|
*/
|
|
14
14
|
get realSize() {
|
|
15
15
|
this.cleanup();
|
|
@@ -79,7 +79,7 @@ export class IterableWeakMap extends Collection {
|
|
|
79
79
|
}
|
|
80
80
|
return deleted;
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
82
|
+
/** Prune garbage collected entries */
|
|
83
83
|
cleanup() {
|
|
84
84
|
drain(this);
|
|
85
85
|
this.updateSize();
|
package/database/query.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Flatten,
|
|
1
|
+
import type { Flatten, Record } from '../types.js';
|
|
2
2
|
import type { Geometry } from '../types/geo-json.js';
|
|
3
3
|
export type QueryOptions<T = any> = {
|
|
4
4
|
sort?: Sort<T>[];
|
|
@@ -10,7 +10,7 @@ export type LogicalQueryTypes = keyof (LogicalAndQuery & LogicalOrQuery & Logica
|
|
|
10
10
|
export declare const allLogicalQueryTypes: LogicalQueryTypes[];
|
|
11
11
|
export type ComparisonQueryBody<T = any> = {
|
|
12
12
|
[P in keyof T]?: ComparisonQueryOrValue<T[P]>;
|
|
13
|
-
} &
|
|
13
|
+
} & Record<ComparisonQueryOrValue>;
|
|
14
14
|
export type ComparisonQueryOrValue<T = any> = ComparisonQuery<T> | T | Flatten<T>;
|
|
15
15
|
export type ComparisonQuery<T = any> = Partial<ComparisonNotQuery<T> & ComparisonEqualsQuery<T> & ComparisonNotEqualsQuery<T> & ComparisonExistsQuery & ComparisonItemQuery<T> & ComparisonInQuery<T> & ComparisonNotInQuery<T> & ComparisonAllQuery<T> & ComparisonGreaterThanQuery<T> & ComparisonGreaterThanOrEqualsQuery<T> & ComparisonLessThanQuery<T> & ComparisonLessThanOrEqualsQuery<T> & ComparisonRegexQuery & ComparisonTextQuery & ComparisonGeoShapeQuery & ComparisonGeoDistanceQuery>;
|
|
16
16
|
export type ComparisonQueryTypes = keyof ComparisonQuery;
|
|
@@ -100,11 +100,11 @@ export type ComparisonGeoDistanceQuery = {
|
|
|
100
100
|
longitude: number;
|
|
101
101
|
latitude: number;
|
|
102
102
|
/**
|
|
103
|
-
*
|
|
103
|
+
* Maximum distance in meters
|
|
104
104
|
*/
|
|
105
105
|
maxDistance?: number;
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
107
|
+
* Minimum distance in meters
|
|
108
108
|
*/
|
|
109
109
|
minDistance?: number;
|
|
110
110
|
};
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import { Signal } from '../../signals/api.js';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
observeTrigger?: Observable<Element>;
|
|
6
|
-
unobserveTrigger?: Observable<Element>;
|
|
7
|
-
};
|
|
8
|
-
export declare function observeIntersection$(elements: Element | Element[], options?: ObserveIntersectionOptions): Observable<IntersectionObserverEntry[]>;
|
|
9
|
-
export declare function observeIntersection(elements: Element | Element[], options?: ObserveIntersectionOptions): Signal<IntersectionObserverEntry[]>;
|
|
1
|
+
import { type Signal } from '../../signals/api.js';
|
|
2
|
+
import { type Observable } from 'rxjs';
|
|
3
|
+
export declare function observeIntersection$(element: Element, options?: IntersectionObserverInit): Observable<IntersectionObserverEntry>;
|
|
4
|
+
export declare function observeIntersection(elements: Element, options?: IntersectionObserverInit): Signal<IntersectionObserverEntry | undefined>;
|
|
@@ -1,31 +1,26 @@
|
|
|
1
|
+
import { IterableWeakMap } from '../../data-structures/iterable-weak-map.js';
|
|
1
2
|
import { toSignal } from '../../signals/api.js';
|
|
2
|
-
import {
|
|
3
|
-
import { isDefined } from '../../utils/type-guards.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
import { FactoryMap } from '../../utils/factory-map.js';
|
|
4
|
+
import { isDefined, isNumber } from '../../utils/type-guards.js';
|
|
5
|
+
import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
|
|
6
|
+
const observerMap = new FactoryMap((root) => new FactoryMap((rootMargin) => new FactoryMap((threshold) => {
|
|
7
|
+
const observer = new IntersectionObserver((entries) => subject.next(entries), { root, rootMargin, threshold });
|
|
8
|
+
const subject = new Subject;
|
|
9
|
+
return ({
|
|
10
|
+
observer,
|
|
11
|
+
subject,
|
|
12
|
+
elementObservables: new FactoryMap((element) => fromEventPattern((handler) => {
|
|
11
13
|
observer.observe(element);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
subscriptions.push(observeTrigger.subscribe({ next: (element) => observer.observe(element) }));
|
|
18
|
-
}
|
|
19
|
-
if (isDefined(unobserveTrigger)) {
|
|
20
|
-
subscriptions.push(unobserveTrigger.subscribe({ next: (element) => observer.unobserve(element) }));
|
|
21
|
-
}
|
|
22
|
-
subscriber.next(observer.takeRecords());
|
|
23
|
-
return () => {
|
|
24
|
-
observer.disconnect();
|
|
25
|
-
subscriptions.forEach((subscription) => subscription.unsubscribe());
|
|
26
|
-
};
|
|
14
|
+
return subject.pipe(map((entries) => entries.find((entry) => entry.target == element)), filter(isDefined)).subscribe((entry) => handler(entry));
|
|
15
|
+
}, (_, subscription) => {
|
|
16
|
+
observer.unobserve(element);
|
|
17
|
+
subscription.unsubscribe();
|
|
18
|
+
}).pipe(shareReplay({ bufferSize: 1, refCount: true })), new IterableWeakMap())
|
|
27
19
|
});
|
|
20
|
+
}, undefined, (threshold) => isNumber(threshold) ? threshold : threshold?.join(','))));
|
|
21
|
+
export function observeIntersection$(element, options) {
|
|
22
|
+
return observerMap.get(options?.root).get(options?.rootMargin).get(options?.threshold).elementObservables.get(element);
|
|
28
23
|
}
|
|
29
24
|
export function observeIntersection(elements, options) {
|
|
30
|
-
return toSignal(observeIntersection$(elements, options)
|
|
25
|
+
return toSignal(observeIntersection$(elements, options));
|
|
31
26
|
}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import { Signal } from '../../signals/api.js';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
unobserveTrigger?: Observable<Element>;
|
|
6
|
-
};
|
|
7
|
-
export declare function observeResize$(elements: Element | (Element | [Element, ResizeObserverOptions])[], options?: ObserveResizeOptions): Observable<ResizeObserverEntry[]>;
|
|
8
|
-
export declare function observeResize(elements: Element | (Element | [Element, ResizeObserverOptions])[], options?: ObserveResizeOptions): Signal<ResizeObserverEntry[]>;
|
|
1
|
+
import { type Signal } from '../../signals/api.js';
|
|
2
|
+
import { type Observable } from 'rxjs';
|
|
3
|
+
export declare function observeResize$(element: Element, options?: ResizeObserverOptions): Observable<ResizeObserverEntry>;
|
|
4
|
+
export declare function observeResize(elements: Element, options?: ResizeObserverOptions): Signal<ResizeObserverEntry | undefined>;
|
|
@@ -1,35 +1,29 @@
|
|
|
1
|
+
import { IterableWeakMap } from '../../data-structures/iterable-weak-map.js';
|
|
1
2
|
import { toSignal } from '../../signals/api.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
import { FactoryMap } from '../../utils/factory-map.js';
|
|
4
|
+
import { isDefined } from '../../utils/type-guards.js';
|
|
5
|
+
import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
|
|
6
|
+
let observer;
|
|
7
|
+
let subject;
|
|
8
|
+
const elementObservablesMap = new FactoryMap(() => ({}), new IterableWeakMap());
|
|
9
|
+
export function observeResize$(element, options) {
|
|
10
|
+
const box = options?.box ?? 'undefined';
|
|
11
|
+
const elementObservables = elementObservablesMap.get(element);
|
|
12
|
+
if (isDefined(elementObservables) && isDefined(elementObservables[box])) {
|
|
13
|
+
return elementObservables[box];
|
|
14
|
+
}
|
|
15
|
+
subject ??= new Subject();
|
|
16
|
+
observer ??= new ResizeObserver((entries) => subject.next(entries));
|
|
17
|
+
const elementResize$ = fromEventPattern((handler) => {
|
|
18
|
+
observer.observe(element, options);
|
|
19
|
+
return subject.pipe(map((entries) => entries.find((entry) => entry.target == element)), filter(isDefined)).subscribe((entry) => handler(entry));
|
|
20
|
+
}, (_, subscription) => {
|
|
21
|
+
observer.unobserve(element);
|
|
22
|
+
subscription.unsubscribe();
|
|
23
|
+
}).pipe(shareReplay({ bufferSize: 1, refCount: true }));
|
|
24
|
+
elementObservables[box] = elementResize$;
|
|
25
|
+
return elementResize$;
|
|
24
26
|
}
|
|
25
27
|
export function observeResize(elements, options) {
|
|
26
|
-
return toSignal(observeResize$(elements, options)
|
|
27
|
-
}
|
|
28
|
-
function observe(observer, element, defaultOptions) {
|
|
29
|
-
if (isArray(element)) {
|
|
30
|
-
observer.observe(element[0], element[1] ?? defaultOptions);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
observer.observe(element, defaultOptions);
|
|
34
|
-
}
|
|
28
|
+
return toSignal(observeResize$(elements, options));
|
|
35
29
|
}
|
|
@@ -11,7 +11,7 @@ import { HttpError, HttpErrorReason } from '../../../http/http.error.js';
|
|
|
11
11
|
import { Singleton, injectArgument, resolveArgumentType } from '../../../injector/index.js';
|
|
12
12
|
import { Injector } from '../../../injector/injector.js';
|
|
13
13
|
import { toArray } from '../../../utils/array/array.js';
|
|
14
|
-
import { isDefined } from '../../../utils/type-guards.js';
|
|
14
|
+
import { isBlob, isDefined, isUint8Array } from '../../../utils/type-guards.js';
|
|
15
15
|
import { HttpClientResponse } from '../http-client-response.js';
|
|
16
16
|
import { HttpClientAdapter } from '../http-client.adapter.js';
|
|
17
17
|
let defaultOptions = {};
|
|
@@ -26,14 +26,15 @@ let UndiciHttpClientAdapter = class UndiciHttpClientAdapter extends HttpClientAd
|
|
|
26
26
|
else if (isDefined(httpClientRequest.body?.text)) {
|
|
27
27
|
body = httpClientRequest.body.text;
|
|
28
28
|
}
|
|
29
|
-
else if (isDefined(httpClientRequest.body?.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
else if (isDefined(httpClientRequest.body?.binary)) {
|
|
30
|
+
if (isBlob(httpClientRequest.body.binary)) {
|
|
31
|
+
body = Readable.from(httpClientRequest.body.binary.stream());
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
body = isUint8Array(httpClientRequest.body.binary)
|
|
35
|
+
? httpClientRequest.body.binary
|
|
36
|
+
: Readable.from(httpClientRequest.body.binary);
|
|
37
|
+
}
|
|
37
38
|
}
|
|
38
39
|
else if (isDefined(httpClientRequest.body?.form)) {
|
|
39
40
|
const params = new URLSearchParams();
|
|
@@ -44,6 +45,9 @@ let UndiciHttpClientAdapter = class UndiciHttpClientAdapter extends HttpClientAd
|
|
|
44
45
|
}
|
|
45
46
|
body = params.toString();
|
|
46
47
|
}
|
|
48
|
+
else if (isDefined(httpClientRequest.body?.formData)) {
|
|
49
|
+
body = httpClientRequest.body.formData;
|
|
50
|
+
}
|
|
47
51
|
try {
|
|
48
52
|
const response = await request(httpClientRequest.url, {
|
|
49
53
|
method: httpClientRequest.method,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CancellationSignal } from '../../cancellation/index.js';
|
|
2
2
|
import { dispose, type Disposable } from '../../disposable/index.js';
|
|
3
|
+
import type { OneOrMany } from '../../schema/index.js';
|
|
3
4
|
import type { Record, TypedOmit, UndefinableJson, UndefinableJsonObject } from '../../types.js';
|
|
4
5
|
import { HttpForm, type HttpFormObject } from '../http-form.js';
|
|
5
6
|
import { HttpHeaders, type HttpHeadersObject } from '../http-headers.js';
|
|
@@ -11,9 +12,8 @@ export type HttpRequestBody = {
|
|
|
11
12
|
text?: string;
|
|
12
13
|
json?: UndefinableJson;
|
|
13
14
|
form?: HttpForm;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
stream?: ReadableStream<Uint8Array>;
|
|
15
|
+
formData?: FormData;
|
|
16
|
+
binary?: Uint8Array | Blob | ReadableStream<Uint8Array>;
|
|
17
17
|
};
|
|
18
18
|
export type HttpRequestAuthorization = {
|
|
19
19
|
basic?: {
|
|
@@ -23,18 +23,17 @@ export type HttpRequestAuthorization = {
|
|
|
23
23
|
bearer?: string;
|
|
24
24
|
token?: string;
|
|
25
25
|
};
|
|
26
|
+
export type HttpFormDataObjectValue = string | number | boolean | Uint8Array | Blob;
|
|
27
|
+
export type HttpFormDataObject = Record<string, OneOrMany<HttpFormDataObjectValue>>;
|
|
26
28
|
export type HttpClientRequestOptions = Partial<TypedOmit<HttpClientRequest, 'url' | 'method' | 'abortSignal' | 'abort' | 'headers' | 'query' | 'body'>> & {
|
|
27
29
|
urlParameter?: HttpUrlParametersObject | HttpUrlParameters;
|
|
28
30
|
headers?: HttpHeadersObject | HttpHeaders;
|
|
29
31
|
query?: HttpQueryObject | HttpQuery;
|
|
30
32
|
credentials?: HttpRequestCredentials;
|
|
31
33
|
authorization?: HttpRequestAuthorization;
|
|
32
|
-
body?: {
|
|
33
|
-
text?: string;
|
|
34
|
-
json?: UndefinableJson;
|
|
34
|
+
body?: TypedOmit<HttpRequestBody, 'form' | 'formData'> & {
|
|
35
35
|
form?: HttpFormObject | HttpForm;
|
|
36
|
-
|
|
37
|
-
stream?: ReadableStream<Uint8Array>;
|
|
36
|
+
formData?: HttpFormDataObject | FormData;
|
|
38
37
|
};
|
|
39
38
|
abortSignal?: CancellationSignal;
|
|
40
39
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CancellationToken } from '../../cancellation/index.js';
|
|
2
2
|
import { dispose } from '../../disposable/index.js';
|
|
3
3
|
import { clone } from '../../utils/clone.js';
|
|
4
|
-
import {
|
|
4
|
+
import { objectEntries } from '../../utils/object/object.js';
|
|
5
|
+
import { isArray, isBlob, isDefined, isString, isUint8Array, isUndefined } from '../../utils/type-guards.js';
|
|
5
6
|
import { HttpForm } from '../http-form.js';
|
|
6
7
|
import { HttpHeaders } from '../http-headers.js';
|
|
7
8
|
import { HttpQuery } from '../http-query.js';
|
|
@@ -149,5 +150,28 @@ function normalizeBody(body) {
|
|
|
149
150
|
if (isDefined(normalizedBody.form)) {
|
|
150
151
|
normalizedBody.form = new HttpForm(normalizedBody.form);
|
|
151
152
|
}
|
|
153
|
+
if (isDefined(normalizedBody.formData) && !(normalizedBody.formData instanceof FormData)) {
|
|
154
|
+
const formData = new FormData();
|
|
155
|
+
for (const [key, value] of objectEntries(normalizedBody.formData)) {
|
|
156
|
+
if (isArray(value)) {
|
|
157
|
+
for (const item of value) {
|
|
158
|
+
formData.append(key, convertFormDataObjectValue(item));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
formData.set(key, convertFormDataObjectValue(value));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
normalizedBody.formData = formData;
|
|
166
|
+
}
|
|
152
167
|
return normalizedBody;
|
|
153
168
|
}
|
|
169
|
+
function convertFormDataObjectValue(value) {
|
|
170
|
+
if (isString(value) || isBlob(value)) {
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
if (isUint8Array(value)) {
|
|
174
|
+
return new Blob([value]);
|
|
175
|
+
}
|
|
176
|
+
return String(value);
|
|
177
|
+
}
|
|
@@ -15,7 +15,7 @@ import { encodeUtf8 } from '../../utils/encoding.js';
|
|
|
15
15
|
import { composeAsyncMiddleware } from '../../utils/middleware.js';
|
|
16
16
|
import { objectEntries } from '../../utils/object/object.js';
|
|
17
17
|
import { readableStreamFromPromise } from '../../utils/stream/readable-stream-from-promise.js';
|
|
18
|
-
import { assertDefined, isArray, isDefined, isObject, isUndefined } from '../../utils/type-guards.js';
|
|
18
|
+
import { assertDefined, isArray, isBlob, isDefined, isObject, isUndefined } from '../../utils/type-guards.js';
|
|
19
19
|
import { buildUrl } from '../../utils/url-builder.js';
|
|
20
20
|
import { HttpHeaders } from '../http-headers.js';
|
|
21
21
|
import { HttpError, HttpErrorReason } from '../http.error.js';
|
|
@@ -217,11 +217,13 @@ function getAddRequestHeadersMiddleware(defaultHeaders) {
|
|
|
217
217
|
else if (isDefined(body.form)) {
|
|
218
218
|
request.headers.contentType = 'application/x-www-form-urlencoded';
|
|
219
219
|
}
|
|
220
|
-
else if (isDefined(body.
|
|
221
|
-
|
|
220
|
+
else if (isDefined(body.formData)) {
|
|
221
|
+
// Form data content type header has to be set by implementation because of boundary value
|
|
222
222
|
}
|
|
223
|
-
else if (isDefined(body.
|
|
224
|
-
request.headers.contentType =
|
|
223
|
+
else if (isDefined(body.binary)) {
|
|
224
|
+
request.headers.contentType = ((isBlob(body.binary) && body.binary.type.length > 0))
|
|
225
|
+
? body.binary.type
|
|
226
|
+
: 'application/octet-stream';
|
|
225
227
|
}
|
|
226
228
|
}
|
|
227
229
|
if (isDefined(authorization) && isUndefined(request.headers.authorization)) {
|
package/orm/entity.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Record, TypedOmit } from '../types.js';
|
|
2
|
+
export declare abstract class EntityMetadata {
|
|
3
|
+
revision: number;
|
|
4
|
+
revisionTimestamp: number;
|
|
5
|
+
createTimestamp: number;
|
|
6
|
+
deleteTimestamp: number | null;
|
|
7
|
+
attributes: Record;
|
|
8
|
+
}
|
|
9
|
+
export declare abstract class Entity {
|
|
10
|
+
id: string;
|
|
11
|
+
metadata: EntityMetadata;
|
|
12
|
+
}
|
|
13
|
+
export type NewEntity<T extends Entity> = TypedOmit<T, 'id' | 'metadata'> & {
|
|
14
|
+
id?: string;
|
|
15
|
+
metadata?: Partial<Pick<EntityMetadata, 'attributes'>>;
|
|
16
|
+
};
|
package/orm/entity.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { NumberProperty, Property, any, record } from '../schema/index.js';
|
|
11
|
+
export class EntityMetadata {
|
|
12
|
+
revision;
|
|
13
|
+
revisionTimestamp;
|
|
14
|
+
createTimestamp;
|
|
15
|
+
deleteTimestamp;
|
|
16
|
+
attributes;
|
|
17
|
+
}
|
|
18
|
+
__decorate([
|
|
19
|
+
Property(),
|
|
20
|
+
__metadata("design:type", Number)
|
|
21
|
+
], EntityMetadata.prototype, "revision", void 0);
|
|
22
|
+
__decorate([
|
|
23
|
+
Property(),
|
|
24
|
+
__metadata("design:type", Number)
|
|
25
|
+
], EntityMetadata.prototype, "revisionTimestamp", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
Property(),
|
|
28
|
+
__metadata("design:type", Number)
|
|
29
|
+
], EntityMetadata.prototype, "createTimestamp", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
NumberProperty({ nullable: true }),
|
|
32
|
+
__metadata("design:type", Object)
|
|
33
|
+
], EntityMetadata.prototype, "deleteTimestamp", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
Property({ schema: record(any(), any()) }),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], EntityMetadata.prototype, "attributes", void 0);
|
|
38
|
+
export class Entity {
|
|
39
|
+
id;
|
|
40
|
+
metadata;
|
|
41
|
+
}
|
|
42
|
+
__decorate([
|
|
43
|
+
Property(),
|
|
44
|
+
__metadata("design:type", String)
|
|
45
|
+
], Entity.prototype, "id", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
Property(EntityMetadata),
|
|
48
|
+
__metadata("design:type", EntityMetadata)
|
|
49
|
+
], Entity.prototype, "metadata", void 0);
|
package/orm/index.d.ts
ADDED
package/orm/index.js
ADDED
package/orm/query.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { Flatten, Record } from '../types.js';
|
|
2
|
+
import type { Geometry } from '../types/geo-json.js';
|
|
3
|
+
export type LogicalQuery<T = any> = LogicalAndQuery<T> | LogicalOrQuery<T> | LogicalNorQuery<T>;
|
|
4
|
+
export type LogicalQueryTypes = keyof (LogicalAndQuery & LogicalOrQuery & LogicalNorQuery);
|
|
5
|
+
export declare const allLogicalQueryTypes: LogicalQueryTypes[];
|
|
6
|
+
export type ComparisonQueryBody<T = any> = {
|
|
7
|
+
[P in keyof T]?: ComparisonQueryOrValue<T[P]>;
|
|
8
|
+
} & Record<ComparisonQueryOrValue>;
|
|
9
|
+
export type ComparisonQueryOrValue<T = any> = ComparisonQuery<T> | T | Flatten<T>;
|
|
10
|
+
export type ComparisonQuery<T = any> = Partial<ComparisonNotQuery<T> & ComparisonEqualsQuery<T> & ComparisonNotEqualsQuery<T> & ComparisonExistsQuery & ComparisonItemQuery<T> & ComparisonInQuery<T> & ComparisonNotInQuery<T> & ComparisonAllQuery<T> & ComparisonGreaterThanQuery<T> & ComparisonGreaterThanOrEqualsQuery<T> & ComparisonLessThanQuery<T> & ComparisonLessThanOrEqualsQuery<T> & ComparisonRegexQuery & ComparisonTextQuery & ComparisonGeoShapeQuery & ComparisonGeoDistanceQuery>;
|
|
11
|
+
export type ComparisonQueryTypes = keyof ComparisonQuery;
|
|
12
|
+
export declare const allComparisonQueryTypes: ComparisonQueryTypes[];
|
|
13
|
+
export type SpecialQuery<T = any> = Partial<TextSpanQuery<T>>;
|
|
14
|
+
export type SpecialQueryTypes = keyof SpecialQuery;
|
|
15
|
+
export declare const allSpecialQueryTypes: SpecialQueryTypes[];
|
|
16
|
+
export type Query<T = any> = LogicalQuery<T> | (ComparisonQueryBody<T> & SpecialQuery<T>);
|
|
17
|
+
export type QueryTypes = LogicalQueryTypes | ComparisonQueryTypes | SpecialQueryTypes;
|
|
18
|
+
export declare const allQueryTypes: ("$and" | "$or" | "$nor" | "$not" | "$eq" | "$neq" | "$exists" | "$item" | "$in" | "$nin" | "$all" | "$gt" | "$gte" | "$lt" | "$lte" | "$regex" | "$text" | "$geoShape" | "$geoDistance" | "$textSpan")[];
|
|
19
|
+
export type Order = 'asc' | 'desc';
|
|
20
|
+
export declare const allOrders: Order[];
|
|
21
|
+
export type Operator = 'and' | 'or';
|
|
22
|
+
export declare const allOperators: Operator[];
|
|
23
|
+
export type LogicalAndQuery<T = any> = {
|
|
24
|
+
$and: Query<T>[];
|
|
25
|
+
};
|
|
26
|
+
export type LogicalOrQuery<T = any> = {
|
|
27
|
+
$or: Query<T>[];
|
|
28
|
+
};
|
|
29
|
+
export type LogicalNorQuery<T = any> = {
|
|
30
|
+
$nor: Query<T>[];
|
|
31
|
+
};
|
|
32
|
+
export type ComparisonValue<T> = T | Flatten<T>;
|
|
33
|
+
export type ComparisonValueWithRegex<T> = T extends string ? ComparisonValue<T | RegExp> : T extends string[] ? ComparisonValue<(Flatten<T> | RegExp)[]> : (T | Flatten<T>);
|
|
34
|
+
export type ComparisonNotQuery<T = any> = {
|
|
35
|
+
$not: ComparisonQuery<T>;
|
|
36
|
+
};
|
|
37
|
+
export type ComparisonEqualsQuery<T = any> = {
|
|
38
|
+
$eq: ComparisonValueWithRegex<T>;
|
|
39
|
+
};
|
|
40
|
+
export type ComparisonNotEqualsQuery<T = any> = {
|
|
41
|
+
$neq: ComparisonValueWithRegex<T>;
|
|
42
|
+
};
|
|
43
|
+
export type ComparisonExistsQuery = {
|
|
44
|
+
$exists: ComparisonValue<boolean>;
|
|
45
|
+
};
|
|
46
|
+
export type ComparisonItemQuery<T = any> = {
|
|
47
|
+
$item: T extends (infer U)[] ? U extends Record<any, any> ? Query<U> : ComparisonQuery<U> : never;
|
|
48
|
+
};
|
|
49
|
+
export type ComparisonInQuery<T = any> = {
|
|
50
|
+
$in: ComparisonValueWithRegex<T>[];
|
|
51
|
+
};
|
|
52
|
+
export type ComparisonNotInQuery<T = any> = {
|
|
53
|
+
$nin: ComparisonValueWithRegex<T>[];
|
|
54
|
+
};
|
|
55
|
+
export type ComparisonAllQuery<T = any> = {
|
|
56
|
+
$all: ComparisonValueWithRegex<T>[];
|
|
57
|
+
};
|
|
58
|
+
export type ComparisonGreaterThanQuery<T = any> = {
|
|
59
|
+
$gt: ComparisonValue<T>;
|
|
60
|
+
};
|
|
61
|
+
export type ComparisonGreaterThanOrEqualsQuery<T = any> = {
|
|
62
|
+
$gte: ComparisonValue<T>;
|
|
63
|
+
};
|
|
64
|
+
export type ComparisonLessThanQuery<T = any> = {
|
|
65
|
+
$lt: ComparisonValue<T>;
|
|
66
|
+
};
|
|
67
|
+
export type ComparisonLessThanOrEqualsQuery<T = any> = {
|
|
68
|
+
$lte: ComparisonValue<T>;
|
|
69
|
+
};
|
|
70
|
+
export type ComparisonRegexQuery = {
|
|
71
|
+
$regex: string | RegExp | {
|
|
72
|
+
pattern: string;
|
|
73
|
+
flags: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export type ComparisonTextQuery = {
|
|
77
|
+
$text: string | {
|
|
78
|
+
text: string;
|
|
79
|
+
operator?: Operator;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export type GeoShapeRelation = 'intersects' | 'within' | 'disjoint' | 'contains';
|
|
83
|
+
export type ComparisonGeoShapeQuery = {
|
|
84
|
+
$geoShape: {
|
|
85
|
+
geometry: Geometry;
|
|
86
|
+
relation: GeoShapeRelation;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
export type ComparisonGeoDistanceQuery = {
|
|
90
|
+
$geoDistance: {
|
|
91
|
+
longitude: number;
|
|
92
|
+
latitude: number;
|
|
93
|
+
/**
|
|
94
|
+
* Maximum distance in meters
|
|
95
|
+
*/
|
|
96
|
+
maxDistance?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Minimum distance in meters
|
|
99
|
+
*/
|
|
100
|
+
minDistance?: number;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
export type TextSpanQueryMode = 'best' | 'most' | 'cross';
|
|
104
|
+
export declare const allTextSpanQueryModes: TextSpanQueryMode[];
|
|
105
|
+
export type TextSpanQuery<T = any> = {
|
|
106
|
+
$textSpan: {
|
|
107
|
+
fields: (Extract<keyof T, string>)[];
|
|
108
|
+
text: string;
|
|
109
|
+
mode?: TextSpanQueryMode;
|
|
110
|
+
operator?: Operator;
|
|
111
|
+
};
|
|
112
|
+
};
|
package/orm/query.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const allLogicalQueryTypes = ['$and', '$or', '$nor'];
|
|
2
|
+
export const allComparisonQueryTypes = ['$all', '$not', '$eq', '$exists', '$gt', '$gte', '$in', '$item', '$lt', '$lte', '$neq', '$nin', '$regex', '$text', '$geoDistance', '$geoShape'];
|
|
3
|
+
export const allSpecialQueryTypes = ['$textSpan'];
|
|
4
|
+
export const allQueryTypes = [...allLogicalQueryTypes, ...allComparisonQueryTypes, ...allSpecialQueryTypes];
|
|
5
|
+
export const allOrders = ['asc', 'desc'];
|
|
6
|
+
export const allOperators = ['and', 'or'];
|
|
7
|
+
export const allTextSpanQueryModes = ['best', 'most', 'cross'];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Paths, Type, TypedOmit } from '../types.js';
|
|
2
|
+
import type { Entity, EntityMetadata, NewEntity } from './entity.js';
|
|
3
|
+
import type { Query } from './query.js';
|
|
4
|
+
export declare const repositoryType: unique symbol;
|
|
5
|
+
export type OrderOptions<T extends Entity> = {
|
|
6
|
+
order?: {
|
|
7
|
+
[P in Paths<T>]?: 1 | -1 | 'asc' | 'desc';
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export type LoadOptions<T extends Entity> = OrderOptions<T> & {
|
|
11
|
+
offset?: number;
|
|
12
|
+
};
|
|
13
|
+
export type LoadManyOptions<T extends Entity> = LoadOptions<T> & {
|
|
14
|
+
limit?: number;
|
|
15
|
+
};
|
|
16
|
+
export type EntityMetadataUpdate = {
|
|
17
|
+
metadata?: Partial<EntityMetadata>;
|
|
18
|
+
};
|
|
19
|
+
export type EntityUpdate<T extends Entity> = Partial<TypedOmit<T, 'metadata'>> & EntityMetadataUpdate;
|
|
20
|
+
export declare abstract class EntityRepository<T extends Entity = Entity> {
|
|
21
|
+
readonly type: Type<T>;
|
|
22
|
+
abstract load(id: string): Promise<T>;
|
|
23
|
+
abstract tryLoad(id: string): Promise<T | undefined>;
|
|
24
|
+
abstract loadByFilter(query: Query<T>, options?: LoadOptions<T>): Promise<T>;
|
|
25
|
+
abstract tryLoadByFilter(query: Query<T>, options?: LoadOptions<T>): Promise<T | undefined>;
|
|
26
|
+
abstract loadMany(ids: string[], options?: LoadManyOptions<T>): Promise<T[]>;
|
|
27
|
+
abstract loadManyCursor(ids: string[], options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
|
|
28
|
+
abstract loadManyByFilter(query: Query<T>, options?: LoadManyOptions<T>): Promise<T[]>;
|
|
29
|
+
abstract loadManyByFilterCursor(query: Query<T>, options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
|
|
30
|
+
abstract loadAll(options?: LoadManyOptions<T>): Promise<T[]>;
|
|
31
|
+
abstract loadAllCursor(options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
|
|
32
|
+
abstract count(): Promise<number>;
|
|
33
|
+
abstract countByFilter(query: Query<T>): Promise<number>;
|
|
34
|
+
abstract has(id: string): Promise<boolean>;
|
|
35
|
+
abstract hasByFilter(query: Query<T>): Promise<boolean>;
|
|
36
|
+
abstract hasMany(ids: string[]): Promise<string[]>;
|
|
37
|
+
abstract hasAll(ids: string[]): Promise<boolean>;
|
|
38
|
+
abstract insert(entity: NewEntity<T>): Promise<T>;
|
|
39
|
+
abstract insertMany(entities: NewEntity<T>[]): Promise<T[]>;
|
|
40
|
+
abstract update(id: string, update: EntityUpdate<T>): Promise<void>;
|
|
41
|
+
abstract updateByFilter(query: Query<T>, update: EntityUpdate<T>): Promise<void>;
|
|
42
|
+
abstract updateMany(ids: string[], update: EntityUpdate<T>): Promise<void>;
|
|
43
|
+
abstract updateManyByFilter(filter: Query<T>, update: EntityUpdate<T>): Promise<void>;
|
|
44
|
+
abstract delete<U extends T>(entity: U): Promise<boolean>;
|
|
45
|
+
abstract deleteMany<U extends T>(entities: U[]): Promise<number>;
|
|
46
|
+
abstract deleteById(id: string): Promise<boolean>;
|
|
47
|
+
abstract deleteManyById(ids: string[]): Promise<number>;
|
|
48
|
+
abstract deleteByFilter<U extends T = T>(query: Query<U>): Promise<boolean>;
|
|
49
|
+
abstract deleteManyByFilter<U extends T = T>(query: Query<U>): Promise<number>;
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.89",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
117
|
"@mxssfd/typedoc-theme": "1.1",
|
|
118
|
-
"@stylistic/eslint-plugin": "2.
|
|
118
|
+
"@stylistic/eslint-plugin": "2.2",
|
|
119
119
|
"@types/chroma-js": "2.4",
|
|
120
120
|
"@types/koa__router": "12.0",
|
|
121
121
|
"@types/luxon": "3.4",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"typescript": "5.4"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
|
-
"@elastic/elasticsearch": "^8.
|
|
137
|
+
"@elastic/elasticsearch": "^8.14",
|
|
138
138
|
"@koa/router": "^12.0",
|
|
139
139
|
"@tstdl/angular": "^0.90",
|
|
140
140
|
"@zxcvbn-ts/core": "^3.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OneOrMany, Record, TypedOmit } from '../../types.js';
|
|
2
2
|
import type { SchemaTestable } from '../schema.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type ObjectSchema } from '../types/index.js';
|
|
4
4
|
export type RecordOptions<T extends Record = Record> = TypedOmit<ObjectSchema<T>, 'properties' | 'unknownProperties' | 'unknownPropertiesKey' | 'mask'>;
|
|
5
5
|
export declare function record<K extends PropertyKey, T>(keySchema: OneOrMany<SchemaTestable<K>>, valueSchema: OneOrMany<SchemaTestable<T>>, options?: RecordOptions): ObjectSchema<Record<K, T>>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { FactoryMap } from '../factory-map.js';
|
|
2
1
|
import { isAsyncIterable } from './is-async-iterable.js';
|
|
3
2
|
export async function groupToMapAsync(iterable, selector) {
|
|
4
3
|
return isAsyncIterable(iterable)
|
|
@@ -6,20 +5,26 @@ export async function groupToMapAsync(iterable, selector) {
|
|
|
6
5
|
: sync(iterable, selector);
|
|
7
6
|
}
|
|
8
7
|
async function async(iterable, selector) {
|
|
9
|
-
const map = new
|
|
8
|
+
const map = new Map();
|
|
10
9
|
let index = 0;
|
|
11
10
|
for await (const item of iterable) {
|
|
12
11
|
const groupKey = await selector(item, index++);
|
|
12
|
+
if (!map.has(groupKey)) {
|
|
13
|
+
map.set(groupKey, []);
|
|
14
|
+
}
|
|
13
15
|
map.get(groupKey).push(item);
|
|
14
16
|
}
|
|
15
|
-
return map
|
|
17
|
+
return map;
|
|
16
18
|
}
|
|
17
19
|
async function sync(iterable, selector) {
|
|
18
|
-
const map = new
|
|
20
|
+
const map = new Map();
|
|
19
21
|
let index = 0;
|
|
20
22
|
for (const item of iterable) {
|
|
21
23
|
const groupKey = await selector(item, index++);
|
|
24
|
+
if (!map.has(groupKey)) {
|
|
25
|
+
map.set(groupKey, []);
|
|
26
|
+
}
|
|
22
27
|
map.get(groupKey).push(item);
|
|
23
28
|
}
|
|
24
|
-
return map
|
|
29
|
+
return map;
|
|
25
30
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { FactoryMap } from '../../factory-map.js';
|
|
2
1
|
import { parallelForEach } from './for-each.js';
|
|
3
2
|
export async function parallelGroup(iterable, concurrency, selector) {
|
|
4
|
-
const map = new
|
|
3
|
+
const map = new Map();
|
|
5
4
|
await parallelForEach(iterable, concurrency, async (item, index) => {
|
|
6
5
|
const groupKey = await selector(item, index);
|
|
6
|
+
if (!map.has(groupKey)) {
|
|
7
|
+
map.set(groupKey, []);
|
|
8
|
+
}
|
|
7
9
|
map.get(groupKey).push(item);
|
|
8
10
|
});
|
|
9
|
-
return map
|
|
11
|
+
return map;
|
|
10
12
|
}
|
package/utils/factory-map.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
export type Factory<Key, Value> = (key: Key) => Value;
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
export type FactoryItemIdentityProvider<K, I> = (key: K) => I;
|
|
3
|
+
/** Same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
|
|
4
|
+
export declare class FactoryMap<K, V, I = K> implements Map<K, V> {
|
|
4
5
|
private readonly factory;
|
|
5
6
|
readonly [Symbol.toStringTag]: 'FactoryMap';
|
|
6
|
-
readonly backingMap: Map<
|
|
7
|
+
readonly backingMap: Map<I, {
|
|
8
|
+
key: K;
|
|
9
|
+
value: V;
|
|
10
|
+
}>;
|
|
11
|
+
readonly identityProvider: FactoryItemIdentityProvider<K, I>;
|
|
7
12
|
get size(): number;
|
|
13
|
+
constructor(factory: Factory<K, V>, backingMap: Map<I, V> | undefined, identityProvider: FactoryItemIdentityProvider<K, I>);
|
|
8
14
|
constructor(factory: Factory<K, V>, backingMap?: Map<K, V>);
|
|
9
15
|
clear(): void;
|
|
10
16
|
has(key: K): boolean;
|
|
@@ -12,7 +18,7 @@ export declare class FactoryMap<K, V> implements Map<K, V> {
|
|
|
12
18
|
getWithoutBuild(key: K): V | undefined;
|
|
13
19
|
set(key: K, value: V): this;
|
|
14
20
|
delete(key: K): boolean;
|
|
15
|
-
forEach(callback: (value: V, key: K, map: FactoryMap<K, V>) => void, thisArg?: any): void;
|
|
21
|
+
forEach(callback: (value: V, key: K, map: FactoryMap<K, V, I>) => void, thisArg?: any): void;
|
|
16
22
|
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
17
23
|
entries(): IterableIterator<[K, V]>;
|
|
18
24
|
keys(): IterableIterator<K>;
|
package/utils/factory-map.js
CHANGED
|
@@ -1,55 +1,66 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
|
|
2
2
|
export class FactoryMap {
|
|
3
3
|
factory;
|
|
4
4
|
[Symbol.toStringTag];
|
|
5
5
|
backingMap;
|
|
6
|
+
identityProvider;
|
|
6
7
|
get size() {
|
|
7
8
|
return this.backingMap.size;
|
|
8
9
|
}
|
|
9
|
-
constructor(factory, backingMap) {
|
|
10
|
+
constructor(factory, backingMap, identityProvider) {
|
|
10
11
|
this.factory = factory;
|
|
11
12
|
this[Symbol.toStringTag] = 'FactoryMap';
|
|
12
13
|
this.backingMap = backingMap ?? new Map();
|
|
14
|
+
this.identityProvider = identityProvider ?? ((key) => key);
|
|
13
15
|
}
|
|
14
16
|
clear() {
|
|
15
17
|
this.backingMap.clear();
|
|
16
18
|
}
|
|
17
19
|
has(key) {
|
|
18
|
-
return this.backingMap.has(key);
|
|
20
|
+
return this.backingMap.has(this.identityProvider(key));
|
|
19
21
|
}
|
|
20
22
|
get(key) {
|
|
21
|
-
const
|
|
23
|
+
const identity = this.identityProvider(key);
|
|
24
|
+
const has = this.backingMap.has(identity);
|
|
22
25
|
if (has) {
|
|
23
|
-
return this.backingMap.get(
|
|
26
|
+
return this.backingMap.get(identity).value;
|
|
24
27
|
}
|
|
25
28
|
const value = this.factory(key);
|
|
26
|
-
this.backingMap.set(key, value);
|
|
29
|
+
this.backingMap.set(identity, { key, value });
|
|
27
30
|
return value;
|
|
28
31
|
}
|
|
29
32
|
getWithoutBuild(key) {
|
|
30
|
-
return this.backingMap.get(key);
|
|
33
|
+
return this.backingMap.get(this.identityProvider(key))?.value;
|
|
31
34
|
}
|
|
32
35
|
set(key, value) {
|
|
33
|
-
this.backingMap.set(key, value);
|
|
36
|
+
this.backingMap.set(this.identityProvider(key), { key, value });
|
|
34
37
|
return this;
|
|
35
38
|
}
|
|
36
39
|
delete(key) {
|
|
37
|
-
return this.backingMap.delete(key);
|
|
40
|
+
return this.backingMap.delete(this.identityProvider(key));
|
|
38
41
|
}
|
|
39
42
|
forEach(callback, thisArg) {
|
|
40
43
|
const boundCallback = callback.bind(thisArg);
|
|
41
|
-
this.backingMap.forEach((
|
|
44
|
+
this.backingMap.forEach(({ key, value }) => boundCallback(value, key, this));
|
|
42
45
|
}
|
|
43
46
|
*[Symbol.iterator]() {
|
|
44
|
-
|
|
47
|
+
for (const [, { key, value }] of this.backingMap) {
|
|
48
|
+
yield [key, value];
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
51
|
*entries() {
|
|
47
|
-
|
|
52
|
+
for (const [, { key, value }] of this.backingMap.entries()) {
|
|
53
|
+
yield [key, value];
|
|
54
|
+
}
|
|
48
55
|
}
|
|
49
56
|
*keys() {
|
|
50
|
-
|
|
57
|
+
for (const [, { key }] of this.backingMap.entries()) {
|
|
58
|
+
yield key;
|
|
59
|
+
}
|
|
51
60
|
}
|
|
52
61
|
*values() {
|
|
53
|
-
|
|
62
|
+
for (const [, { value }] of this.backingMap.entries()) {
|
|
63
|
+
yield value;
|
|
64
|
+
}
|
|
54
65
|
}
|
|
55
66
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { FactoryMap } from '../factory-map.js';
|
|
2
1
|
export function groupToMap(iterable, selector) {
|
|
3
|
-
const map = new
|
|
2
|
+
const map = new Map();
|
|
4
3
|
let index = 0;
|
|
5
4
|
for (const item of iterable) {
|
|
6
5
|
const groupKey = selector(item, index++);
|
|
6
|
+
if (!map.has(groupKey)) {
|
|
7
|
+
map.set(groupKey, []);
|
|
8
|
+
}
|
|
7
9
|
map.get(groupKey).push(item);
|
|
8
10
|
}
|
|
9
|
-
return map
|
|
11
|
+
return map;
|
|
10
12
|
}
|