@node-in-layers/data 1.0.2

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 ADDED
@@ -0,0 +1,343 @@
1
+ # Data - A Node In Layers Package used for handling data and databases.
2
+
3
+ This repository focuses on accessing and manipulating data, especially the ability to easily communicate with different databases. This package provides a high level interface for working with databases via the [functional-models](https://github.com/monolithst/functional-models) framework, particularly the [functional-models-orm](https://github.com/monolithst/functional-models-orm) functional object relational mapper (ORM) framework. It also provides access to the lower level database objects, for optimized direct querying.
4
+
5
+ # How To Install
6
+
7
+ `npm i @node-in-layers/data@latest`
8
+
9
+ ## Supported Databases
10
+
11
+ - dynamo
12
+ - memory
13
+ - mongo
14
+ - mysql
15
+ - opensearch
16
+ - postgres
17
+ - sqlite
18
+
19
+ ## How To Add To a Node In Layers System
20
+
21
+ To use this package you must do the following:
22
+
23
+ 1. Add it to the `apps` property.
24
+ 1. Add a `@node-in-layers/data` section to your configuration file.
25
+
26
+ We recommend that you put the `data` app, as one of the earliest apps, it does not have any requirements, and subsequent packages likely want to use it.
27
+
28
+ #### Example inside a `config.dev.mjs` file:
29
+
30
+ ```javascript
31
+ import { CoreNamespace } from '@node-in-layers/core/index.js'
32
+ import { DataNamespace } from '@node-in-layers/data/index.js'
33
+
34
+ const core = {
35
+ systemName: 'my-system-name',
36
+ environment: 'dev',
37
+ apps: await Promise.all([
38
+ import('@node-in-layers/data/index.js'), // Right here
39
+ import('@node-in-layers/http/index.js'),
40
+ import('./src/my-local-app/index.js'),
41
+ ]),
42
+ layerOrder: ['services', 'features'],
43
+ logLevel: 'debug',
44
+ logFormat: 'json',
45
+ }
46
+
47
+ const data = {
48
+ databases: {
49
+ default: {
50
+ datastoreType: 'mysql',
51
+ },
52
+ },
53
+ }
54
+
55
+ export default () => ({
56
+ [CoreNamespace.root]: core,
57
+ [DataNamespace.root]: data,
58
+ })
59
+ ```
60
+
61
+ ### Multiple Database Support
62
+
63
+ This package has support for configuring multiple databases through the config file. There must be a "default" database, and any other database can be named and configured.
64
+
65
+ In the following example we configure 3 databases. 1 is the default, the 2nd is a database for "caching" and the 3rd is a database that has "legacy data" in it.
66
+
67
+ ```javascript
68
+ import { CoreNamespace } from '@node-in-layers/core/index.js'
69
+ import { DataNamespace } from '@node-in-layers/data/index.js'
70
+
71
+ const core = {
72
+ systemName: 'my-system-name',
73
+ environment: 'dev',
74
+ apps: await Promise.all([
75
+ import('@node-in-layers/data/index.js'), // Right here
76
+ import('@node-in-layers/http/index.js'),
77
+ import('./src/my-local-app/index.js'),
78
+ ]),
79
+ layerOrder: ['services', 'features'],
80
+ logLevel: 'debug',
81
+ logFormat: 'json',
82
+ }
83
+
84
+ const data = {
85
+ databases: {
86
+ default: {
87
+ datastoreType: 'mysql',
88
+ },
89
+ myCacheDb: {
90
+ datastoreType: 'dynamo',
91
+ awsRegion: 'us-east-1',
92
+ },
93
+ myLegacyData: {
94
+ datastoreType: 'sqlite',
95
+ filename: '/data/legacy.sqlite3',
96
+ },
97
+ },
98
+ }
99
+
100
+ export default () => ({
101
+ [CoreNamespace.root]: core,
102
+ [DataNamespace.root]: data,
103
+ })
104
+ ```
105
+
106
+ ## How To Use
107
+
108
+ There are 2 recommended uses of this package.
109
+
110
+ 1. The Model Cruds Interface
111
+ 1. Direct database access
112
+
113
+ ### The Model Cruds Interface
114
+
115
+ The Model Cruds Interface (Create, Retrieve, Update, Delete, Search), is a series of wrappers over the top of the `functional-models-orm` framework, so that seamless integration with models can be used. Instead of having to work with the model instances directly, data can pass in and out of the database without having to know anything about how database interactions work.
116
+
117
+ This interface can quickly wrap models at the service level, feature level and above, making it very easy to create model based REST APIS.
118
+
119
+ #### A Quick Note About Designing a System Using Models
120
+
121
+ It has been our experience that data models can and should be used throughout the system, however, the "orm" part of the models, it is recommended that they only be used at the services layer. The best way to do this, is where you need "non-orm" model use (validation, meta data, etc), we recommend using the ["noop" DatastoreProvider](https://github.com/monolithst/functional-models-orm/blob/master/src/datastore/noop.ts) that is made available with the `functional-models-orm` framework.
122
+
123
+ In many other systems (such as Python's Django), when a developer uses the orm part of the modeling code (save/create/delete/etc), anywhere in the application, it can make it very difficult to optimize and understand bottlenecks of a system.
124
+
125
+ <b>Node In Layers was designed from the beginning to fix this problem, by keeping each 'kind of code' in their appropriate layers. Database accessing code should go in services.</b>
126
+
127
+ Here is how to use the Model Cruds Interface:
128
+
129
+ ```typescript
130
+ import { loadSystem, Config, ServiceContext } from '@node-in-layers/core'
131
+ import { memoizeValue } from '@node-in-layers/core/libs'
132
+ import { DataNamespace, DataServicesLayer } from '@node-in-layers/data'
133
+ import { createSimpleServiceModelWrappers } from '@node-in-layers/data/libs'
134
+ import { OrmModelFactory, ormQueryBuilder } from 'functional-models-orm'
135
+ import { TextProperty, UniqueIdProperty } from 'functional-models'
136
+ import { FeaturesContext } from '@node-in-layers/core/index.js'
137
+
138
+ type MyCustomModel = Readonly<{
139
+ id: string
140
+ name: string
141
+ }>
142
+
143
+ type AnotherModel = Readonly<{
144
+ id: string
145
+ name: string
146
+ }>
147
+
148
+ const createMyModels = ({ Model }: { Model: OrmModelFactory }) => {
149
+ const MyCustomModels = Model<MyCustomModel>('MyCustomModels', {
150
+ properties: {
151
+ id: UniqueIdProperty({ required: true }),
152
+ name: TextProperty({ required: true }),
153
+ },
154
+ })
155
+ const AnotherModels = Model<AnotherModel>('AnotherModels', {
156
+ properties: {
157
+ id: UniqueIdProperty({ required: true }),
158
+ name: TextProperty({ required: true }),
159
+ },
160
+ })
161
+ return {
162
+ MyCustomModels,
163
+ AnotherModels,
164
+ }
165
+ }
166
+
167
+ // Using this in a service.
168
+ const myService = {
169
+ // Add DataServices as part of the context.
170
+ create: (context: ServiceContext<Config, DataServicesLayer>) => {
171
+ const dataContext = context.services[DataNamespace.root]
172
+
173
+ // A helper function so we don't have to get this more than once. We memoize it so its only executed once
174
+ const _getModels = memoizeValue(async () => {
175
+ // 1. Create your database instance/s
176
+ const databases = await dataContext.getDatabases()
177
+
178
+ // 2. Create an orm instance with your dbObjects
179
+ const orm = dataContext.getOrm(databases.default)
180
+
181
+ // 3. Create models
182
+ return createMyModels(orm)
183
+ })
184
+
185
+ // Example: CRUDS as a service - Here is a function makes the models available as service functions.
186
+ const getModelCruds = async () => {
187
+ const models = await _getModels()
188
+ // 4. Create Model Cruds Interface Wrapper.
189
+ const wrappedMyCustomModels = dataContext.modelCrudsService(
190
+ models.MyCustomModels
191
+ )
192
+ return {
193
+ [models.MyCustomModels.getName()]: wrappedMyCustomModels,
194
+ }
195
+
196
+ /* An alternative approach is wrapping all of them automagically */
197
+ return dataContext.modelCrudsServiceWrappers(models)
198
+ }
199
+
200
+ // Example: Using models in a service - Here is another function that uses the models to do a specific kind of search
201
+ const mySpecialSearch = async (value: string) => {
202
+ const models = await _getModels()
203
+ return models.AnotherModels.search(
204
+ ormQueryBuilder().property('name', value).take(1).compile()
205
+ ).then(i => i.instances[0])
206
+ }
207
+
208
+ return {
209
+ getModelCruds,
210
+ mySpecialSearch,
211
+ }
212
+ },
213
+ }
214
+
215
+ // An Example consumer of the model cruds interface.
216
+ const myFeature = {
217
+ create: async (context: FeaturesContext<MyConfig>) => {
218
+ const myComplexFeature = async () => {
219
+ const myService = context.context['myService']
220
+ const modelServices = await myService.getModelServices()
221
+ // Creates and saves.
222
+ const myModel = await modelServices.MyCustomModels.create({
223
+ id: 'my-id',
224
+ name: 'my-custom-name',
225
+ })
226
+
227
+ // Get It back
228
+ const instance = await modelServices.MyCustomModels.retrieve('my-id')
229
+
230
+ // Use another service function that uses models.
231
+ const value = modelServices.mySpecialSearch(instance.name)
232
+
233
+ // Delete it.
234
+ await modelServices.myCustomModels.delete(instance.id)
235
+ return 'OK'
236
+ }
237
+ return {
238
+ myComplexFeature,
239
+ }
240
+ },
241
+ }
242
+ ```
243
+
244
+ ### Direct Database Access
245
+
246
+ All of the objects that provide database access to `functional-models-orm` is made available in the DatabaseObjects object that comes back from `getDatabases()`. These objects (such as `knexClient`, `opensearchClient`, `mongoClient`, etc) provide the ability to do direct queries on the database using the underlying objects.
247
+
248
+ ### Important SQL Notice
249
+
250
+ The underlying libraries needed to make sql databases work are not bundled. In order to make one work (say sqlite), you must include it in your individual systems dependencies or devDependencies.
251
+
252
+ ## Configurations
253
+
254
+ The following contains examples of configurations for each database:
255
+
256
+ ### Dynamo Database
257
+
258
+ ```typescript
259
+ {
260
+ datastoreType: 'dynamo',
261
+ environment: Environment,
262
+ serviceName: PeteServiceName,
263
+ awsRegion: string
264
+ httpsAgentConfig?: {
265
+ keepAlive?: boolean
266
+ maxSockets?: number
267
+ }
268
+ }
269
+ ```
270
+
271
+ ### Memory Database
272
+
273
+ ```typescript
274
+ {
275
+ datastoreType: 'memory',
276
+ }
277
+ ```
278
+
279
+ ### Mongo Database
280
+
281
+ ```typescript
282
+ {
283
+ datastoreType: 'mongo',
284
+ environment: Environment,
285
+ serviceName: PeteServiceName,
286
+ host: string
287
+ port?: number
288
+ username?: string
289
+ password?: string
290
+ }
291
+ ```
292
+
293
+ ### Mysql Database
294
+
295
+ ```typescript
296
+ {
297
+ datastoreType: 'mysql',
298
+ environment: Environment,
299
+ serviceName: PeteServiceName,
300
+ host: string
301
+ port?: number
302
+ username?: string
303
+ password?: string
304
+ }
305
+ ```
306
+
307
+ ### Opensearch Database
308
+
309
+ ```typescript
310
+ {
311
+ datastoreType: 'opensearch',
312
+ environment: Environment,
313
+ serviceName: PeteServiceName,
314
+ username: string
315
+ password: string
316
+ host: string
317
+ }
318
+ ```
319
+
320
+ ### Postgresql Database
321
+
322
+ ```typescript
323
+ {
324
+ datastoreType: 'postgres',
325
+ environment: Environment,
326
+ serviceName: PeteServiceName,
327
+ host: string
328
+ port?: number
329
+ username?: string
330
+ password?: string
331
+ }
332
+ ```
333
+
334
+ ### Sqlite3 Database
335
+
336
+ ```typescript
337
+ {
338
+ datastoreType: 'sqlite',
339
+ environment: Environment,
340
+ serviceName: PeteServiceName,
341
+ filename: string
342
+ }
343
+ ```
package/features.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { Config, FeaturesContext } from '@node-in-layers/core/index.js';
2
+ import { DataServicesLayer, DataFeaturesLayer, DataFeatures } from './types.js';
3
+ declare const create: (context: FeaturesContext<Config, DataServicesLayer, DataFeaturesLayer>) => DataFeatures;
4
+ export { create };
package/features.js ADDED
@@ -0,0 +1,18 @@
1
+ import merge from 'lodash/merge.js';
2
+ const create = (
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ context) => {
5
+ const wrapModelCrudsService = (modelCruds, overrides) => {
6
+ return merge({}, modelCruds, overrides);
7
+ };
8
+ const wrapAllModelCrudsServices = (objs, overrides) => {
9
+ overrides = overrides || {};
10
+ return merge({}, objs, overrides);
11
+ };
12
+ return {
13
+ wrapModelCrudsService,
14
+ wrapAllModelCrudsServices,
15
+ };
16
+ };
17
+ export { create };
18
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../src/features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,iBAAiB,CAAA;AAUnC,MAAM,MAAM,GAAG;AACb,6DAA6D;AAC7D,OAAsE,EACxD,EAAE;IAChB,MAAM,qBAAqB,GAAG,CAC5B,UAAkC,EAClC,SAA0C,EAC1C,EAAE;QACF,OAAO,KAAK,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,CAAC,CAAA;IACzC,CAAC,CAAA;IAED,MAAM,yBAAyB,GAAG,CAChC,IAA8C,EAC9C,SAA6D,EAC7D,EAAE;QACF,SAAS,GAAG,SAAS,IAAI,EAAE,CAAA;QAC3B,OAAO,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;IACnC,CAAC,CAAA;IAED,OAAO;QACL,qBAAqB;QACrB,yBAAyB;KAC1B,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { DataNamespace } from './types.js';
2
+ declare const name = DataNamespace.root;
3
+ export { name };
4
+ export * as features from './features.js';
5
+ export * as types from './types.js';
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { DataNamespace } from './types.js';
2
+ const name = DataNamespace.root;
3
+ export { name };
4
+ export * as features from './features.js';
5
+ export * as types from './types.js';
6
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAA;AAE/B,OAAO,EAAE,IAAI,EAAE,CAAA;AACf,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA"}
package/libs.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Model } from 'functional-models/interfaces.js';
2
+ declare const getSystemInfrastructureName: ({ environment, systemName, component, }: {
3
+ component?: string | undefined;
4
+ environment: string;
5
+ systemName: string;
6
+ }) => string;
7
+ declare const defaultGetTableNameForModel: (environment: string, systemName: string, model: Model<any> | string) => string;
8
+ declare const getMongoCollectionNameForModel: () => (model: any | string) => string;
9
+ export { getMongoCollectionNameForModel, defaultGetTableNameForModel, getSystemInfrastructureName, };
package/libs.js ADDED
@@ -0,0 +1,19 @@
1
+ import kebabCase from 'lodash/kebabCase.js';
2
+ import isString from 'lodash/isString.js';
3
+ const getSystemInfrastructureName = ({ environment, systemName, component, }) => {
4
+ return component
5
+ ? kebabCase(`${systemName}-${component}-${environment}`)
6
+ : kebabCase(`${systemName}-${environment}`);
7
+ };
8
+ const defaultGetTableNameForModel = (environment, systemName, model) => {
9
+ const component = isString(model) ? model : model.getName();
10
+ return getSystemInfrastructureName({ systemName, environment, component });
11
+ };
12
+ const getMongoCollectionNameForModel = () => (model) => {
13
+ if (isString(model)) {
14
+ return kebabCase(model);
15
+ }
16
+ return kebabCase(model.getName());
17
+ };
18
+ export { getMongoCollectionNameForModel, defaultGetTableNameForModel, getSystemInfrastructureName, };
19
+ //# sourceMappingURL=libs.js.map
package/libs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"libs.js","sourceRoot":"","sources":["../src/libs.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,qBAAqB,CAAA;AAC3C,OAAO,QAAQ,MAAM,oBAAoB,CAAA;AAEzC,MAAM,2BAA2B,GAAG,CAAC,EACnC,WAAW,EACX,UAAU,EACV,SAAS,GAKV,EAAE,EAAE;IACH,OAAO,SAAS;QACd,CAAC,CAAC,SAAS,CAAC,GAAG,UAAU,IAAI,SAAS,IAAI,WAAW,EAAE,CAAC;QACxD,CAAC,CAAC,SAAS,CAAC,GAAG,UAAU,IAAI,WAAW,EAAE,CAAC,CAAA;AAC/C,CAAC,CAAA;AAED,MAAM,2BAA2B,GAAG,CAClC,WAAmB,EACnB,UAAkB,EAClB,KAA0B,EAC1B,EAAE;IACF,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;IAC3D,OAAO,2BAA2B,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC,CAAA;AAED,MAAM,8BAA8B,GAAG,GAAG,EAAE,CAAC,CAAC,KAAmB,EAAE,EAAE;IACnE,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;AACnC,CAAC,CAAA;AAED,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,2BAA2B,GAC5B,CAAA"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@node-in-layers/data",
3
+ "type": "module",
4
+ "version": "1.0.2",
5
+ "description": "A Node In Layers package used for handling databases.",
6
+ "main": "index.js",
7
+ "scripts": {
8
+ "build": "rm -Rf ./dist && tsc -p ./tsconfig.json && cp package.json ./dist && cp README.md ./dist",
9
+ "build:watch": "nodemon -e '*' --watch ./src --exec \"npm run build || exit 1\"",
10
+ "commit": "cz",
11
+ "dist": "npm run build && cd dist && npm publish",
12
+ "eslint": "eslint .",
13
+ "feature-tests": "./node_modules/.bin/cucumber-js -p default",
14
+ "prettier": "prettier --write .",
15
+ "test": "export TS_NODE_PROJECT='./tsconfig.test.json' && mocha -r tsx ./test/src/*.test.ts ./test/src/**/*.test.ts ./test/src/**/**/*.test.ts",
16
+ "test:coverage": "nyc --all --reporter cobertura --reporter text --reporter lcov --reporter html npm run test"
17
+ },
18
+ "config": {
19
+ "commitizen": {
20
+ "path": "./node_modules/cz-conventional-changelog"
21
+ }
22
+ },
23
+ "author": "",
24
+ "license": "ISC",
25
+ "devDependencies": {
26
+ "@cucumber/cucumber": "11.0.1",
27
+ "@eslint/compat": "^1.2.0",
28
+ "@eslint/eslintrc": "^3.1.0",
29
+ "@eslint/js": "^9.12.0",
30
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
31
+ "@types/chai-as-promised": "^8.0.1",
32
+ "@types/json-stringify-safe": "^5.0.3",
33
+ "@types/lodash": "^4.17.13",
34
+ "@types/mocha": "^9.1.1",
35
+ "@types/node": "^22.9.0",
36
+ "@types/proxyquire": "^1.3.31",
37
+ "@types/sinon": "^17.0.3",
38
+ "@typescript-eslint/eslint-plugin": "8.13.0",
39
+ "@typescript-eslint/parser": "8.13.0",
40
+ "argparse": "^2.0.1",
41
+ "chai": "^4.2.0",
42
+ "chai-as-promised": "^7.1.1",
43
+ "cz-conventional-changelog": "^3.3.0",
44
+ "eslint": "9.14.0",
45
+ "eslint-config-prettier": "^9.1.0",
46
+ "eslint-import-resolver-typescript": "^3.6.3",
47
+ "eslint-plugin-functional": "~7.1.0",
48
+ "eslint-plugin-import": "^2.31.0",
49
+ "globals": "^15.12.0",
50
+ "handlebars": "^4.7.8",
51
+ "js-yaml": "^4.1.0",
52
+ "mocha": "^11.0.1",
53
+ "nodemon": "^3.1.7",
54
+ "nyc": "^17.1.0",
55
+ "prettier": "^3.3.3",
56
+ "proxyquire": "^2.1.3",
57
+ "sinon": "^19.0.2",
58
+ "sinon-chai": "^3.5.0",
59
+ "source-map-support": "^0.5.21",
60
+ "ts-node": "^10.4.0",
61
+ "tsx": "^4.19.2",
62
+ "typescript": "5.3.3"
63
+ },
64
+ "dependencies": {
65
+ "@aws-sdk/client-dynamodb": "^3.721.0",
66
+ "@aws-sdk/lib-dynamodb": "^3.721.0",
67
+ "@node-in-layers/core": "^1.1.3",
68
+ "@opensearch-project/opensearch": "^2.13.0",
69
+ "functional-models": "^2.1.14",
70
+ "functional-models-orm": "^2.1.13",
71
+ "functional-models-orm-dynamo": "^2.1.7",
72
+ "functional-models-orm-elastic": "^1.0.5",
73
+ "functional-models-orm-mongo": "^2.0.7",
74
+ "functional-models-orm-sql": "^2.1.3",
75
+ "knex": "^3.1.0",
76
+ "lodash": "^4.17.21",
77
+ "modern-async": "^2.0.4",
78
+ "mongodb": "^6.12.0"
79
+ }
80
+ }
package/services.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { ServicesContext } from '@node-in-layers/core/index.js';
2
+ import { DataConfig, DataServices } from './types.js';
3
+ declare const create: (context: ServicesContext<DataConfig>) => DataServices;
4
+ export { create };
package/services.js ADDED
@@ -0,0 +1,251 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import https from 'node:https';
11
+ import { memoizeValue } from '@node-in-layers/core/utils.js';
12
+ import { orm, } from 'functional-models-orm';
13
+ import { asyncMap } from 'modern-async';
14
+ import merge from 'lodash/merge.js';
15
+ import * as dynamo from '@aws-sdk/client-dynamodb';
16
+ import * as libDynamo from '@aws-sdk/lib-dynamodb';
17
+ import { Client as OpenSearchClient } from '@opensearch-project/opensearch';
18
+ import { MongoClient } from 'mongodb';
19
+ import knex from 'knex';
20
+ import curry from 'lodash/curry.js';
21
+ import omit from 'lodash/omit.js';
22
+ import { datastoreProvider as dynamoDatastoreProvider } from 'functional-models-orm-dynamo';
23
+ import { datastoreProvider as opensearchDatastoreProvider } from 'functional-models-orm-elastic';
24
+ import { datastoreProvider as mongoDatastoreProvider } from 'functional-models-orm-mongo';
25
+ import { datastoreProvider as sqlDatastoreProvider } from 'functional-models-orm-sql';
26
+ import * as memoryDatastoreProvider from 'functional-models-orm/datastore/memory.js';
27
+ import { SupportedDatabase, DataNamespace, } from './types.js';
28
+ import { getSystemInfrastructureName, defaultGetTableNameForModel, getMongoCollectionNameForModel, } from './libs.js';
29
+ const DEFAULT_MONGO_PORT = 27017;
30
+ const createMongoConnectionString = ({ host, port, username, password, }) => {
31
+ return `mongodb://${username ? `${username}:${password}@` : ''}${host}:${port || DEFAULT_MONGO_PORT}`;
32
+ };
33
+ const createMongoDatabaseObjects = ({ environment, systemName, host, port, username, password, getTableNameForModel, }) => __awaiter(void 0, void 0, void 0, function* () {
34
+ const database = getSystemInfrastructureName({
35
+ environment,
36
+ systemName,
37
+ });
38
+ const connectionString = createMongoConnectionString({
39
+ host,
40
+ port,
41
+ username,
42
+ password,
43
+ });
44
+ const mongoClient = new MongoClient(connectionString);
45
+ yield mongoClient.connect();
46
+ const datastoreProvider = mongoDatastoreProvider({
47
+ mongoClient,
48
+ databaseName: database,
49
+ getCollectionNameForModel: curry(getTableNameForModel || getMongoCollectionNameForModel)(environment, systemName),
50
+ });
51
+ const cleanup = () => {
52
+ return mongoClient.close();
53
+ };
54
+ return {
55
+ mongoClient,
56
+ datastoreProvider,
57
+ cleanup,
58
+ };
59
+ });
60
+ const createMemoryDatabaseObjects = () => {
61
+ const datastoreProvider = memoryDatastoreProvider.default.default({});
62
+ return {
63
+ cleanup: () => Promise.resolve(),
64
+ datastoreProvider,
65
+ };
66
+ };
67
+ const createOpensearchDatabaseObjects = ({ environment, systemName, username, password, host, getTableNameForModel, }) => {
68
+ const node = `https://${username}:${password}@${host}`;
69
+ const client = new OpenSearchClient({
70
+ node,
71
+ });
72
+ return {
73
+ cleanup: () => Promise.resolve(),
74
+ opensearchClient: client,
75
+ datastoreProvider: opensearchDatastoreProvider.create({
76
+ client,
77
+ getIndexForModel: curry(getTableNameForModel || defaultGetTableNameForModel)(environment, systemName),
78
+ }),
79
+ };
80
+ };
81
+ const createSqlDatabaseObjects = (props) => {
82
+ const needsDatabase = props.datastoreType !== 'sqlite';
83
+ const knexConfig = Object.assign(Object.assign({ client: props.datastoreType }, (needsDatabase
84
+ ? {
85
+ database: getSystemInfrastructureName({
86
+ environment: props.environment,
87
+ systemName: props.systemName,
88
+ }),
89
+ }
90
+ : {})), { connection: Object.assign({}, omit(props, [
91
+ 'datastoreType',
92
+ 'environment',
93
+ 'systemName',
94
+ 'database',
95
+ ])) });
96
+ // @ts-ignore
97
+ const knexClient = knex(knexConfig);
98
+ const datastoreProvider = sqlDatastoreProvider({
99
+ knex: knexClient,
100
+ getTableNameForModel: curry(props.getTableNameForModel || defaultGetTableNameForModel)(props.environment, props.systemName),
101
+ //propertyTypeToParser: sqlParsers.BasicPropertyTypeToParser
102
+ });
103
+ return {
104
+ knexClient,
105
+ cleanup: () => Promise.resolve(),
106
+ datastoreProvider,
107
+ };
108
+ };
109
+ const createDynamoDatabaseObjects = ({ awsRegion, environment, systemName, httpsAgentConfig, getTableNameForModel, }) => {
110
+ const sslAgent = new https.Agent(httpsAgentConfig || {
111
+ keepAlive: true,
112
+ maxSockets: 50,
113
+ });
114
+ const awsConfig = {
115
+ region: awsRegion,
116
+ sslAgent,
117
+ };
118
+ const dynamoDbClient = new dynamo.DynamoDBClient(awsConfig);
119
+ const aws3 = Object.assign(Object.assign({}, dynamo), libDynamo);
120
+ const datastoreProvider = dynamoDatastoreProvider({
121
+ aws3: Object.assign(Object.assign({}, aws3), { dynamoDbClient }),
122
+ getTableNameForModel: curry(getTableNameForModel || defaultGetTableNameForModel)(environment, systemName),
123
+ });
124
+ return {
125
+ dynamoLibs: aws3,
126
+ dynamoDbClient,
127
+ datastoreProvider,
128
+ cleanup: () => Promise.resolve(),
129
+ };
130
+ };
131
+ const _supportedToDatastoreProviderFunc = {
132
+ [SupportedDatabase.memory]: createMemoryDatabaseObjects,
133
+ [SupportedDatabase.dynamo]: createDynamoDatabaseObjects,
134
+ [SupportedDatabase.mongo]: createMongoDatabaseObjects,
135
+ [SupportedDatabase.opensearch]: createOpensearchDatabaseObjects,
136
+ [SupportedDatabase.sqlite]: createSqlDatabaseObjects,
137
+ [SupportedDatabase.mysql]: createSqlDatabaseObjects,
138
+ [SupportedDatabase.postgres]: createSqlDatabaseObjects,
139
+ };
140
+ const createModelCrudsService = (model) => {
141
+ const update = (data) => {
142
+ return model
143
+ .create(data)
144
+ .save()
145
+ .then(instance => {
146
+ if (!instance) {
147
+ throw new Error(`Impossible situation`);
148
+ }
149
+ return instance.toObj();
150
+ });
151
+ };
152
+ const create = update;
153
+ const del = (id) => __awaiter(void 0, void 0, void 0, function* () {
154
+ const instance = yield model.retrieve(id);
155
+ if (!instance) {
156
+ return undefined;
157
+ }
158
+ yield instance.delete();
159
+ return undefined;
160
+ });
161
+ const retrieve = (id) => {
162
+ return model.retrieve(id).then(instance => {
163
+ if (!instance) {
164
+ return undefined;
165
+ }
166
+ return instance.toObj();
167
+ });
168
+ };
169
+ const search = (ormQuery) => {
170
+ return model.search(ormQuery).then((result) => __awaiter(void 0, void 0, void 0, function* () {
171
+ const instances = (yield asyncMap(result.instances, i => i.toObj()));
172
+ return {
173
+ instances,
174
+ page: result.page,
175
+ };
176
+ }));
177
+ };
178
+ return {
179
+ create,
180
+ update,
181
+ delete: del,
182
+ retrieve,
183
+ search,
184
+ };
185
+ };
186
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
187
+ const create = (context) => {
188
+ const databases = context.config['@node-in-layers/data'].databases;
189
+ if (!databases) {
190
+ throw new Error(`Must include "${DataNamespace.root}.databases" inside of a config that uses the "${DataNamespace.root}" namespace`);
191
+ }
192
+ const modelCrudsServices = createModelCrudsService;
193
+ const modelCrudsServiceWrappers = (models) => {
194
+ return merge(models.map(m => {
195
+ return {
196
+ [m.getName()]: createModelCrudsService(m),
197
+ };
198
+ }));
199
+ };
200
+ const getDatabaseObjects = (props) => {
201
+ return Promise.resolve().then(() => {
202
+ const func = _supportedToDatastoreProviderFunc[props.datastoreType];
203
+ if (!func) {
204
+ throw new Error(`Unhandled type ${props.datastoreType}`);
205
+ }
206
+ return func(props);
207
+ });
208
+ };
209
+ const getOrm = (props) => {
210
+ const { Model, fetcher } = orm(props);
211
+ return {
212
+ Model,
213
+ fetcher,
214
+ };
215
+ };
216
+ const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
217
+ const databases = yield getDatabases();
218
+ yield asyncMap(Object.values(databases), d => d.cleanup(), 1);
219
+ });
220
+ const _getDatabases = () => __awaiter(void 0, void 0, void 0, function* () {
221
+ const neededProps = {
222
+ environment: context.config.environment,
223
+ systemName: context.config.systemName,
224
+ };
225
+ const defaultDbProps = merge(databases.default, neededProps);
226
+ const otherProps = omit(databases, 'default') || {};
227
+ const otherProps2 = Object.entries(otherProps).reduce((acc, [x, y]) => {
228
+ return merge(acc, { [x]: merge(y, neededProps) });
229
+ }, {});
230
+ const defaultDb = yield getDatabaseObjects(defaultDbProps);
231
+ const otherDatabases = yield Object.entries(otherProps2).reduce((accP, props) => __awaiter(void 0, void 0, void 0, function* () {
232
+ const acc = yield accP;
233
+ const dbObjects = yield getDatabaseObjects(props[1]);
234
+ return merge(acc, {
235
+ [props[0]]: dbObjects,
236
+ });
237
+ }), Promise.resolve({}));
238
+ return Object.assign({ default: defaultDb }, otherDatabases);
239
+ });
240
+ const getDatabases = () => memoizeValue(_getDatabases)();
241
+ return {
242
+ getDatabaseObjects,
243
+ getOrm,
244
+ getDatabases,
245
+ cleanup,
246
+ modelCrudsServices,
247
+ modelCrudsServiceWrappers,
248
+ };
249
+ };
250
+ export { create };
251
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
package/types.d.ts ADDED
@@ -0,0 +1,167 @@
1
+ import { FunctionalModel, Model, ModelFetcher } from 'functional-models/interfaces.js';
2
+ import { DatastoreProvider, OrmModel, OrmModelFactory, OrmQuery } from 'functional-models-orm';
3
+ import { Config } from '@node-in-layers/core/index.js';
4
+ declare enum DataNamespace {
5
+ root = "@node-in-layers/data"
6
+ }
7
+ declare enum SupportedDatabase {
8
+ memory = "memory",
9
+ dynamo = "dynamo",
10
+ mongo = "mongo",
11
+ opensearch = "opensearch",
12
+ mysql = "mysql",
13
+ postgres = "postgres",
14
+ sqlite = "sqlite"
15
+ }
16
+ type BasicDatabaseProps = Readonly<{
17
+ environment: string;
18
+ systemName: string;
19
+ getTableNameForModel?: (systemName: string, environment: string, model: Model<any>) => string;
20
+ }>;
21
+ type KnexConfigProps = Readonly<{
22
+ username?: string;
23
+ port?: number;
24
+ host?: string;
25
+ password?: string;
26
+ }>;
27
+ type SqliteConfigProps = Readonly<{
28
+ filename: string;
29
+ }>;
30
+ type SqlDatabaseObjectsProps = Readonly<{
31
+ datastoreType: SupportedDatabase.mysql | SupportedDatabase.postgres | SupportedDatabase.sqlite;
32
+ }> & BasicDatabaseProps & (KnexConfigProps | SqliteConfigProps);
33
+ type MongoDatabaseObjectsProps = Readonly<{
34
+ host: string;
35
+ port?: number;
36
+ username?: string;
37
+ password?: string;
38
+ }> & BasicDatabaseProps;
39
+ type OpensearchDatabaseObjectsProps = Readonly<{
40
+ username: string;
41
+ password: string;
42
+ host: string;
43
+ }> & BasicDatabaseProps;
44
+ type DynamoDatabaseObjectsProps = Readonly<{
45
+ awsRegion: string;
46
+ httpsAgentConfig?: {
47
+ keepAlive?: boolean;
48
+ maxSockets?: number;
49
+ };
50
+ }> & BasicDatabaseProps;
51
+ type DatabaseObjectsProps = Readonly<{
52
+ datastoreType: SupportedDatabase;
53
+ }> & BasicDatabaseProps & (DynamoDatabaseObjectsProps | OpensearchDatabaseObjectsProps | MongoDatabaseObjectsProps | SqlDatabaseObjectsProps);
54
+ type SearchResult<T extends FunctionalModel> = Readonly<{
55
+ instances: readonly T[];
56
+ page?: any;
57
+ }>;
58
+ type NonProvidedDatabaseProps = Omit<DatabaseObjectsProps, 'systemName' | 'environment'>;
59
+ type DefaultDatabaseProps = {
60
+ default: NonProvidedDatabaseProps;
61
+ };
62
+ type MultiDatabasesProps = DefaultDatabaseProps & Record<string, NonProvidedDatabaseProps>;
63
+ /**
64
+ * A config that uses databases.
65
+ */
66
+ type DataConfig = Config & {
67
+ [DataNamespace.root]: {
68
+ databases: DefaultDatabaseProps | MultiDatabasesProps;
69
+ };
70
+ };
71
+ /**
72
+ * Represents a set of database related objects. Both highlevel and low level.
73
+ * These objects can be utilized deep inside a services layer, to access data.
74
+ */
75
+ type DatabaseObjects<T extends object = object> = {
76
+ /**
77
+ * This datastoreProvider is used for backing the ORM system.
78
+ */
79
+ datastoreProvider: DatastoreProvider;
80
+ /**
81
+ * A cleanup function that should run at the end of the application, that cleans up database connections.
82
+ */
83
+ cleanup: () => Promise<void>;
84
+ } & T;
85
+ /**
86
+ * An interface for making CRUDS (create/retrieve/update/delete/search) commands into a database.
87
+ */
88
+ type ModelCrudsInterface<T extends FunctionalModel> = Readonly<{
89
+ /**
90
+ * Create either one item, or an array of items in a database
91
+ * @param data
92
+ */
93
+ create: (data: T) => Promise<T>;
94
+ /**
95
+ * Retrieve a single item from the database.
96
+ * @param id
97
+ */
98
+ retrieve: (id: string | number) => Promise<T | undefined>;
99
+ /**
100
+ * Updates a single item in the database
101
+ * @param data
102
+ */
103
+ update: (data: T) => Promise<T>;
104
+ /**
105
+ * Deletes an item from the database
106
+ * @param id
107
+ */
108
+ delete: (id: string | number) => Promise<void>;
109
+ /**
110
+ * Searches the corresponding table for this item.
111
+ * @param ormQuery
112
+ */
113
+ search: (ormQuery: OrmQuery) => Promise<SearchResult<T>>;
114
+ }>;
115
+ /**
116
+ * Data services.
117
+ */
118
+ type DataServices = Readonly<{
119
+ getDatabaseObjects: (props: DatabaseObjectsProps) => Promise<DatabaseObjects> | DatabaseObjects;
120
+ getOrm: (props: {
121
+ datastoreProvider: DatastoreProvider;
122
+ }) => {
123
+ Model: OrmModelFactory;
124
+ fetcher: ModelFetcher;
125
+ };
126
+ /**
127
+ * Gets all databases. This is memoized, so on the first attempt, it will create connections to 1 or more databases
128
+ * and then give you access to those database objects for further use. Very useful in a services layer.
129
+ */
130
+ getDatabases: () => Promise<MultiDatabases>;
131
+ /**
132
+ * Runs cleanup on every database connection. Only run when the application is ending.
133
+ */
134
+ cleanup: () => Promise<void>;
135
+ modelCrudsServices: <T extends FunctionalModel>(model: OrmModel<T>) => ModelCrudsInterface<T>;
136
+ modelCrudsServiceWrappers: (models: OrmModel<any>[]) => Record<string, ModelCrudsInterface<any>>;
137
+ }>;
138
+ /**
139
+ * The services for the Data package.
140
+ */
141
+ type DataServicesLayer = Readonly<{
142
+ [DataNamespace.root]: DataServices;
143
+ }>;
144
+ /**
145
+ * The Features for the Data package.
146
+ */
147
+ type DataFeatures = Readonly<{
148
+ wrapModelCrudsService: <T extends FunctionalModel>(modelCruds: ModelCrudsInterface<T>, overrides: Partial<ModelCrudsInterface<T>>) => ModelCrudsInterface<T>;
149
+ wrapAllModelCrudsServices: (objs: Record<string, ModelCrudsInterface<any>>, overrides?: Record<string, ModelCrudsInterface<any>>) => Record<string, ModelCrudsInterface<any>>;
150
+ }>;
151
+ /**
152
+ * The Features Layer for the Data package.
153
+ */
154
+ type DataFeaturesLayer = Readonly<{
155
+ [DataNamespace.root]: DataFeatures;
156
+ }>;
157
+ /**
158
+ * The default database configured.
159
+ */
160
+ type DefaultDatabase = {
161
+ default: DatabaseObjects;
162
+ };
163
+ /**
164
+ * 1 or more databases configured
165
+ */
166
+ type MultiDatabases = DefaultDatabase & Record<string, DatabaseObjects>;
167
+ export { DataServices, DataFeatures, DataFeaturesLayer, DataNamespace, SupportedDatabase, MongoDatabaseObjectsProps, DatabaseObjectsProps, DynamoDatabaseObjectsProps, BasicDatabaseProps, OpensearchDatabaseObjectsProps, SqlDatabaseObjectsProps, KnexConfigProps, SqliteConfigProps, SearchResult, DatabaseObjects, ModelCrudsInterface, DataConfig, DataServicesLayer, MultiDatabasesProps, MultiDatabases, NonProvidedDatabaseProps, };
package/types.js ADDED
@@ -0,0 +1,16 @@
1
+ var DataNamespace;
2
+ (function (DataNamespace) {
3
+ DataNamespace["root"] = "@node-in-layers/data";
4
+ })(DataNamespace || (DataNamespace = {}));
5
+ var SupportedDatabase;
6
+ (function (SupportedDatabase) {
7
+ SupportedDatabase["memory"] = "memory";
8
+ SupportedDatabase["dynamo"] = "dynamo";
9
+ SupportedDatabase["mongo"] = "mongo";
10
+ SupportedDatabase["opensearch"] = "opensearch";
11
+ SupportedDatabase["mysql"] = "mysql";
12
+ SupportedDatabase["postgres"] = "postgres";
13
+ SupportedDatabase["sqlite"] = "sqlite";
14
+ })(SupportedDatabase || (SupportedDatabase = {}));
15
+ export { DataNamespace, SupportedDatabase, };
16
+ //# sourceMappingURL=types.js.map
package/types.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAaA,IAAK,aAEJ;AAFD,WAAK,aAAa;IAChB,8CAA6B,CAAA;AAC/B,CAAC,EAFI,aAAa,KAAb,aAAa,QAEjB;AAED,IAAK,iBAQJ;AARD,WAAK,iBAAiB;IACpB,sCAAiB,CAAA;IACjB,sCAAiB,CAAA;IACjB,oCAAe,CAAA;IACf,8CAAyB,CAAA;IACzB,oCAAe,CAAA;IACf,0CAAqB,CAAA;IACrB,sCAAiB,CAAA;AACnB,CAAC,EARI,iBAAiB,KAAjB,iBAAiB,QAQrB;AA8MD,OAAO,EAIL,aAAa,EACb,iBAAiB,GAiBlB,CAAA"}