@owlmeans/resource 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +420 -0
  3. package/build/.gitkeep +0 -0
  4. package/build/consts.d.ts +4 -0
  5. package/build/consts.d.ts.map +1 -0
  6. package/build/consts.js +47 -0
  7. package/build/consts.js.map +1 -0
  8. package/build/errors.d.ts +32 -0
  9. package/build/errors.d.ts.map +1 -0
  10. package/build/errors.js +61 -0
  11. package/build/errors.js.map +1 -0
  12. package/build/helper.d.ts +4 -0
  13. package/build/helper.d.ts.map +1 -0
  14. package/build/helper.js +30 -0
  15. package/build/helper.js.map +1 -0
  16. package/build/index.d.ts +6 -0
  17. package/build/index.d.ts.map +1 -0
  18. package/build/index.js +5 -0
  19. package/build/index.js.map +1 -0
  20. package/build/service.d.ts +4 -0
  21. package/build/service.d.ts.map +1 -0
  22. package/build/service.js +67 -0
  23. package/build/service.js.map +1 -0
  24. package/build/types.d.ts +110 -0
  25. package/build/types.d.ts.map +1 -0
  26. package/build/types.js +2 -0
  27. package/build/types.js.map +1 -0
  28. package/build/utils/index.d.ts +2 -0
  29. package/build/utils/index.d.ts.map +1 -0
  30. package/build/utils/index.js +2 -0
  31. package/build/utils/index.js.map +1 -0
  32. package/build/utils/name.d.ts +3 -0
  33. package/build/utils/name.d.ts.map +1 -0
  34. package/build/utils/name.js +20 -0
  35. package/build/utils/name.js.map +1 -0
  36. package/package.json +40 -0
  37. package/src/consts.ts +49 -0
  38. package/src/errors.ts +78 -0
  39. package/src/helper.ts +33 -0
  40. package/src/index.ts +6 -0
  41. package/src/service.ts +93 -0
  42. package/src/types.ts +129 -0
  43. package/src/utils/index.ts +2 -0
  44. package/src/utils/name.ts +27 -0
  45. package/tsconfig.json +14 -0
  46. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAA6B,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAG9E,eAAO,MAAM,eAAe,GAC1B,EAAE,EAAE,MAAM,EAAE,OAAO,SAAS,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,yCAClD,MAAM,YAAY,OAAO,CAAC,OAAO,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,KAAG,OAqFzE,CAAA"}
@@ -0,0 +1,67 @@
1
+ import { assertContext, createLazyService } from '@owlmeans/context';
2
+ import { dbName } from './utils/name.js';
3
+ export const createDbService = (alias, override, init) => {
4
+ const location = `abstract-db-service:${alias}`;
5
+ const cachedAliases = new Set();
6
+ const cachedConfigs = new Map();
7
+ const cachedNames = new Map();
8
+ const service = createLazyService(alias, {
9
+ clients: {},
10
+ ensureConfigAlias: configAlias => {
11
+ let config = typeof configAlias === 'object' ? configAlias : undefined;
12
+ configAlias = typeof configAlias === 'string' ? configAlias : config?.alias ?? service.alias;
13
+ if (cachedAliases.has(configAlias)) {
14
+ return configAlias;
15
+ }
16
+ if (configAlias === service.alias) {
17
+ const context = assertContext(service.ctx, location);
18
+ config = context.cfg.dbs?.find(db => db.alias === service.alias);
19
+ if (config == null) {
20
+ config = context.cfg.dbs?.find(db => db.service === service.alias);
21
+ if (config != null) {
22
+ config.alias = service.alias;
23
+ }
24
+ }
25
+ if (config == null) {
26
+ throw new SyntaxError(`No config for mongo initialization ${configAlias} in ${service.alias}`);
27
+ }
28
+ }
29
+ cachedAliases.add(configAlias);
30
+ return configAlias;
31
+ },
32
+ config: configAlias => {
33
+ const context = assertContext(service.ctx, location);
34
+ configAlias = service.ensureConfigAlias(configAlias);
35
+ const cached = cachedConfigs.get(configAlias);
36
+ if (cached != null) {
37
+ return cached;
38
+ }
39
+ const config = context.cfg.dbs?.find(db => db.alias === configAlias);
40
+ if (config == null) {
41
+ throw new SyntaxError(`No config for mongo initialization ${configAlias} in ${service.alias}`);
42
+ }
43
+ cachedConfigs.set(configAlias, config);
44
+ return config;
45
+ },
46
+ name: configAlias => {
47
+ configAlias = service.ensureConfigAlias(configAlias);
48
+ const chached = cachedNames.get(configAlias);
49
+ if (chached != null) {
50
+ return chached;
51
+ }
52
+ const context = assertContext(service.ctx, location);
53
+ const config = service.config(configAlias);
54
+ const name = dbName(context, service, config);
55
+ cachedNames.set(configAlias, name);
56
+ return name;
57
+ },
58
+ client: async (configAlias) => {
59
+ await service.initialize(configAlias);
60
+ configAlias = service.ensureConfigAlias(configAlias);
61
+ return service.clients[configAlias];
62
+ },
63
+ ...override
64
+ }, init);
65
+ return service;
66
+ };
67
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import type { BasicConfig, BasicContext, BasicResource, LazyService } from '@owlmeans/context';
2
+ export interface Resource<T extends ResourceRecord> extends BasicResource {
3
+ /**
4
+ * @throws {UnknownRecordError}
5
+ */
6
+ get: <Type extends T>(id: string, field?: Getter, opts?: LifecycleOptions) => Promise<Type>;
7
+ load: <Type extends T>(id: string, field?: Getter, opts?: LifecycleOptions) => Promise<Type | null>;
8
+ list: <Type extends T>(criteria?: ListOptions | ListCriteria, opts?: ListOptions) => Promise<ListResult<Type>>;
9
+ save: <Type extends T>(record: Partial<Type>, opts?: Getter) => Promise<Type>;
10
+ /**
11
+ * @throws {RecordExists}
12
+ */
13
+ create: <Type extends T>(record: Partial<Type>, opts?: LifecycleOptions) => Promise<Type>;
14
+ /**
15
+ * @throws {UnknownRecordError}
16
+ */
17
+ update: <Type extends T>(record: Partial<Type>, opts?: Getter) => Promise<Type>;
18
+ delete: <Type extends T>(id: string | T, opts?: Getter) => Promise<Type | null>;
19
+ /**
20
+ * @throws {UnknownRecordError}
21
+ */
22
+ pick: <Type extends T>(id: string | T, opts?: Getter) => Promise<Type>;
23
+ }
24
+ export interface ResourceRecord {
25
+ id?: string;
26
+ }
27
+ type MaybeArray<T> = T | T[];
28
+ export interface ListCriteria extends Record<string, MaybeArray<ListCriteria | number | string | undefined>> {
29
+ }
30
+ export interface ListOptions {
31
+ pager?: ListPager;
32
+ criteria?: ListCriteria;
33
+ }
34
+ export type ListSort = string | [string, boolean?];
35
+ export interface ListPager {
36
+ sort?: ListSort[];
37
+ page?: number;
38
+ size?: number;
39
+ total?: number;
40
+ }
41
+ export interface ListResult<T extends ResourceRecord> {
42
+ items: T[];
43
+ pager?: ListPager;
44
+ }
45
+ type Getter = string | GetterOptions;
46
+ export interface GetterOptions extends LifecycleOptions {
47
+ field?: string;
48
+ }
49
+ export interface LifecycleOptions {
50
+ ttl?: number | Date | string;
51
+ }
52
+ export interface ResourceMaker<R extends ResourceRecord, T extends Resource<R> = Resource<R>> {
53
+ (dbAlias?: string, serviceAlias?: string): T;
54
+ }
55
+ export interface ResourceDbService<Db, Client> extends LazyService {
56
+ clients: Record<string, Client>;
57
+ /**
58
+ * @abstract
59
+ */
60
+ db: (alias?: string) => Promise<Db>;
61
+ /**
62
+ * @final
63
+ */
64
+ config: (alias?: string) => DbConfig;
65
+ /**
66
+ * @abstract
67
+ */
68
+ initialize: (alias?: string) => Promise<void>;
69
+ /**
70
+ * @final
71
+ */
72
+ ensureConfigAlias: (alias?: string | DbConfig) => string;
73
+ /**
74
+ * @final
75
+ */
76
+ name: (alias?: string | DbConfig) => string;
77
+ /**
78
+ * @final
79
+ */
80
+ client: (alias?: string) => Promise<Client>;
81
+ }
82
+ export interface DbLocker<T extends ResourceRecord> {
83
+ lock: (alias: string, record: Partial<T>, fields: string[]) => Promise<T>;
84
+ unlock: (alias: string, record: Partial<T>, fields: string[]) => Promise<T>;
85
+ }
86
+ export interface ResourceLocker<T extends ResourceRecord> {
87
+ lock: (record: Partial<T>, fields?: string[]) => Promise<T>;
88
+ unlock: (record: Partial<T>, fields?: string[]) => Promise<T>;
89
+ }
90
+ export interface DbConfig<P extends {} = {}> {
91
+ service: string;
92
+ alias?: string;
93
+ host: string | string[];
94
+ port?: number;
95
+ user?: string;
96
+ secret?: string;
97
+ schema?: string;
98
+ resourcePrefix?: string;
99
+ entitySensitive?: boolean;
100
+ serviceSensitive?: boolean;
101
+ encryptionKey?: string;
102
+ meta?: P;
103
+ }
104
+ export interface Config extends BasicConfig {
105
+ dbs?: DbConfig[];
106
+ }
107
+ export interface Context<C extends Config = Config> extends BasicContext<C> {
108
+ }
109
+ export {};
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export * from './name.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './name.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { Context, Config, ResourceDbService, DbConfig } from '../types.js';
2
+ export declare const dbName: <C extends Config, T extends Context<C> = Context<C>>(context: T, service: ResourceDbService<any, any>, config: DbConfig) => string;
3
+ //# sourceMappingURL=name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../../src/utils/name.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAA;AAK7E,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,WAAW,iBAAiB,CAAC,GAAG,EAAC,GAAG,CAAC,UAAU,QAAQ,WAU5I,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { Layer } from '@owlmeans/context';
2
+ import { sha256 } from '@noble/hashes/sha256';
3
+ import { hex } from '@scure/base';
4
+ export const dbName = (context, service, config) => {
5
+ let name = config.schema ?? config.alias ?? service.alias;
6
+ if (context.cfg.layerId != null
7
+ && [Layer.Entity, Layer.User].includes(context.cfg.layer)
8
+ && service.layers?.includes(Layer.Entity)) {
9
+ name = format(name, context.cfg.layerId);
10
+ }
11
+ return name;
12
+ };
13
+ const format = (name, suffix) => {
14
+ name = (name + '_' + suffix).replace(/\W/g, '_');
15
+ if (name.length > 64) {
16
+ name = name.substring(0, 31) + '_' + hex.encode(sha256(name.substring(31)));
17
+ }
18
+ return name;
19
+ };
20
+ //# sourceMappingURL=name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name.js","sourceRoot":"","sources":["../../src/utils/name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAGzC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEjC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAsD,OAAU,EAAE,OAAmC,EAAE,MAAgB,EAAE,EAAE;IAC/I,IAAI,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAA;IAEzD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI;WAC1B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;WACtD,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1C,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE;IAC9C,IAAI,GAAG,CAAC,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAEhD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACrB,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@owlmeans/resource",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -b",
7
+ "dev": "sleep 252 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
8
+ "watch": "tsc -b -w --preserveWatchOutput --pretty"
9
+ },
10
+ "main": "build/index.js",
11
+ "module": "build/index.js",
12
+ "types": "build/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./build/index.js",
16
+ "require": "./build/index.js",
17
+ "default": "./build/index.js",
18
+ "module": "./build/index.js",
19
+ "types": "./build/index.d.ts"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@noble/hashes": "^1.5.0",
24
+ "@owlmeans/context": "^0.1.0",
25
+ "@owlmeans/error": "^0.1.0",
26
+ "@scure/base": "^1.1.9"
27
+ },
28
+ "peerDependencies": {
29
+ "ajv": "*"
30
+ },
31
+ "devDependencies": {
32
+ "nodemon": "^3.1.7",
33
+ "npm-check": "^6.0.1",
34
+ "typescript": "^5.6.3"
35
+ },
36
+ "private": false,
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }
package/src/consts.ts ADDED
@@ -0,0 +1,49 @@
1
+ import type { JSONSchemaType } from 'ajv'
2
+ import type { ListResult, ResourceRecord } from './types.js'
3
+
4
+ export const createListSchema = <T extends ResourceRecord>(schema: JSONSchemaType<T>): JSONSchemaType<ListResult<T>> => ({
5
+ type: 'object',
6
+ properties: {
7
+ items: {
8
+ type: 'array',
9
+ items: {
10
+ ...schema,
11
+ type: 'object',
12
+ properties: {
13
+ id: { type: 'string', nullable: true },
14
+ ...schema.properties
15
+ },
16
+ ...(schema.required ? { required: [...schema.required] } : undefined),
17
+ additionalProperties: false,
18
+ }
19
+ },
20
+ pager: {
21
+ type: 'object',
22
+ properties: {
23
+ sort: {
24
+ type: 'array',
25
+ items: {
26
+ oneOf: [
27
+ { type: 'string' },
28
+ {
29
+ type: 'array', items: [
30
+ { type: 'string' },
31
+ { type: 'boolean', nullable: true }
32
+ ], minItems: 1, maxItems: 2
33
+ }
34
+ ]
35
+ },
36
+ nullable: true
37
+ },
38
+ page: { type: 'number', nullable: true },
39
+ size: { type: 'number', nullable: true },
40
+ total: { type: 'number', nullable: true }
41
+ },
42
+ required: [],
43
+ nullable: true,
44
+ additionalProperties: false,
45
+ }
46
+ },
47
+ required: ['items'],
48
+ additionalProperties: false,
49
+ })
package/src/errors.ts ADDED
@@ -0,0 +1,78 @@
1
+
2
+ import { ResilientError } from '@owlmeans/error'
3
+
4
+ export class ResourceError extends ResilientError {
5
+ public static override typeName = 'ResourceError'
6
+
7
+ constructor(message: string = 'error') {
8
+ super(ResourceError.typeName, `resource:${message}`)
9
+ }
10
+ }
11
+
12
+ export class UnknownRecordError extends ResourceError {
13
+ public static override typeName = `${ResourceError.typeName}UnknownRecordError`
14
+
15
+ public static readonly idSeparator: string = '/'
16
+
17
+ constructor(id: string) {
18
+ super(`unknown-record${UnknownRecordError.idSeparator}${id}`)
19
+ this.type = UnknownRecordError.typeName
20
+ }
21
+
22
+ get id(): string {
23
+ return this.message.split(UnknownRecordError.idSeparator)[1]
24
+ }
25
+ }
26
+
27
+ export class MisshapedRecord extends ResourceError {
28
+ public static override typeName = `${ResourceError.typeName}MisshapedRecord`
29
+
30
+ constructor(msg: string) {
31
+ super(`misshaped-record:${msg}`)
32
+ this.type = MisshapedRecord.typeName
33
+ }
34
+ }
35
+
36
+ export class RecordExists extends ResourceError {
37
+ public static override typeName = `${ResourceError.typeName}RecordExists`
38
+
39
+ constructor(msg: string) {
40
+ super(`record-exists:${msg}`)
41
+ this.type = RecordExists.typeName
42
+ }
43
+ }
44
+
45
+ export class RecordUpdateFailed extends ResourceError {
46
+ public static override typeName = `${ResourceError.typeName}RecordUpdateFailed`
47
+
48
+ constructor(msg: string) {
49
+ super(`record-update-failed:${msg}`)
50
+ this.type = RecordUpdateFailed.typeName
51
+ }
52
+ }
53
+
54
+ export class UnsupportedArgumentError extends ResourceError {
55
+ public static override typeName = `${ResourceError.typeName}UnsupportedArgumentError`
56
+
57
+ constructor(argument: string) {
58
+ super(`unsupported-argument:${argument}`)
59
+ this.type = UnsupportedArgumentError.typeName
60
+ }
61
+ }
62
+
63
+ export class UnsupportedMethodError extends ResourceError {
64
+ public static override typeName = `${ResourceError.typeName}UnsupportedMethodError`
65
+
66
+ constructor(method: string) {
67
+ super(`unsupported-method:${method}`)
68
+ this.type = UnsupportedMethodError.typeName
69
+ }
70
+ }
71
+
72
+ ResilientError.registerErrorClass(ResourceError)
73
+ ResilientError.registerErrorClass(UnknownRecordError)
74
+ ResilientError.registerErrorClass(MisshapedRecord)
75
+ ResilientError.registerErrorClass(RecordExists)
76
+ ResilientError.registerErrorClass(RecordUpdateFailed)
77
+ ResilientError.registerErrorClass(UnsupportedArgumentError)
78
+ ResilientError.registerErrorClass(UnsupportedMethodError)
package/src/helper.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { ListCriteria, ListOptions, ListPager } from './types.js'
2
+
3
+ export const prepareListOptions = (defPageSize: number = 10, criteria?: ListOptions | ListCriteria, opts?: ListOptions): ListOptions => {
4
+ if (opts == null) {
5
+ if (criteria == null) {
6
+ criteria = {}
7
+ opts = {}
8
+ } else if ('criteria' in criteria) {
9
+ criteria = criteria.criteria as ListCriteria
10
+ opts = { pager: criteria.pager as ListPager | undefined }
11
+ } else if ('pager' in criteria) {
12
+ opts = { pager: criteria.pager as ListPager | undefined }
13
+ criteria = {}
14
+ }
15
+ }
16
+
17
+ const size = (opts?.pager?.size ?? defPageSize)
18
+ const pager: ListPager = {
19
+ sort: opts?.pager?.sort,
20
+ page: opts?.pager?.page ?? 0,
21
+ size, total: 0
22
+ }
23
+
24
+ return { criteria: criteria as ListCriteria, pager }
25
+ }
26
+
27
+ export const filterObject = <T extends {}>(obj: T, keep?: string[]): T =>
28
+ Object.entries(obj).reduce((obj, [key, value]) => {
29
+ if (value == null && !keep?.includes(key)) {
30
+ return obj
31
+ }
32
+ return { ...obj, [key]: value }
33
+ }, {} as T)
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+
2
+ export * from './errors.js'
3
+ export * from './consts.js'
4
+ export * from './service.js'
5
+ export * from './helper.js'
6
+ export type * from './types.js'
package/src/service.ts ADDED
@@ -0,0 +1,93 @@
1
+ import { assertContext, createLazyService } from '@owlmeans/context'
2
+ import type { InitMethod } from '@owlmeans/context'
3
+ import type { Config, Context, DbConfig, ResourceDbService } from './types.js'
4
+ import { dbName } from './utils/name.js'
5
+
6
+ export const createDbService = <
7
+ Db, Client, Service extends ResourceDbService<Db, Client> = ResourceDbService<Db, Client>
8
+ >(alias: string, override: Partial<Service>, init?: InitMethod<Service>): Service => {
9
+ const location = `abstract-db-service:${alias}`
10
+
11
+ const cachedAliases = new Set<string>()
12
+ const cachedConfigs = new Map<string, DbConfig>()
13
+ const cachedNames = new Map<string, string>()
14
+
15
+ const service: Service = createLazyService<Service>(alias, {
16
+ clients: {},
17
+
18
+ ensureConfigAlias: configAlias => {
19
+ let config: DbConfig | undefined = typeof configAlias === 'object' ? configAlias : undefined
20
+ configAlias = typeof configAlias === 'string' ? configAlias : config?.alias ?? service.alias
21
+
22
+ if (cachedAliases.has(configAlias)) {
23
+ return configAlias
24
+ }
25
+
26
+ if (configAlias === service.alias) {
27
+ const context = assertContext<Config, Context>(service.ctx as Context, location)
28
+ config = context.cfg.dbs?.find(db => db.alias === service.alias)
29
+ if (config == null) {
30
+ config = context.cfg.dbs?.find(db => db.service === service.alias)
31
+ if (config != null) {
32
+ config.alias = service.alias
33
+ }
34
+ }
35
+ if (config == null) {
36
+ throw new SyntaxError(`No config for mongo initialization ${configAlias} in ${service.alias}`)
37
+ }
38
+ }
39
+
40
+ cachedAliases.add(configAlias)
41
+
42
+ return configAlias
43
+ },
44
+
45
+ config: configAlias => {
46
+ const context = assertContext<Config, Context>(service.ctx as Context, location)
47
+ configAlias = service.ensureConfigAlias(configAlias)
48
+
49
+ const cached = cachedConfigs.get(configAlias)
50
+ if (cached != null) {
51
+ return cached
52
+ }
53
+
54
+ const config = context.cfg.dbs?.find(db => db.alias === configAlias)
55
+
56
+ if (config == null) {
57
+ throw new SyntaxError(`No config for mongo initialization ${configAlias} in ${service.alias}`)
58
+ }
59
+
60
+ cachedConfigs.set(configAlias, config)
61
+
62
+ return config
63
+ },
64
+
65
+ name: configAlias => {
66
+ configAlias = service.ensureConfigAlias(configAlias)
67
+ const chached = cachedNames.get(configAlias)
68
+ if (chached != null) {
69
+ return chached
70
+ }
71
+
72
+ const context = assertContext<Config, Context>(service.ctx as Context, location)
73
+ const config = service.config(configAlias)
74
+
75
+ const name = dbName(context, service, config)
76
+
77
+ cachedNames.set(configAlias, name)
78
+
79
+ return name
80
+ },
81
+
82
+ client: async configAlias => {
83
+ await service.initialize(configAlias)
84
+ configAlias = service.ensureConfigAlias(configAlias)
85
+
86
+ return service.clients[configAlias]
87
+ },
88
+
89
+ ...override
90
+ }, init)
91
+
92
+ return service
93
+ }