@reldens/storage 0.53.0 → 0.54.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.
- package/README.md +28 -21
- package/bin/generate-prisma-schema.js +132 -63
- package/bin/reldens-storage.js +106 -51
- package/lib/entities-generator.js +4 -4
- package/lib/prisma/prisma-schema-generator.js +27 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,32 +23,39 @@ It ensures consistent data access methods across different database types and OR
|
|
|
23
23
|
### CLI Tools
|
|
24
24
|
Generate entity files directly from your database structure:
|
|
25
25
|
```bash
|
|
26
|
-
npx reldens-storage generateEntities --user=dbuser --pass=dbpass --database=dbname --driver=objection-js
|
|
26
|
+
npx reldens-storage generateEntities --user=[dbuser] --pass=[dbpass] --database=[dbname] --driver=[objection-js]
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Options:
|
|
30
|
-
- `--user` - Database username
|
|
31
|
-
- `--pass` - Database password
|
|
32
|
-
- `--host` - Database host (default: localhost)
|
|
33
|
-
- `--port` - Database port (default: 3306)
|
|
34
|
-
- `--database` - Database name
|
|
35
|
-
- `--driver` - ORM driver (objection-js|mikro-orm)
|
|
36
|
-
- `--client` - Database client (mysql|mysql2|mongodb)
|
|
37
|
-
- `--path` - Project path for output files
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
- `--user=[username]` - Database username
|
|
31
|
+
- `--pass=[password]` - Database password
|
|
32
|
+
- `--host=[host]` - Database host (default: localhost)
|
|
33
|
+
- `--port=[port]` - Database port (default: 3306)
|
|
34
|
+
- `--database=[name]` - Database name
|
|
35
|
+
- `--driver=[driver]` - ORM driver (objection-js|mikro-orm|prisma)
|
|
36
|
+
- `--client=[client]` - Database client (mysql|mysql2|mongodb)
|
|
37
|
+
- `--path=[path]` - Project path for output files
|
|
38
|
+
- `--override` - Regenerate all files even if they exist
|
|
39
|
+
|
|
40
|
+
Generate Prisma schema:
|
|
40
41
|
```bash
|
|
41
|
-
npx reldens-
|
|
42
|
+
npx reldens-generate-prisma-schema --host=[host] --port=[port] --user=[dbuser] --password=[dbpass] --database=[dbname]
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
Options:
|
|
45
|
-
- `--
|
|
46
|
-
- `--
|
|
47
|
-
- `--
|
|
48
|
-
- `--
|
|
49
|
-
- `--database` - Database name
|
|
50
|
-
- `--client` - Database client (mysql
|
|
51
|
-
- `--
|
|
46
|
+
- `--host=[host]` - Database host (required)
|
|
47
|
+
- `--port=[port]` - Database port (required)
|
|
48
|
+
- `--user=[username]` - Database username (required)
|
|
49
|
+
- `--password=[password]` - Database password (required)
|
|
50
|
+
- `--database=[name]` - Database name (required)
|
|
51
|
+
- `--client=[client]` - Database client (default: mysql)
|
|
52
|
+
- `--debug` - Enable debug mode
|
|
53
|
+
- `--dataProxy` - Enable data proxy
|
|
54
|
+
- `--checkInterval=[ms]` - Check interval in milliseconds (default: 1000)
|
|
55
|
+
- `--maxWaitTime=[ms]` - Max wait time in milliseconds (default: 30000)
|
|
56
|
+
- `--prismaSchemaPath=[path]` - Path to Prisma schema directory
|
|
57
|
+
- `--clientOutputPath=[path]` - Client output path (if not set, uses Prisma default)
|
|
58
|
+
- `--generateBinaryTargets=[targets]` - Comma-separated binary targets (default: native)
|
|
52
59
|
|
|
53
60
|
## Usage Examples
|
|
54
61
|
|
|
@@ -96,7 +103,7 @@ const entities = server.generateEntities();
|
|
|
96
103
|
|
|
97
104
|
First, generate your Prisma schema:
|
|
98
105
|
```bash
|
|
99
|
-
npx reldens-
|
|
106
|
+
npx reldens-generate-prisma-schema --host=localhost --port=3306 --user=dbuser --password=dbpass --database=dbname
|
|
100
107
|
```
|
|
101
108
|
|
|
102
109
|
Then, use the PrismaDataServer in your code:
|
|
@@ -119,7 +126,7 @@ await server.connect();
|
|
|
119
126
|
const entities = server.generateEntities();
|
|
120
127
|
```
|
|
121
128
|
|
|
122
|
-
Note: The PrismaDataServer requires the Prisma schema to be generated first. Make sure to run the `reldens-
|
|
129
|
+
Note: The PrismaDataServer requires the Prisma schema to be generated first. Make sure to run the `reldens-generate-prisma-schema` command before using PrismaDataServer.
|
|
123
130
|
|
|
124
131
|
## Custom Drivers
|
|
125
132
|
|
|
@@ -7,83 +7,152 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { PrismaSchemaGenerator } = require('../lib/prisma/prisma-schema-generator');
|
|
10
|
-
const {
|
|
11
|
-
const { Logger } = require('@reldens/utils');
|
|
10
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
class PrismaSchemaGeneratorCLI
|
|
13
|
+
{
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
host: 'localhost',
|
|
21
|
-
database: '',
|
|
22
|
-
port: 3306
|
|
15
|
+
constructor()
|
|
16
|
+
{
|
|
17
|
+
this.args = process.argv.slice(2);
|
|
18
|
+
this.config = {};
|
|
19
|
+
this.parseArguments();
|
|
23
20
|
}
|
|
24
|
-
};
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
parseArguments()
|
|
23
|
+
{
|
|
24
|
+
for(let i = 0; i < this.args.length; i++){
|
|
25
|
+
let arg = this.args[i];
|
|
26
|
+
if(!arg.startsWith('--')){
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
let equalIndex = arg.indexOf('=');
|
|
30
|
+
if(-1 === equalIndex){
|
|
31
|
+
let flag = arg.substring(2);
|
|
32
|
+
if('debug' === flag || 'dataProxy' === flag || 'help' === flag || 'h' === flag){
|
|
33
|
+
this.config[flag] = true;
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
let key = arg.substring(2, equalIndex);
|
|
38
|
+
let value = arg.substring(equalIndex + 1);
|
|
39
|
+
if('port' === key || 'checkInterval' === key || 'maxWaitTime' === key){
|
|
40
|
+
this.config[key] = parseInt(value);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if('generateBinaryTargets' === key){
|
|
44
|
+
this.config[key] = value.split(',').map(target => target.trim());
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
this.config[key] = value;
|
|
48
|
+
}
|
|
31
49
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if('pass' === key){
|
|
37
|
-
connectionData.config.password = value;
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if('path' === key){
|
|
41
|
-
projectPath = value;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if('user' === key){
|
|
45
|
-
connectionData.config.user = value;
|
|
46
|
-
continue;
|
|
50
|
+
|
|
51
|
+
shouldShowHelp()
|
|
52
|
+
{
|
|
53
|
+
return 0 === this.args.length || sc.get(this.config, 'help', false) || sc.get(this.config, 'h', false);
|
|
47
54
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
|
|
56
|
+
showHelp()
|
|
57
|
+
{
|
|
58
|
+
Logger.info('');
|
|
59
|
+
Logger.info('Reldens Prisma Schema Generator');
|
|
60
|
+
Logger.info('================================');
|
|
61
|
+
Logger.info('');
|
|
62
|
+
Logger.info('Usage: npx reldens-generate-prisma-schema [options]');
|
|
63
|
+
Logger.info('');
|
|
64
|
+
Logger.info('Required Options:');
|
|
65
|
+
Logger.info(' --host=[host] Database host');
|
|
66
|
+
Logger.info(' --port=[port] Database port');
|
|
67
|
+
Logger.info(' --user=[user] Database user');
|
|
68
|
+
Logger.info(' --password=[password] Database password');
|
|
69
|
+
Logger.info(' --database=[database] Database name');
|
|
70
|
+
Logger.info('');
|
|
71
|
+
Logger.info('Optional Options:');
|
|
72
|
+
Logger.info(' --client=[client] Database client (default: mysql)');
|
|
73
|
+
Logger.info(' --debug Enable debug mode (default: false)');
|
|
74
|
+
Logger.info(' --dataProxy Enable data proxy (default: false)');
|
|
75
|
+
Logger.info(' --checkInterval=[ms] Check interval in milliseconds (default: 1000)');
|
|
76
|
+
Logger.info(' --maxWaitTime=[ms] Max wait time in milliseconds (default: 30000)');
|
|
77
|
+
Logger.info(' --prismaSchemaPath=[path] Path to Prisma schema directory');
|
|
78
|
+
Logger.info(' --clientOutputPath=[path] Client output path (if not set, uses Prisma default)');
|
|
79
|
+
Logger.info(' --generateBinaryTargets=[targets] Comma-separated binary targets (default: native)');
|
|
80
|
+
Logger.info('');
|
|
81
|
+
Logger.info('Example:');
|
|
82
|
+
Logger.info(' npx reldens-generate-prisma-schema --host=localhost --port=3306 --user=root --password=secret --database=mydb');
|
|
83
|
+
Logger.info('');
|
|
84
|
+
Logger.info('Advanced Example:');
|
|
85
|
+
Logger.info(' npx reldens-generate-prisma-schema --host=localhost --port=3306 --user=root --password=secret --database=mydb --client=postgresql --debug --dataProxy --checkInterval=2000 --maxWaitTime=60000 --prismaSchemaPath=./custom/prisma --clientOutputPath=./custom/client --generateBinaryTargets=native,debian-openssl-1.1.x');
|
|
86
|
+
Logger.info('');
|
|
51
87
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
|
|
89
|
+
validateRequiredArgs()
|
|
90
|
+
{
|
|
91
|
+
let requiredArgs = ['host', 'port', 'user', 'password', 'database'];
|
|
92
|
+
let missing = [];
|
|
93
|
+
for(let arg of requiredArgs){
|
|
94
|
+
if(!this.config[arg]){
|
|
95
|
+
missing.push(arg);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if(0 < missing.length){
|
|
99
|
+
Logger.error('Missing required arguments: ' + missing.join(', '));
|
|
100
|
+
this.showHelp();
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
55
104
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
105
|
+
|
|
106
|
+
getSchemaConfig()
|
|
107
|
+
{
|
|
108
|
+
return {
|
|
109
|
+
config: {
|
|
110
|
+
host: this.config.host,
|
|
111
|
+
port: this.config.port,
|
|
112
|
+
user: this.config.user,
|
|
113
|
+
password: this.config.password,
|
|
114
|
+
database: this.config.database
|
|
115
|
+
},
|
|
116
|
+
client: sc.get(this.config, 'client', 'mysql'),
|
|
117
|
+
debug: sc.get(this.config, 'debug', false),
|
|
118
|
+
dataProxy: sc.get(this.config, 'dataProxy', false),
|
|
119
|
+
checkInterval: sc.get(this.config, 'checkInterval', 1000),
|
|
120
|
+
maxWaitTime: sc.get(this.config, 'maxWaitTime', 30000),
|
|
121
|
+
prismaSchemaPath: sc.get(this.config, 'prismaSchemaPath'),
|
|
122
|
+
clientOutputPath: sc.get(this.config, 'clientOutputPath'),
|
|
123
|
+
generateBinaryTargets: sc.get(this.config, 'generateBinaryTargets')
|
|
124
|
+
};
|
|
59
125
|
}
|
|
60
|
-
|
|
61
|
-
|
|
126
|
+
|
|
127
|
+
async run()
|
|
128
|
+
{
|
|
129
|
+
if(this.shouldShowHelp()){
|
|
130
|
+
this.showHelp();
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if(!this.validateRequiredArgs()){
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
let schemaConfig = this.getSchemaConfig();
|
|
137
|
+
let generator = new PrismaSchemaGenerator(schemaConfig);
|
|
138
|
+
let success = await generator.generate();
|
|
139
|
+
if(!success){
|
|
140
|
+
Logger.critical('Failed to generate Prisma schema');
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
Logger.info('Prisma schema generation completed successfully');
|
|
144
|
+
return true;
|
|
62
145
|
}
|
|
63
|
-
}
|
|
64
146
|
|
|
65
|
-
if(!connectionData.config.user || !connectionData.config.database){
|
|
66
|
-
Logger.error('Required parameters missing.');
|
|
67
|
-
Logger.error(
|
|
68
|
-
'Usage:',
|
|
69
|
-
'npx reldens-storage generatePrismaSchema --user=[db-username] --pass=[db-password] --host=[db-host] --database=[db-name] --client=[db-client] --path=[project-path]'
|
|
70
|
-
);
|
|
71
|
-
process.exit();
|
|
72
147
|
}
|
|
73
148
|
|
|
74
|
-
let generator = new
|
|
75
|
-
|
|
76
|
-
prismaSchemaPath: FileHandler.joinPaths(projectPath, 'prisma')
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
generator.generate().then((success) => {
|
|
149
|
+
let generator = new PrismaSchemaGeneratorCLI();
|
|
150
|
+
generator.run().then((success) => {
|
|
80
151
|
if(!success){
|
|
81
|
-
|
|
82
|
-
process.exit();
|
|
152
|
+
process.exit(1);
|
|
83
153
|
}
|
|
84
|
-
|
|
85
|
-
process.exit();
|
|
154
|
+
process.exit(0);
|
|
86
155
|
}).catch((error) => {
|
|
87
|
-
Logger.
|
|
88
|
-
process.exit();
|
|
156
|
+
Logger.critical('Unexpected error: ' + error.message);
|
|
157
|
+
process.exit(1);
|
|
89
158
|
});
|
package/bin/reldens-storage.js
CHANGED
|
@@ -7,69 +7,124 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { EntitiesGenerator } = require('../lib/entities-generator');
|
|
10
|
-
const { Logger } = require('@reldens/utils');
|
|
10
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
class StorageEntitiesGenerator
|
|
13
|
+
{
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
user: '',
|
|
24
|
-
password: '',
|
|
25
|
-
host: 'localhost',
|
|
26
|
-
database: '',
|
|
27
|
-
port: 3306
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
let projectPath = process.cwd();
|
|
31
|
-
for(let i = 1; i < args.length; i++){
|
|
32
|
-
let arg = args[i];
|
|
33
|
-
if(!arg.startsWith('--')){
|
|
34
|
-
continue;
|
|
15
|
+
constructor()
|
|
16
|
+
{
|
|
17
|
+
this.args = process.argv.slice(2);
|
|
18
|
+
this.command = this.args[0];
|
|
19
|
+
this.config = {};
|
|
20
|
+
this.projectPath = process.cwd();
|
|
21
|
+
this.isOverride = false;
|
|
22
|
+
this.parseArguments();
|
|
35
23
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
|
|
25
|
+
parseArguments()
|
|
26
|
+
{
|
|
27
|
+
for(let i = 1; i < this.args.length; i++){
|
|
28
|
+
let arg = this.args[i];
|
|
29
|
+
if(!arg.startsWith('--')){
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
let equalIndex = arg.indexOf('=');
|
|
33
|
+
if(-1 === equalIndex){
|
|
34
|
+
let flag = arg.substring(2);
|
|
35
|
+
if('override' === flag){
|
|
36
|
+
this.isOverride = true;
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let key = arg.substring(2, equalIndex);
|
|
41
|
+
let value = arg.substring(equalIndex + 1);
|
|
42
|
+
if('path' === key){
|
|
43
|
+
this.projectPath = value;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if('pass' === key){
|
|
47
|
+
this.config['password'] = value;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if('port' === key){
|
|
51
|
+
this.config[key] = parseInt(value);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
this.config[key] = value;
|
|
55
|
+
}
|
|
39
56
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
|
|
58
|
+
getConnectionData()
|
|
59
|
+
{
|
|
60
|
+
let connectionData = {
|
|
61
|
+
driver: sc.get(this.config, 'driver', 'objection-js'),
|
|
62
|
+
client: sc.get(this.config, 'client', 'mysql2'),
|
|
63
|
+
user: sc.get(this.config, 'user', ''),
|
|
64
|
+
password: sc.get(this.config, 'password', ''),
|
|
65
|
+
host: sc.get(this.config, 'host', 'localhost'),
|
|
66
|
+
database: sc.get(this.config, 'database', ''),
|
|
67
|
+
port: sc.get(this.config, 'port', 3306)
|
|
68
|
+
};
|
|
69
|
+
if('mikro-orm' === connectionData.driver && !this.config.client){
|
|
70
|
+
connectionData.client = 'mysql';
|
|
71
|
+
}
|
|
72
|
+
return connectionData;
|
|
43
73
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
74
|
+
|
|
75
|
+
validateCommand()
|
|
76
|
+
{
|
|
77
|
+
if('generateEntities' !== this.command){
|
|
78
|
+
Logger.error('Unknown command. Available command "generateEntities".');
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
47
82
|
}
|
|
48
|
-
connectionData[key] = value;
|
|
49
|
-
}
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
84
|
+
validateRequiredArgs(connectionData)
|
|
85
|
+
{
|
|
86
|
+
if(!connectionData.user || !connectionData.database){
|
|
87
|
+
Logger.error('Required parameters missing.');
|
|
88
|
+
Logger.error('Usage: npx reldens-storage generateEntities --user=[db-username] --pass=[db-password] --host=[db-host] --database=[db-name] --driver=[driver-map-key] --client=[db-client] --path=[project-path] --override');
|
|
89
|
+
Logger.error('');
|
|
90
|
+
Logger.error('Optional flags:');
|
|
91
|
+
Logger.error(' --override Regenerate all files even if they exist');
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
54
96
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
97
|
+
async run()
|
|
98
|
+
{
|
|
99
|
+
if(!this.validateCommand()){
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
let connectionData = this.getConnectionData();
|
|
103
|
+
if(!this.validateRequiredArgs(connectionData)){
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
let generator = new EntitiesGenerator({
|
|
107
|
+
connectionData,
|
|
108
|
+
projectPath: this.projectPath,
|
|
109
|
+
isOverride: this.isOverride
|
|
110
|
+
});
|
|
111
|
+
let success = await generator.generate();
|
|
112
|
+
if(!success){
|
|
113
|
+
Logger.error('Entity generation failed.');
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
Logger.info('Entity generation completed successfully!');
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
62
119
|
}
|
|
63
120
|
|
|
64
|
-
let generator = new
|
|
65
|
-
generator.
|
|
121
|
+
let generator = new StorageEntitiesGenerator();
|
|
122
|
+
generator.run().then((success) => {
|
|
66
123
|
if(!success){
|
|
67
|
-
|
|
68
|
-
process.exit();
|
|
124
|
+
process.exit(1);
|
|
69
125
|
}
|
|
70
|
-
|
|
71
|
-
process.exit();
|
|
126
|
+
process.exit(0);
|
|
72
127
|
}).catch((error) => {
|
|
73
128
|
Logger.error('Error during entity generation: '+error.message);
|
|
74
|
-
process.exit();
|
|
129
|
+
process.exit(1);
|
|
75
130
|
});
|
|
@@ -606,8 +606,8 @@ class EntitiesGenerator
|
|
|
606
606
|
return true;
|
|
607
607
|
}
|
|
608
608
|
if(!FileHandler.exists(this.entitiesConfigPath)){
|
|
609
|
-
Logger.
|
|
610
|
-
return
|
|
609
|
+
Logger.info('Entities config file does not exist, creating new file.');
|
|
610
|
+
return this.regenerateEntitiesConfigFile();
|
|
611
611
|
}
|
|
612
612
|
let existingContent = FileHandler.readFile(this.entitiesConfigPath);
|
|
613
613
|
if(!existingContent){
|
|
@@ -753,8 +753,8 @@ class EntitiesGenerator
|
|
|
753
753
|
return true;
|
|
754
754
|
}
|
|
755
755
|
if(!FileHandler.exists(this.entitiesTranslationsPath)){
|
|
756
|
-
Logger.
|
|
757
|
-
return
|
|
756
|
+
Logger.info('Entities translations file does not exist, creating new file.');
|
|
757
|
+
return this.regenerateEntitiesTranslationsFile();
|
|
758
758
|
}
|
|
759
759
|
let existingContent = FileHandler.readFile(this.entitiesTranslationsPath);
|
|
760
760
|
if(!existingContent){
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const { execSync
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
8
|
const { FileHandler } = require('@reldens/server-utils');
|
|
9
9
|
const { Logger, sc } = require('@reldens/utils');
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ class PrismaSchemaGenerator
|
|
|
21
21
|
this.maxWaitTime = sc.get(props, 'maxWaitTime', 30000);
|
|
22
22
|
this.prismaSchemaPath = sc.get(props, 'prismaSchemaPath', FileHandler.joinPaths(process.cwd(), 'prisma'));
|
|
23
23
|
this.schemaFilePath = FileHandler.joinPaths(this.prismaSchemaPath, 'schema.prisma');
|
|
24
|
-
this.clientOutputPath = sc.get(props, 'clientOutputPath', '
|
|
24
|
+
this.clientOutputPath = sc.get(props, 'clientOutputPath', '');
|
|
25
25
|
this.generateBinaryTargets = sc.get(props, 'generateBinaryTargets', ['native']);
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -30,62 +30,41 @@ class PrismaSchemaGenerator
|
|
|
30
30
|
FileHandler.createFolder(this.prismaSchemaPath);
|
|
31
31
|
this.generateSchemaFile();
|
|
32
32
|
Logger.info('Running prisma introspect "npx prisma db pull"...');
|
|
33
|
-
|
|
33
|
+
try {
|
|
34
|
+
execSync('npx prisma db pull', { stdio: 'inherit' });
|
|
35
|
+
} catch(error) {
|
|
36
|
+
Logger.critical('Failed to pull database schema: ' + error.message);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
34
39
|
let generateCommand = 'npx prisma generate';
|
|
35
40
|
if(this.dataProxy){
|
|
36
41
|
generateCommand += ' --data-proxy';
|
|
37
42
|
}
|
|
38
43
|
Logger.info('Running prisma generate "'+generateCommand+'"...');
|
|
39
|
-
await this.executeWithFallback(generateCommand);
|
|
40
|
-
await this.waitForSchemaGeneration();
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async executeWithFallback(command)
|
|
45
|
-
{
|
|
46
44
|
try {
|
|
47
|
-
execSync(
|
|
45
|
+
execSync(generateCommand, { stdio: 'inherit' });
|
|
48
46
|
} catch(error) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
let errorString = error.toString();
|
|
48
|
+
if(errorString.includes('EPERM') && errorString.includes('query_engine-windows.dll.node')){
|
|
49
|
+
Logger.warning('Windows permission error detected with query engine file.');
|
|
50
|
+
Logger.warning('This is a known Prisma issue on Windows.');
|
|
51
|
+
Logger.warning('Please manually run: ' + generateCommand);
|
|
52
|
+
Logger.warning('You may need to close any processes using the Prisma client first.');
|
|
53
|
+
return false;
|
|
53
54
|
}
|
|
54
|
-
Logger.critical('
|
|
55
|
+
Logger.critical('Generate command failed: ' + error.message);
|
|
55
56
|
return false;
|
|
56
57
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
isWindowsPermissionError(error)
|
|
60
|
-
{
|
|
61
|
-
return error.message
|
|
62
|
-
&& error.message.includes('EPERM')
|
|
63
|
-
&& error.message.includes('rename')
|
|
64
|
-
&& error.message.includes('query_engine-windows.dll.node');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
executeDetached(command)
|
|
68
|
-
{
|
|
69
|
-
return new Promise((resolve, reject) => {
|
|
70
|
-
let child = spawn(command, [], {
|
|
71
|
-
stdio: 'inherit',
|
|
72
|
-
shell: true,
|
|
73
|
-
detached: true
|
|
74
|
-
});
|
|
75
|
-
child.on('close', (code) => {
|
|
76
|
-
if(0 === code){
|
|
77
|
-
resolve();
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
reject(new Error('Command failed with exit code ' + code));
|
|
81
|
-
});
|
|
82
|
-
child.on('error', reject);
|
|
83
|
-
});
|
|
58
|
+
await this.waitForSchemaGeneration();
|
|
59
|
+
return true;
|
|
84
60
|
}
|
|
85
61
|
|
|
86
62
|
async waitForSchemaGeneration()
|
|
87
63
|
{
|
|
88
|
-
let
|
|
64
|
+
let clientPath = this.clientOutputPath || 'node_modules/.prisma/client';
|
|
65
|
+
let generatedClientPath = clientPath.startsWith('node_modules')
|
|
66
|
+
? FileHandler.joinPaths(process.cwd(), clientPath)
|
|
67
|
+
: FileHandler.joinPaths(this.prismaSchemaPath, clientPath);
|
|
89
68
|
let clientIndexPath = FileHandler.joinPaths(generatedClientPath, 'index.js');
|
|
90
69
|
let startTime = Date.now();
|
|
91
70
|
return new Promise((resolve) => {
|
|
@@ -160,7 +139,10 @@ class PrismaSchemaGenerator
|
|
|
160
139
|
{
|
|
161
140
|
let generatorContent = 'generator client {\n';
|
|
162
141
|
generatorContent += ' provider = "prisma-client-js"\n';
|
|
163
|
-
|
|
142
|
+
if(this.clientOutputPath){
|
|
143
|
+
let normalizedPath = this.clientOutputPath.replace(/\\/g, '/');
|
|
144
|
+
generatorContent += ' output = "' + normalizedPath + '"\n';
|
|
145
|
+
}
|
|
164
146
|
if(0 < this.generateBinaryTargets.length){
|
|
165
147
|
generatorContent += ' binaryTargets = [' +
|
|
166
148
|
this.generateBinaryTargets.map(target => '"' + target + '"').join(', ')
|