@rws-framework/db 1.0.1 → 2.0.1

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 CHANGED
@@ -77,12 +77,11 @@ export default User;
77
77
 
78
78
  ***Basic many to one relation***
79
79
  ```typescript
80
- import { RWSannotations, RWSModel } from '@rws-framework/server';
80
+ import { RWSModel, TrackType, Relation } from '@rws-framework/db';
81
81
 
82
82
  import 'reflect-metadata';
83
83
  import User from './User';
84
84
  import IApiKey from './interfaces/IApiKey';
85
- const { RWSTrackType, Relation } = RWSannotations.modelAnnotations;
86
85
 
87
86
  class ApiKey extends RWSModel<ApiKey> implements IApiKey {
88
87
  static _RELATIONS = {
@@ -92,13 +91,13 @@ class ApiKey extends RWSModel<ApiKey> implements IApiKey {
92
91
  @Relation(() => User, true) // second attribute is required = false
93
92
  user: User;
94
93
 
95
- @RWSTrackType(Object)
94
+ @TrackType(Object)
96
95
  keyval: string;
97
96
 
98
- @RWSTrackType(Date, { required: true })
97
+ @TrackType(Date, { required: true })
99
98
  created_at: Date;
100
99
 
101
- @RWSTrackType(Date)
100
+ @TrackType(Date)
102
101
  updated_at: Date;
103
102
 
104
103
  static _collection = 'api_keys';
@@ -121,7 +120,8 @@ export default ApiKey;
121
120
 
122
121
  ```typescript
123
122
  import 'reflect-metadata';
124
- import Model, { OpModelType } from '../_model';
123
+
124
+ import { RWSModel, OpModelType } from '@rws-framework/db';
125
125
 
126
126
  interface IRelationOpts {
127
127
  required?: boolean
@@ -131,7 +131,7 @@ interface IRelationOpts {
131
131
  relatedTo: OpModelType<Model<any>>
132
132
  }
133
133
 
134
- function Relation(theModel: () => OpModelType<Model<any>>, required: boolean = false, relationField: string = null, relatedToField: string = 'id') {
134
+ function Relation(theModel: () => OpModelType<RWSModel<any>>, required: boolean = false, relationField: string = null, relatedToField: string = 'id') {
135
135
  return function(target: any, key: string) {
136
136
  // Store the promise in metadata immediately
137
137
  const metadataPromise = Promise.resolve().then(() => {
@@ -162,15 +162,15 @@ export {IRelationOpts};
162
162
  ***Inverse relation decorator*** (one-to-many)
163
163
  ```typescript
164
164
  import 'reflect-metadata';
165
- import Model, { OpModelType } from '../_model';
165
+ import { RWSModel, OpModelType } from '@rws-framework/db';
166
166
 
167
167
  interface InverseRelationOpts{
168
168
  key: string,
169
- inversionModel: OpModelType<Model<any>>,
169
+ inversionModel: OpModelType<RWSModel<any>>,
170
170
  foreignKey: string
171
171
  }
172
172
 
173
- function InverseRelation(inversionModel: () => OpModelType<Model<any>>, sourceModel: () => OpModelType<Model<any>>, foreignKey: string = null) {
173
+ function InverseRelation(inversionModel: () => OpModelType<RWSModel<any>>, sourceModel: () => OpModelType<RWSModel<any>>, foreignKey: string = null) {
174
174
  return function(target: any, key: string) {
175
175
  // Store the promise in metadata immediately
176
176
  const metadataPromise = Promise.resolve().then(() => {
@@ -201,14 +201,116 @@ export {InverseRelationOpts};
201
201
 
202
202
  ## RWS Model to prisma conversion
203
203
 
204
+ ### Init helper class
205
+
206
+ **This needs to be run either from the package or CLI - it changes models to prisma schema and registers it.**
207
+
208
+ *IDbConfigHandler* - An interface for config bag for DBService
209
+
210
+ ```typescript
211
+ import { OpModelType } from "../models/_model";
212
+
213
+ export interface IDbConfigParams {
214
+ mongo_url?: string;
215
+ mongo_db?: string;
216
+ db_models?: OpModelType<any>[]
217
+ }
218
+
219
+ export interface IDbConfigHandler {
220
+ get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K];
221
+ }
222
+ ```
223
+
224
+ **Helper prisma install example**
225
+
226
+ ```typescript
227
+ class Config implements IDbConfigHandler {
228
+ private data: IDbConfigParams = {
229
+ db_models: [],
230
+ mongo_db: null,
231
+ mongo_url: null
232
+ };
233
+
234
+ private modelsDir: string;
235
+ private cliExecRoot: string;
236
+ private static _instance: Config = null;
237
+
238
+ private constructor(){}
239
+
240
+ static async getInstance(): Promise<Config>
241
+ {
242
+ if(!this._instance){
243
+ this._instance = new Config();
244
+ }
245
+
246
+ await this._instance.fill();
247
+
248
+ return this._instance;
249
+ }
250
+
251
+
252
+ async fill(): Promise<void>
253
+ {
254
+ this.data.mongo_url = args[0];
255
+ this.data.mongo_db = args[1];
256
+
257
+
258
+ this.modelsDir = args[2];
259
+ this.cliExecRoot = args[3];
260
+
261
+ this.data.db_models = (await import('@V/index')).default;
262
+ }
263
+
264
+ getModelsDir(): string
265
+ {
266
+ return this.modelsDir
267
+ }
268
+
269
+ getCliExecRoot(): string
270
+ {
271
+ return this.cliExecRoot
272
+ }
273
+
274
+ get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K] {
275
+ return this.data[key];
276
+ }
277
+ }
278
+
279
+ async function main(): Promise<void>
280
+ {
281
+ console.log('INSTALL PRISMA');
282
+ const cfg = await Config.getInstance();
283
+ DbHelper.installPrisma(cfg, new DBService(cfg), false);
284
+ }
285
+ ```
204
286
 
205
287
  ### Init CLI
206
- Basic CLI command that executes **generateModelSections()** from conversion script is
288
+ Basic CLI command that executes **generateModelSections()** from conversion script is:
289
+
290
+ **rws-db [DB_URL] [DB_NAME] [MODELS_DIRECTORY]**
291
+
292
+ The exec file.
293
+ ```
294
+ /exec/src/console.js
295
+ ```
296
+
297
+ ```bash
298
+ #npm
299
+
300
+ npx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName src/models
301
+ ```
207
302
 
208
303
  ```bash
209
- yarn rws init
304
+ #yarn
305
+
306
+ yarn rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName src/models
210
307
  ```
211
308
 
309
+ ```bash
310
+ #bun
311
+
312
+ bunx rws-db "mongodb://user:pass@localhost:27017/databaseName?authSource=admin&replicaSet=rs0" databaseName src/models
313
+ ```
212
314
 
213
315
  Code for RWS to prisma conversion from "@rws-framework/server" package:
214
316
 
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { rwsShell, rwsPath } = require('@rws-framework/console');
4
+ const chalk = require('chalk');
5
+ const crypto = require('crypto');
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ const params = process.argv.splice(2);
10
+ let paramsString = params.length ? (' ' + params.join(' ')) : '';
11
+
12
+ const appRoot = process.cwd();
13
+ const rwsCliConfigDir = path.resolve(appRoot, 'node_modules', '.rws', 'cli');
14
+ const getCachedPath = (key) => path.resolve(rwsCliConfigDir, key);
15
+
16
+ const currentCwd = path.resolve(__dirname);
17
+
18
+ console.log({params})
19
+
20
+
21
+ const commandString = `npx webpack --config db.rws.webpack.config.js --output-path ./build ${process.cwd()} ${params[2]}`;
22
+ function needsCacheWarming(){
23
+
24
+ if(!fs.existsSync(getCachedPath('paths')) || !fs.existsSync(getCachedPath('checksum'))){
25
+ return true;
26
+ }
27
+
28
+ const fileList = fs.readFileSync(getCachedPath('paths'), 'utf-8').split('\n');
29
+
30
+ if(fileList.length){
31
+ const fileContents = [];
32
+ for(const filePath of fileList){
33
+ if(fs.existsSync(filePath)){
34
+ fileContents.push(fs.readFileSync(filePath, 'utf-8'));
35
+ }
36
+ }
37
+ const finalMD5 = crypto.createHash('md5').update(fileContents.join('\n')).digest('hex');
38
+ const cachedMD5 = fs.readFileSync(getCachedPath('checksum'), 'utf-8');
39
+
40
+ if(finalMD5 === cachedMD5){
41
+ return false;
42
+ }
43
+ }
44
+
45
+ return true;
46
+ }
47
+
48
+ async function main()
49
+ {
50
+ const hasRebuild = paramsString.split(' ').pop().indexOf('--rebuild') > -1;
51
+ const doWarmCache = needsCacheWarming() || hasRebuild;
52
+
53
+ if(!((params[0] || false) && (params[1] || false) && (params[2] || false))){
54
+ throw new Error(`CLI command MUST have 3 parameters: {DB_URL, DB_NAME, MODELS_DIR}`);
55
+ }
56
+
57
+ if(doWarmCache){
58
+ console.log(chalk.yellow('[RWS DB CLI] Building CLI client...'));
59
+
60
+ const cacheTypes = ['paths', 'checksum'];
61
+
62
+ for(const type of cacheTypes){
63
+ if(fs.existsSync(getCachedPath(type))){
64
+ fs.unlinkSync(getCachedPath(type));
65
+ }
66
+ }
67
+
68
+ await tsc();
69
+
70
+ await rwsShell.runCommand(commandString, currentCwd);
71
+
72
+
73
+ }else{
74
+ console.log(chalk.blue('[RWS CLI CACHE] Starting command from built CLI client.'));
75
+ }
76
+
77
+ let startSlice = hasRebuild ? -1 : paramsString.split(' ').length;
78
+ let endSlice = hasRebuild ? -1 : null ;
79
+
80
+ paramsString = [
81
+ ...paramsString.split(' ').slice(0, startSlice),
82
+ currentCwd,
83
+ endSlice ?
84
+ paramsString.split(' ').at(endSlice)
85
+ : null
86
+ ].filter((item) => item !== null).join(' ');
87
+
88
+ await rwsShell.runCommand(`node ${path.join(currentCwd, 'build', 'main.cli.rws.js')}${paramsString}`, process.cwd());
89
+ }
90
+
91
+ async function tsc (){
92
+ const tempConfigContent = {
93
+ "extends": "./tsconfig.json",
94
+ "include": [
95
+ path.join(process.cwd(), params[2], 'index.ts')
96
+ ],
97
+ };
98
+
99
+ const tempConfigPath = path.join(currentCwd, '.tmp.gitignore.json');
100
+ fs.writeFileSync(tempConfigPath, JSON.stringify(tempConfigContent, null, 2));
101
+
102
+
103
+ await rwsShell.runCommand(`tsc -p ${tempConfigPath}`, currentCwd);
104
+ fs.unlinkSync(tempConfigPath);
105
+ }
106
+
107
+ main().then((data) => {
108
+ console.log(chalk.green('[RWS DB CLI] Command complete.'));
109
+ }).catch((e) => {
110
+ console.error(e.message);
111
+ });
@@ -0,0 +1,168 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const webpackFilters = require('./webpackFilters');
4
+ const webpack = require('webpack');
5
+ const { rwsPath } = require('@rws-framework/console');
6
+ // Get CLI arguments
7
+ const args = process.argv.slice(2);
8
+ const fs = require('fs');
9
+ const appRootPath = args[4] || process.cwd();
10
+ const modelsDir = args[5] || '';
11
+
12
+ const internalCwd = process.cwd()
13
+ const rootPackageNodeModules = path.resolve(rwsPath.findRootWorkspacePath(), 'node_modules');
14
+ const thisPackage = path.resolve(__dirname, '..');
15
+ const WEBPACK_PLUGINS = [new webpack.optimize.ModuleConcatenationPlugin()];
16
+
17
+ const modules_setup = [rootPackageNodeModules, appRootPath];
18
+ const isDev = true;
19
+
20
+ function prettyLog(data){
21
+ for(const key of Object.keys(data)){
22
+ const valObject = data[key];
23
+
24
+ console.log(`${chalk.yellow('[Log]')} ${chalk.blue(key)}:`, valObject)
25
+ }
26
+ }
27
+
28
+
29
+
30
+ const mainEntry = './' + path.relative(appRootPath, path.join(internalCwd, '/src/cli.ts'));
31
+ const vPath = path.relative(__dirname, path.join(__dirname, '../build/vendors'));
32
+
33
+ prettyLog({ buildPaths:{
34
+ thisPackage,
35
+ rootPackageNodeModules,
36
+ appRootPath,
37
+ internalCwd,
38
+ vPath
39
+ }});
40
+
41
+ if(!fs.existsSync(path.join(appRootPath, modelsDir, 'index.ts'))){
42
+ console.log(`${chalk.red('[RWS Structure Error] ')} ${chalk.blue(`
43
+ No index.ts in "${path.join(appRootPath, modelsDir)}"\n
44
+ RWS DB requires "index.ts" that has default export with array of your models:\n
45
+
46
+ ${chalk.blue('import')} RWSModel${chalk.blue(',')} OpModelType ${chalk.blue('from')} ${chalk.green('./src/models/user.model.ts')}${chalk.blue(';')}
47
+
48
+ RWSModel<ModelDataInterface> is instance type and
49
+ OpModelType<ModelDataInterface> is type for static methods that navigate through db to populate instanced models.`)}\n
50
+
51
+ Example: \n
52
+
53
+ ${chalk.blue('import')} User ${chalk.blue('from')} ${chalk.green('\'./src/models/user.model.ts\'')}${chalk.blue(';')}
54
+ ${chalk.blue('import')} ApiKey ${chalk.blue('from')} ${chalk.green('\'./src/models/apiKey.model.ts\'')}${chalk.blue(';')}
55
+
56
+ ${chalk.blue('export')} default ${chalk.magenta('[')}
57
+ User${chalk.blue(',')}
58
+ ApiKey
59
+ ${chalk.magenta(']')}${chalk.blue(';')}
60
+ `);
61
+
62
+ throw new Error("Build stopped.")
63
+ }
64
+
65
+ const cfgExport = {
66
+ context: appRootPath,
67
+ entry: mainEntry,
68
+ mode: isDev ? 'development' : 'production',
69
+ target: 'node',
70
+ devtool: isDev ? 'source-map' : false,
71
+ output: {
72
+ path: path.resolve(internalCwd, 'build'), // Resolve output path relative to config directory
73
+ filename: '[name].cli.rws.js',
74
+ sourceMapFilename: '[file].map',
75
+ chunkFilename: "[name].chunk.js",
76
+ libraryTarget: 'commonjs2',
77
+ clean: false
78
+ },
79
+ resolve: {
80
+ extensions: ['.ts', '.js'],
81
+ modules: modules_setup,
82
+ alias: {
83
+ '@V': vPath,
84
+ 'src': path.resolve(appRootPath, 'src'), // Add explicit resolution for src directory
85
+ },
86
+ fallback: {
87
+ "kerberos": false,
88
+ "mongodb-client-encryption": false
89
+ }
90
+ },
91
+ module: {
92
+ rules: [
93
+ {
94
+ test: /\.(ts)$/,
95
+ use: [
96
+ {
97
+ loader: 'ts-loader',
98
+ options: {
99
+ transpileOnly: true,
100
+ configFile: path.resolve(__dirname, 'tsconfig.json'),
101
+ compilerOptions: {
102
+ outDir: path.resolve(internalCwd, 'build'),
103
+ }
104
+ }
105
+ }
106
+ ],
107
+ include: [
108
+ path.resolve(appRootPath),
109
+ path.resolve(thisPackage),
110
+ path.resolve(rootPackageNodeModules, '@rws-framework')
111
+ ],
112
+ exclude: [
113
+ /node_modules\/(?!(@rws-framework)\/).*/,
114
+ /\.d\.ts$/
115
+ ]
116
+ },
117
+ {
118
+ test: /\.node$/,
119
+ use: 'node-loader',
120
+ }
121
+ ],
122
+ },
123
+ plugins: [
124
+ ...WEBPACK_PLUGINS,
125
+ new webpack.DefinePlugin({
126
+ 'process.env.APP_ROOT': JSON.stringify(appRootPath),
127
+ 'process.env.DB_CLI': JSON.stringify(1)
128
+ }),
129
+ new webpack.IgnorePlugin({
130
+ resourceRegExp: /^kerberos$/,
131
+ }),
132
+ new webpack.NormalModuleReplacementPlugin(
133
+ /.*\/build\/Debug\/kerberos\.node$/,
134
+ '@rws-framework/db/src/empty.js'
135
+ )
136
+ ],
137
+ ignoreWarnings: webpackFilters,
138
+ optimization: {
139
+ minimize: false
140
+ },
141
+ experiments: {
142
+ topLevelAwait: true, // Enable top-level await if needed
143
+ }
144
+ // stats: 'verbose'
145
+
146
+ };
147
+
148
+ cfgExport.externals = {
149
+ '@nestjs/common': 'commonjs @nestjs/common',
150
+ '@nestjs/core': 'commonjs @nestjs/core',
151
+ '@nestjs/config': 'commonjs @nestjs/config',
152
+ '@anthropic-ai/sdk': 'commonjs @anthropic-ai/sdk',
153
+ '@zip.js/zip.js': 'commonjs @zip.js/zip.js',
154
+ 'mongodb-client-encryption': 'commonjs mongodb-client-encryption',
155
+ 'uuid': 'commonjs uuid',
156
+ 'source-map-support': 'commonjs source-map-support'
157
+ };
158
+
159
+ cfgExport.plugins.push(
160
+ new webpack.BannerPlugin({
161
+ banner: 'require("source-map-support").install();',
162
+ raw: true
163
+ })
164
+ );
165
+
166
+ // console.log('Final config', cfgExport);
167
+
168
+ module.exports = cfgExport;
@@ -0,0 +1,73 @@
1
+ import 'reflect-metadata';
2
+
3
+ const args: string[] = process.argv.slice(2).filter(cmd => cmd !== '--rebuild');
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { DbHelper, DBService, OpModelType, RWSModel } from '../../src';
7
+ import { IDbConfigHandler, IDbConfigParams } from '../../src/types/DbConfigHandler';
8
+ import chalk from 'chalk';
9
+
10
+ class Config implements IDbConfigHandler {
11
+ private data: IDbConfigParams = {
12
+ db_models: [],
13
+ mongo_db: null,
14
+ mongo_url: null
15
+ };
16
+
17
+ private modelsDir: string;
18
+ private cliExecRoot: string;
19
+ private static _instance: Config = null;
20
+
21
+ private constructor(){}
22
+
23
+ static async getInstance(): Promise<Config>
24
+ {
25
+ if(!this._instance){
26
+ this._instance = new Config();
27
+ }
28
+
29
+ await this._instance.fill();
30
+
31
+ return this._instance;
32
+ }
33
+
34
+
35
+ async fill(): Promise<void>
36
+ {
37
+ this.data.mongo_url = args[0];
38
+ this.data.mongo_db = args[1];
39
+
40
+
41
+ this.modelsDir = args[2];
42
+ this.cliExecRoot = args[3];
43
+
44
+ console.log({args})
45
+
46
+ // this.data.db_models = (await import('@V/index')).default;
47
+ }
48
+
49
+ getModelsDir(): string
50
+ {
51
+ return this.modelsDir
52
+ }
53
+
54
+ getCliExecRoot(): string
55
+ {
56
+ return this.cliExecRoot
57
+ }
58
+
59
+ get<K extends keyof IDbConfigParams>(key: K): IDbConfigParams[K] {
60
+ return this.data[key];
61
+ }
62
+ }
63
+
64
+ async function main(): Promise<void>
65
+ {
66
+ console.log('INSTALL PRISMA');
67
+ const cfg = await Config.getInstance();
68
+ DbHelper.installPrisma(cfg, new DBService(cfg), false);
69
+ }
70
+
71
+ console.log(chalk.bgGreen('[RWS DB CLI] Starting systems...'));
72
+
73
+ main();
@@ -1,8 +1,9 @@
1
1
  {
2
- "compilerOptions": {
3
- "baseUrl": "./",
2
+ "compilerOptions": {
3
+ "baseUrl": "./",
4
4
  "experimentalDecorators": true,
5
5
  "emitDecoratorMetadata": true,
6
+ "emitDeclarationOnly": false,
6
7
  "target": "ES2018",
7
8
  "module": "commonjs",
8
9
  "moduleResolution": "node",
@@ -14,11 +15,18 @@
14
15
  "allowSyntheticDefaultImports": true,
15
16
  "sourceMap": true,
16
17
  "declaration": true,
18
+ "outDir": "build/vendors",
19
+ "preserveWatchOutput": true,
20
+ "allowJs": true,
21
+ "paths": {
22
+ "@V/*": ["./build/vendors/*"]
23
+ }
17
24
  },
18
25
  "include": [
19
- "src"
26
+ "src/cli.ts",
27
+ "../src/*"
20
28
  ],
21
29
  "exclude": [
22
30
  "node_modules"
23
31
  ]
24
- }
32
+ }
@@ -0,0 +1,18 @@
1
+ module.exports = [
2
+ /aws-crt/,
3
+ /express\/lib\/view/,
4
+ /mongodb-client-encryption\/lib\/providers\/gcp/,
5
+ /mongodb/,
6
+ /nest-commander/,
7
+ /snappy/,
8
+ /mongodb-js\/zstd/,
9
+ /puppeteer/,
10
+ /kerberos/,
11
+ /@zip\.js\/zip.js/,
12
+ /Module not found: Error: Can't resolve 'fsevents' in/,
13
+ /Critical dependency: the request of a dependency is an expression/,
14
+ /Module not found: Error: Can't resolve 'aws4'/,
15
+ /Critical dependency: require function is used in a way in which dependencies cannot be statically extracted/,
16
+ /Can't resolve .* in '.*kerberos.*'/,
17
+ /Can't resolve .* in '.*mongodb-client-encryption.*'/
18
+ ];
package/package.json CHANGED
@@ -1,19 +1,30 @@
1
1
  {
2
2
  "name": "@rws-framework/db",
3
3
  "private": false,
4
- "version": "1.0.1",
4
+ "version": "2.0.1",
5
5
  "description": "",
6
6
  "main": "src/index.ts",
7
7
  "scripts": {},
8
8
  "author": "papablack",
9
9
  "license": "ISC",
10
+ "bin": {
11
+ "rws-db": "./exec/console.js"
12
+ },
10
13
  "dependencies": {
11
14
  "@rws-framework/console": "*",
12
15
  "@prisma/client": "^5.1.1",
13
16
  "@mongodb-js/zstd": "^1.2.0",
14
17
  "mongodb": "^6.8.1",
15
18
  "mongodb-client-encryption": "^6.1.1",
16
- "xml2js": "^0.6.2"
19
+ "xml2js": "^0.6.2",
20
+ "crypto": "^1.0.1",
21
+ "source-map-support": "^0.5.21",
22
+ "tsconfig-paths": "^4.2.0",
23
+ "tsconfig-paths-webpack-plugin": "^4.1.0",
24
+ "webpack": "^5.97.1",
25
+ "webpack-cli": "^6.0.1",
26
+ "webpack-bundle-analyzer": "^4.10.2",
27
+ "webpack-node-externals": "^3.0.0"
17
28
  },
18
29
  "devDependencies": {
19
30
  "@types/xml2js": "^0.4.14"
package/src/empty.js ADDED
File without changes
@@ -60,7 +60,7 @@ export class DbHelper {
60
60
 
61
61
  if(fs.existsSync(schemaPath)){
62
62
  fs.unlinkSync(schemaPath);
63
- }
63
+ }
64
64
 
65
65
  fs.writeFileSync(schemaPath, template);
66
66
  process.env.DB_URL = dbUrl;
File without changes
File without changes
File without changes