@rapidd/build 1.2.2 → 2.0.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 +219 -68
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +31 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/src/commands/build.d.ts +17 -0
- package/dist/src/commands/build.d.ts.map +1 -0
- package/dist/src/commands/build.js +236 -0
- package/dist/src/commands/build.js.map +1 -0
- package/dist/src/generators/aclGenerator.d.ts +6 -0
- package/dist/src/generators/aclGenerator.d.ts.map +1 -0
- package/dist/src/generators/aclGenerator.js +384 -0
- package/dist/src/generators/aclGenerator.js.map +1 -0
- package/dist/src/generators/index.d.ts +4 -0
- package/dist/src/generators/index.d.ts.map +1 -0
- package/dist/src/generators/index.js +13 -0
- package/dist/src/generators/index.js.map +1 -0
- package/dist/src/generators/modelGenerator.d.ts +10 -0
- package/dist/src/generators/modelGenerator.d.ts.map +1 -0
- package/dist/src/generators/modelGenerator.js +143 -0
- package/dist/src/generators/modelGenerator.js.map +1 -0
- package/dist/src/generators/routeGenerator.d.ts +10 -0
- package/dist/src/generators/routeGenerator.d.ts.map +1 -0
- package/dist/src/generators/routeGenerator.js +172 -0
- package/dist/src/generators/routeGenerator.js.map +1 -0
- package/dist/src/parsers/datasourceParser.d.ts +11 -0
- package/dist/src/parsers/datasourceParser.d.ts.map +1 -0
- package/dist/src/parsers/datasourceParser.js +131 -0
- package/dist/src/parsers/datasourceParser.js.map +1 -0
- package/dist/src/parsers/deepSQLAnalyzer.d.ts +85 -0
- package/dist/src/parsers/deepSQLAnalyzer.d.ts.map +1 -0
- package/dist/src/parsers/deepSQLAnalyzer.js +482 -0
- package/dist/src/parsers/deepSQLAnalyzer.js.map +1 -0
- package/dist/src/parsers/enhancedRLSConverter.d.ts +14 -0
- package/dist/src/parsers/enhancedRLSConverter.d.ts.map +1 -0
- package/dist/src/parsers/enhancedRLSConverter.js +168 -0
- package/dist/src/parsers/enhancedRLSConverter.js.map +1 -0
- package/dist/src/parsers/functionAnalyzer.d.ts +55 -0
- package/dist/src/parsers/functionAnalyzer.d.ts.map +1 -0
- package/dist/src/parsers/functionAnalyzer.js +274 -0
- package/dist/src/parsers/functionAnalyzer.js.map +1 -0
- package/dist/src/parsers/index.d.ts +13 -0
- package/dist/src/parsers/index.d.ts.map +1 -0
- package/dist/src/parsers/index.js +20 -0
- package/dist/src/parsers/index.js.map +1 -0
- package/dist/src/parsers/prismaFilterBuilder.d.ts +79 -0
- package/dist/src/parsers/prismaFilterBuilder.d.ts.map +1 -0
- package/dist/src/parsers/prismaFilterBuilder.js +322 -0
- package/dist/src/parsers/prismaFilterBuilder.js.map +1 -0
- package/dist/src/parsers/prismaParser.d.ts +14 -0
- package/dist/src/parsers/prismaParser.d.ts.map +1 -0
- package/dist/src/parsers/prismaParser.js +263 -0
- package/dist/src/parsers/prismaParser.js.map +1 -0
- package/package.json +21 -13
- package/bin/cli.js +0 -33
- package/index.js +0 -11
- package/src/commands/build.js +0 -638
- package/src/generators/aclGenerator.js +0 -394
- package/src/generators/modelGenerator.js +0 -172
- package/src/generators/relationshipsGenerator.js +0 -200
- package/src/generators/routeGenerator.js +0 -119
- package/src/parsers/datasourceParser.js +0 -121
- package/src/parsers/deepSQLAnalyzer.js +0 -554
- package/src/parsers/enhancedRLSConverter.js +0 -181
- package/src/parsers/functionAnalyzer.js +0 -302
- package/src/parsers/prismaFilterBuilder.js +0 -422
- package/src/parsers/prismaParser.js +0 -287
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Generate relationships.json from Prisma DMMF
|
|
6
|
-
* @param {Object} models - Models object from parser
|
|
7
|
-
* @param {string} outputPath - Path to output relationships.json
|
|
8
|
-
*/
|
|
9
|
-
function generateRelationships(models, outputPath) {
|
|
10
|
-
const relationships = {};
|
|
11
|
-
|
|
12
|
-
for (const [modelName, modelInfo] of Object.entries(models)) {
|
|
13
|
-
relationships[modelName] = {};
|
|
14
|
-
|
|
15
|
-
for (const relation of modelInfo.relations) {
|
|
16
|
-
const relatedModel = models[relation.type];
|
|
17
|
-
|
|
18
|
-
if (!relatedModel) {
|
|
19
|
-
console.warn(`Warning: Related model ${relation.type} not found for ${modelName}.${relation.name}`);
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Check if the related model has a composite primary key (many-to-many junction table)
|
|
24
|
-
const compositeKeyFields = getCompositeKeyFromModel(relatedModel);
|
|
25
|
-
|
|
26
|
-
// Only add field/fields if:
|
|
27
|
-
// 1. Related model has composite key (junction table)
|
|
28
|
-
// 2. It's a many relationship (array)
|
|
29
|
-
// 3. The composite key includes this model's foreign key (proving it's a junction for this model)
|
|
30
|
-
const currentModelFk = `${modelName.toLowerCase()}_id`;
|
|
31
|
-
const isJunctionTable = compositeKeyFields &&
|
|
32
|
-
compositeKeyFields.length > 1 &&
|
|
33
|
-
relation.isArray &&
|
|
34
|
-
compositeKeyFields.includes(currentModelFk);
|
|
35
|
-
|
|
36
|
-
if (isJunctionTable) {
|
|
37
|
-
// Many-to-many relationship through junction table
|
|
38
|
-
// Reorder fields so current model's field comes first
|
|
39
|
-
const reorderedFields = reorderFieldsForModel(compositeKeyFields, modelName);
|
|
40
|
-
|
|
41
|
-
relationships[modelName][relation.name] = {
|
|
42
|
-
'object': relation.type,
|
|
43
|
-
'field': compositeKeyFields.join('_'), // e.g., "course_id_teacher_id"
|
|
44
|
-
'fields': reorderedFields
|
|
45
|
-
};
|
|
46
|
-
} else {
|
|
47
|
-
// Simple one-to-one or one-to-many relationship
|
|
48
|
-
// Find the foreign key field name
|
|
49
|
-
const foreignKeyField = findForeignKeyField(relation, modelInfo, relatedModel);
|
|
50
|
-
|
|
51
|
-
if (!foreignKeyField) {
|
|
52
|
-
// Skip this relationship if we can't find the FK field
|
|
53
|
-
// This usually means the FK is on the other side of the relation
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
relationships[modelName][relation.name] = {
|
|
58
|
-
'object': relation.type,
|
|
59
|
-
'field': foreignKeyField
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Ensure output directory exists
|
|
66
|
-
const outputDir = path.dirname(outputPath);
|
|
67
|
-
if (!fs.existsSync(outputDir)) {
|
|
68
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
fs.writeFileSync(outputPath, JSON.stringify(relationships, null, 4));
|
|
72
|
-
console.log('Generated relationships.json');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Find the foreign key field for a relation
|
|
77
|
-
* @param {Object} relation - Relation object
|
|
78
|
-
* @param {Object} currentModel - Current model info
|
|
79
|
-
* @param {Object} relatedModel - Related model info
|
|
80
|
-
* @returns {string|null} - Foreign key field name
|
|
81
|
-
*/
|
|
82
|
-
function findForeignKeyField(relation, currentModel, relatedModel) {
|
|
83
|
-
// IMPORTANT: The foreign key field is where the @relation(fields: [...]) is defined
|
|
84
|
-
|
|
85
|
-
// For array relations (one-to-many), the FK is in the related model (child)
|
|
86
|
-
if (relation.isArray) {
|
|
87
|
-
// Find the corresponding relation in the related model that points back
|
|
88
|
-
for (const relField of Object.values(relatedModel.fields)) {
|
|
89
|
-
if (relField.kind === 'object' &&
|
|
90
|
-
relField.relationName === relation.relationName &&
|
|
91
|
-
relField.relationFromFields &&
|
|
92
|
-
relField.relationFromFields.length > 0) {
|
|
93
|
-
// This is the FK field in the child (related) model
|
|
94
|
-
return relField.relationFromFields[0];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
// Fallback
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// For singular relations (many-to-one or one-to-one), check if THIS relation has fields defined
|
|
102
|
-
if (relation.relationFromFields && relation.relationFromFields.length > 0) {
|
|
103
|
-
// The FK is in the current model
|
|
104
|
-
return relation.relationFromFields[0];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// For optional one-to-one relations where FK is on the other side
|
|
108
|
-
// (e.g., users -> student_profiles? where userId is in student_profiles)
|
|
109
|
-
if (!relation.isArray) {
|
|
110
|
-
// Find the corresponding relation in the related model that points back
|
|
111
|
-
for (const relField of Object.values(relatedModel.fields)) {
|
|
112
|
-
if (relField.kind === 'object' &&
|
|
113
|
-
relField.relationName === relation.relationName &&
|
|
114
|
-
relField.relationFromFields &&
|
|
115
|
-
relField.relationFromFields.length > 0) {
|
|
116
|
-
// This is the FK field in the related model (pointing back to us)
|
|
117
|
-
return relField.relationFromFields[0];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// If no fields on this side, the FK must be on the other side (shouldn't use this relation for filtering)
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get composite key fields from a model
|
|
128
|
-
* @param {Object} modelInfo - Model information
|
|
129
|
-
* @returns {Array|null} - Array of composite key field names or null
|
|
130
|
-
*/
|
|
131
|
-
function getCompositeKeyFromModel(modelInfo) {
|
|
132
|
-
// First check if the model has a compositeKey property (from parser)
|
|
133
|
-
if (modelInfo.compositeKey && modelInfo.compositeKey.length > 1) {
|
|
134
|
-
return modelInfo.compositeKey;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Fallback: check for fields marked with isId (for schema parser)
|
|
138
|
-
const compositeFields = [];
|
|
139
|
-
for (const [fieldName, fieldInfo] of Object.entries(modelInfo.fields)) {
|
|
140
|
-
if (fieldInfo.isId && !fieldInfo.isRelation) {
|
|
141
|
-
compositeFields.push(fieldName);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// If we found multiple ID fields, it's a composite key
|
|
146
|
-
if (compositeFields.length > 1) {
|
|
147
|
-
return compositeFields;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Reorder composite key fields so the current model's field comes first
|
|
155
|
-
* @param {Array} fields - Array of field names
|
|
156
|
-
* @param {String} currentModelName - Name of the current model
|
|
157
|
-
* @returns {Array} - Reordered array with current model's field first
|
|
158
|
-
*/
|
|
159
|
-
function reorderFieldsForModel(fields, currentModelName) {
|
|
160
|
-
const currentModelField = `${currentModelName.toLowerCase()}_id`;
|
|
161
|
-
const index = fields.indexOf(currentModelField);
|
|
162
|
-
|
|
163
|
-
if (index > 0) {
|
|
164
|
-
// Move current model's field to the front
|
|
165
|
-
const reordered = [...fields];
|
|
166
|
-
reordered.splice(index, 1);
|
|
167
|
-
reordered.unshift(currentModelField);
|
|
168
|
-
return reordered;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return fields;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Generate relationships.json from schema
|
|
176
|
-
* @param {string} schemaPath - Path to Prisma schema file
|
|
177
|
-
* @param {string} outputPath - Path to output relationships.json
|
|
178
|
-
*/
|
|
179
|
-
function generateRelationshipsFromSchema(schemaPath, outputPath) {
|
|
180
|
-
const { parsePrismaSchema } = require('../parsers/prismaParser');
|
|
181
|
-
const parsedData = parsePrismaSchema(schemaPath);
|
|
182
|
-
generateRelationships(parsedData.models, outputPath);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Generate relationships.json from DMMF
|
|
187
|
-
* @param {string} schemaPath - Path to Prisma schema file
|
|
188
|
-
* @param {string} outputPath - Path to output relationships.json
|
|
189
|
-
*/
|
|
190
|
-
async function generateRelationshipsFromDMMF(schemaPath, outputPath) {
|
|
191
|
-
const { parsePrismaDMMF } = require('../parsers/prismaParser');
|
|
192
|
-
const parsedData = await parsePrismaDMMF(schemaPath);
|
|
193
|
-
generateRelationships(parsedData.models, outputPath);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
module.exports = {
|
|
197
|
-
generateRelationships,
|
|
198
|
-
generateRelationshipsFromSchema,
|
|
199
|
-
generateRelationshipsFromDMMF
|
|
200
|
-
};
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Generate Express route for a single model
|
|
6
|
-
* @param {string} modelName - Name of the model
|
|
7
|
-
* @returns {string} - Generated route code
|
|
8
|
-
*/
|
|
9
|
-
function generateRouteFile(modelName) {
|
|
10
|
-
const className = modelName.split(/[^a-zA-Z0-9]+/) // split on any non-alphanumeric char
|
|
11
|
-
.filter(Boolean) // remove empty parts
|
|
12
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
13
|
-
.join('');
|
|
14
|
-
|
|
15
|
-
return `const router = require('express').Router();
|
|
16
|
-
const {${className}, QueryBuilder, prisma} = require('../../../src/Model/${className}');
|
|
17
|
-
|
|
18
|
-
router.all('*', async (req, res, next) => {
|
|
19
|
-
if(req.user){
|
|
20
|
-
req.${className} = new ${className}({'user': req.user});
|
|
21
|
-
next();
|
|
22
|
-
}
|
|
23
|
-
else{
|
|
24
|
-
return res.sendError(401, "no_valid_session");
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// GET ALL
|
|
29
|
-
router.get('/', async function(req, res) {
|
|
30
|
-
try {
|
|
31
|
-
const { q = {}, include = "", limit = 25, offset = 0, sortBy = "id", sortOrder = "asc" } = req.query;
|
|
32
|
-
const results = await req.${className}.getMany(q, include, limit, offset, sortBy, sortOrder);
|
|
33
|
-
return res.sendList(results.data, results.meta);
|
|
34
|
-
}
|
|
35
|
-
catch(error){
|
|
36
|
-
const response = QueryBuilder.errorHandler(error);
|
|
37
|
-
return res.status(response.status_code).send(response);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// GET BY ID
|
|
42
|
-
router.get('/:id', async function(req, res) {
|
|
43
|
-
try{
|
|
44
|
-
const { include = ""} = req.query;
|
|
45
|
-
const response = await req.${className}.get(req.params.id, include);
|
|
46
|
-
return res.json(response);
|
|
47
|
-
}
|
|
48
|
-
catch(error){
|
|
49
|
-
const response = QueryBuilder.errorHandler(error);
|
|
50
|
-
return res.status(response.status_code).send(response);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// CREATE
|
|
55
|
-
router.post('/', async function(req, res) {
|
|
56
|
-
const payload = req.body;
|
|
57
|
-
try{
|
|
58
|
-
const response = await req.${className}.create(payload);
|
|
59
|
-
return res.status(201).json(response);
|
|
60
|
-
}
|
|
61
|
-
catch(error){
|
|
62
|
-
const response = QueryBuilder.errorHandler(error, payload);
|
|
63
|
-
return res.status(response.status_code).send(response);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// UPDATE
|
|
68
|
-
router.patch('/:id', async function(req, res) {
|
|
69
|
-
const payload = req.body;
|
|
70
|
-
try{
|
|
71
|
-
const response = await req.${className}.update(req.params.id, payload);
|
|
72
|
-
return res.json(response);
|
|
73
|
-
}
|
|
74
|
-
catch(error){
|
|
75
|
-
const response = QueryBuilder.errorHandler(error, payload);
|
|
76
|
-
return res.status(response.status_code).send(response);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// DELETE
|
|
81
|
-
router.delete('/:id', async (req, res)=>{
|
|
82
|
-
try{
|
|
83
|
-
await req.${className}.delete(req.params.id);
|
|
84
|
-
return res.sendResponse(200, "object_deleted_successfully", {modelName: "${className}"});
|
|
85
|
-
}
|
|
86
|
-
catch(error){
|
|
87
|
-
const response = QueryBuilder.errorHandler(error);
|
|
88
|
-
return res.status(response.status_code).send(response);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
module.exports = router;
|
|
93
|
-
`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Generate all route files
|
|
98
|
-
* @param {Object} models - Models object from parser
|
|
99
|
-
* @param {string} routesDir - Directory to output route files
|
|
100
|
-
*/
|
|
101
|
-
function generateAllRoutes(models, routesDir) {
|
|
102
|
-
// Create routes directory if it doesn't exist
|
|
103
|
-
if (!fs.existsSync(routesDir)) {
|
|
104
|
-
fs.mkdirSync(routesDir, { recursive: true });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Generate individual route files
|
|
108
|
-
for (const modelName of Object.keys(models)) {
|
|
109
|
-
const routeCode = generateRouteFile(modelName);
|
|
110
|
-
const routePath = path.join(routesDir, `${modelName}.js`);
|
|
111
|
-
fs.writeFileSync(routePath, routeCode);
|
|
112
|
-
console.log(`Generated route: ${modelName}.js`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
module.exports = {
|
|
117
|
-
generateAllRoutes,
|
|
118
|
-
generateRouteFile
|
|
119
|
-
};
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
// Load .env file if it exists
|
|
5
|
-
try {
|
|
6
|
-
require('dotenv').config({ path: path.join(process.cwd(), '.env') });
|
|
7
|
-
} catch (e) {
|
|
8
|
-
// dotenv not available, skip
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Try to load DATABASE_URL from prisma.config.ts (Prisma 7)
|
|
13
|
-
* @returns {string|null} - Database URL or null if not found
|
|
14
|
-
*/
|
|
15
|
-
function loadUrlFromPrismaConfig() {
|
|
16
|
-
const configPath = path.join(process.cwd(), 'prisma.config.ts');
|
|
17
|
-
|
|
18
|
-
if (!fs.existsSync(configPath)) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
24
|
-
|
|
25
|
-
// Look for env('DATABASE_URL') or similar patterns
|
|
26
|
-
const envMatch = configContent.match(/env\(['"]([^'"]+)['"]\)/);
|
|
27
|
-
if (envMatch) {
|
|
28
|
-
const envVar = envMatch[1];
|
|
29
|
-
return process.env[envVar] || null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Look for direct URL assignment
|
|
33
|
-
const urlMatch = configContent.match(/url:\s*['"]([^'"]+)['"]/);
|
|
34
|
-
if (urlMatch) {
|
|
35
|
-
return urlMatch[1];
|
|
36
|
-
}
|
|
37
|
-
} catch (e) {
|
|
38
|
-
// Failed to read config, return null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Parse datasource configuration from Prisma schema
|
|
46
|
-
* @param {string} schemaPath - Path to Prisma schema file
|
|
47
|
-
* @returns {Object} - Datasource configuration with resolved URL
|
|
48
|
-
*/
|
|
49
|
-
function parseDatasource(schemaPath) {
|
|
50
|
-
const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
|
|
51
|
-
|
|
52
|
-
// Extract datasource block
|
|
53
|
-
const datasourceRegex = /datasource\s+\w+\s*{([^}]*)}/;
|
|
54
|
-
const match = schemaContent.match(datasourceRegex);
|
|
55
|
-
|
|
56
|
-
if (!match) {
|
|
57
|
-
throw new Error('No datasource block found in Prisma schema');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const datasourceBlock = match[1];
|
|
61
|
-
|
|
62
|
-
// Extract provider
|
|
63
|
-
const providerMatch = datasourceBlock.match(/provider\s*=\s*"([^"]+)"/);
|
|
64
|
-
const provider = providerMatch ? providerMatch[1] : null;
|
|
65
|
-
|
|
66
|
-
// Try to extract url from schema first
|
|
67
|
-
let url = null;
|
|
68
|
-
const urlMatch = datasourceBlock.match(/url\s*=\s*(.+)/);
|
|
69
|
-
|
|
70
|
-
if (urlMatch) {
|
|
71
|
-
url = urlMatch[1].trim();
|
|
72
|
-
|
|
73
|
-
// Handle env() function
|
|
74
|
-
const envMatch = url.match(/env\(["']([^"']+)["']\)/);
|
|
75
|
-
if (envMatch) {
|
|
76
|
-
const envVar = envMatch[1];
|
|
77
|
-
url = process.env[envVar];
|
|
78
|
-
} else {
|
|
79
|
-
// Remove quotes if present
|
|
80
|
-
url = url.replace(/^["']|["']$/g, '');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// If no URL in schema, try prisma.config.ts (Prisma 7)
|
|
85
|
-
if (!url) {
|
|
86
|
-
url = loadUrlFromPrismaConfig();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// If still no URL, check DATABASE_URL environment variable directly
|
|
90
|
-
if (!url) {
|
|
91
|
-
url = process.env.DATABASE_URL || null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Detect PostgreSQL from provider OR from the actual connection URL
|
|
95
|
-
// This is important because the schema might say "mysql" but DATABASE_URL could be postgresql://
|
|
96
|
-
let isPostgreSQL = provider === 'postgresql' || provider === 'postgres';
|
|
97
|
-
|
|
98
|
-
if (!isPostgreSQL && url) {
|
|
99
|
-
// Check if URL starts with postgresql:// or postgres://
|
|
100
|
-
isPostgreSQL = url.startsWith('postgresql://') || url.startsWith('postgres://');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Explicitly detect MySQL to avoid false PostgreSQL detection
|
|
104
|
-
const isMySQL = provider === 'mysql' || (url && url.startsWith('mysql://'));
|
|
105
|
-
|
|
106
|
-
// If it's MySQL, ensure isPostgreSQL is false
|
|
107
|
-
if (isMySQL) {
|
|
108
|
-
isPostgreSQL = false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
provider,
|
|
113
|
-
url,
|
|
114
|
-
isPostgreSQL,
|
|
115
|
-
isMySQL
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
module.exports = {
|
|
120
|
-
parseDatasource
|
|
121
|
-
};
|