@bairock/lenz 0.0.15 → 0.0.16
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 +88 -4
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +34 -8
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +0 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/index.js +0 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +4 -6
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +24 -3
- package/dist/config/index.js.map +1 -1
- package/dist/engine/CodeGenerator.d.ts +7 -28
- package/dist/engine/CodeGenerator.d.ts.map +1 -1
- package/dist/engine/CodeGenerator.js +25 -1969
- package/dist/engine/CodeGenerator.js.map +1 -1
- package/dist/engine/GraphQLParseHelpers.d.ts +25 -0
- package/dist/engine/GraphQLParseHelpers.d.ts.map +1 -0
- package/dist/engine/GraphQLParseHelpers.js +128 -0
- package/dist/engine/GraphQLParseHelpers.js.map +1 -0
- package/dist/engine/GraphQLParser.d.ts +23 -10
- package/dist/engine/GraphQLParser.d.ts.map +1 -1
- package/dist/engine/GraphQLParser.js +154 -240
- package/dist/engine/GraphQLParser.js.map +1 -1
- package/dist/engine/GraphQLRelationAnalyzer.d.ts +10 -0
- package/dist/engine/GraphQLRelationAnalyzer.d.ts.map +1 -0
- package/dist/engine/GraphQLRelationAnalyzer.js +117 -0
- package/dist/engine/GraphQLRelationAnalyzer.js.map +1 -0
- package/dist/engine/LenzEngine.d.ts +1 -1
- package/dist/engine/LenzEngine.d.ts.map +1 -1
- package/dist/engine/LenzEngine.js +33 -13
- package/dist/engine/LenzEngine.js.map +1 -1
- package/dist/engine/SchemaRelationValidator.d.ts +15 -0
- package/dist/engine/SchemaRelationValidator.d.ts.map +1 -0
- package/dist/engine/SchemaRelationValidator.js +133 -0
- package/dist/engine/SchemaRelationValidator.js.map +1 -0
- package/dist/engine/SchemaValidator.d.ts +11 -10
- package/dist/engine/SchemaValidator.d.ts.map +1 -1
- package/dist/engine/SchemaValidator.js +151 -169
- package/dist/engine/SchemaValidator.js.map +1 -1
- package/dist/engine/directives.d.ts +10 -0
- package/dist/engine/directives.d.ts.map +1 -1
- package/dist/engine/directives.js +152 -6
- package/dist/engine/directives.js.map +1 -1
- package/dist/engine/generators/ClientGenerator.d.ts +7 -0
- package/dist/engine/generators/ClientGenerator.d.ts.map +1 -0
- package/dist/engine/generators/ClientGenerator.js +386 -0
- package/dist/engine/generators/ClientGenerator.js.map +1 -0
- package/dist/engine/generators/DelegateGenerator.d.ts +9 -0
- package/dist/engine/generators/DelegateGenerator.d.ts.map +1 -0
- package/dist/engine/generators/DelegateGenerator.js +453 -0
- package/dist/engine/generators/DelegateGenerator.js.map +1 -0
- package/dist/engine/generators/DelegateHelpers.d.ts +7 -0
- package/dist/engine/generators/DelegateHelpers.d.ts.map +1 -0
- package/dist/engine/generators/DelegateHelpers.js +144 -0
- package/dist/engine/generators/DelegateHelpers.js.map +1 -0
- package/dist/engine/generators/DelegateRelations.d.ts +11 -0
- package/dist/engine/generators/DelegateRelations.d.ts.map +1 -0
- package/dist/engine/generators/DelegateRelations.js +794 -0
- package/dist/engine/generators/DelegateRelations.js.map +1 -0
- package/dist/engine/generators/DelegateTemplateBody.d.ts +8 -0
- package/dist/engine/generators/DelegateTemplateBody.d.ts.map +1 -0
- package/dist/engine/generators/DelegateTemplateBody.js +776 -0
- package/dist/engine/generators/DelegateTemplateBody.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeErrors.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeErrors.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeErrors.js +140 -0
- package/dist/engine/generators/GenerateRuntimeErrors.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeIndex.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeIndex.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeIndex.js +21 -0
- package/dist/engine/generators/GenerateRuntimeIndex.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeLogger.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeLogger.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeLogger.js +125 -0
- package/dist/engine/generators/GenerateRuntimeLogger.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimePagination.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimePagination.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimePagination.js +159 -0
- package/dist/engine/generators/GenerateRuntimePagination.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeQuery.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeQuery.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeQuery.js +427 -0
- package/dist/engine/generators/GenerateRuntimeQuery.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeRelations.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeRelations.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeRelations.js +130 -0
- package/dist/engine/generators/GenerateRuntimeRelations.js.map +1 -0
- package/dist/engine/generators/RuntimeGenerator.d.ts +16 -0
- package/dist/engine/generators/RuntimeGenerator.d.ts.map +1 -0
- package/dist/engine/generators/RuntimeGenerator.js +16 -0
- package/dist/engine/generators/RuntimeGenerator.js.map +1 -0
- package/dist/engine/generators/TypeFilterTypes.d.ts +2 -0
- package/dist/engine/generators/TypeFilterTypes.d.ts.map +1 -0
- package/dist/engine/generators/TypeFilterTypes.js +220 -0
- package/dist/engine/generators/TypeFilterTypes.js.map +1 -0
- package/dist/engine/generators/TypeGenerator.d.ts +16 -0
- package/dist/engine/generators/TypeGenerator.d.ts.map +1 -0
- package/dist/engine/generators/TypeGenerator.js +493 -0
- package/dist/engine/generators/TypeGenerator.js.map +1 -0
- package/dist/engine/generators/helpers.d.ts +13 -0
- package/dist/engine/generators/helpers.d.ts.map +1 -0
- package/dist/engine/generators/helpers.js +316 -0
- package/dist/engine/generators/helpers.js.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +11 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { toCamelCase } from './generators/helpers.js';
|
|
2
|
+
export class GraphQLRelationAnalyzer {
|
|
3
|
+
constructor(models, relations) {
|
|
4
|
+
this.models = models;
|
|
5
|
+
this.relations = relations;
|
|
6
|
+
}
|
|
7
|
+
analyzeRelationships() {
|
|
8
|
+
for (const [modelName, model] of this.models) {
|
|
9
|
+
if (model.isEmbedded)
|
|
10
|
+
continue;
|
|
11
|
+
for (const field of model.fields) {
|
|
12
|
+
if (field.isRelation && this.models.has(field.type)) {
|
|
13
|
+
const targetModel = this.models.get(field.type);
|
|
14
|
+
if (targetModel?.isEmbedded)
|
|
15
|
+
continue;
|
|
16
|
+
const relation = this.determineRelationType(modelName, field);
|
|
17
|
+
if (relation) {
|
|
18
|
+
model.relations.push(relation);
|
|
19
|
+
this.relations.push(relation);
|
|
20
|
+
// Add index for foreign key field if relation.index is true
|
|
21
|
+
if (relation.index && relation.foreignKey) {
|
|
22
|
+
// Add index on FK field in the model that stores it
|
|
23
|
+
const indexedModel = relation.foreignKeyLocation === 'target' ? targetModel : model;
|
|
24
|
+
if (indexedModel) {
|
|
25
|
+
const existingIndex = indexedModel.indexes.find(idx => idx.fields.length === 1 && idx.fields[0] === relation.foreignKey);
|
|
26
|
+
if (!existingIndex) {
|
|
27
|
+
indexedModel.indexes.push({
|
|
28
|
+
fields: [relation.foreignKey],
|
|
29
|
+
unique: false,
|
|
30
|
+
sparse: relation.type === 'oneToOne' || relation.type === 'manyToOne' ? true : false
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
getJoinCollectionName(model1, model2) {
|
|
41
|
+
const [first, second] = [model1.toLowerCase(), model2.toLowerCase()].sort();
|
|
42
|
+
return `${first}_${second}`;
|
|
43
|
+
}
|
|
44
|
+
determineRelationType(modelName, field) {
|
|
45
|
+
const targetModel = this.models.get(field.type);
|
|
46
|
+
if (!targetModel)
|
|
47
|
+
return null;
|
|
48
|
+
let relationType;
|
|
49
|
+
let foreignKey = field.foreignKey;
|
|
50
|
+
let foreignKeyLocation = 'source';
|
|
51
|
+
let joinCollection = undefined;
|
|
52
|
+
if (field.isArray) {
|
|
53
|
+
if (foreignKey && foreignKey.endsWith('Ids')) {
|
|
54
|
+
const reverseField = targetModel.fields.find(f => f.isRelation && f.type === modelName);
|
|
55
|
+
if (reverseField && reverseField.isArray) {
|
|
56
|
+
relationType = 'manyToMany';
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
relationType = 'oneToMany';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (foreignKey) {
|
|
63
|
+
// FK exists but is a single ID — oneToMany (FK stored in target)
|
|
64
|
+
relationType = 'oneToMany';
|
|
65
|
+
foreignKeyLocation = 'target';
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
relationType = 'manyToMany';
|
|
69
|
+
if (!foreignKey) {
|
|
70
|
+
joinCollection = this.getJoinCollectionName(modelName, field.type);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
relationType = 'manyToOne';
|
|
76
|
+
}
|
|
77
|
+
// Auto-generate foreign key if not specified
|
|
78
|
+
if (foreignKey === undefined && relationType !== 'manyToMany') {
|
|
79
|
+
foreignKey = `${toCamelCase(targetModel.name)}Id`;
|
|
80
|
+
}
|
|
81
|
+
// Default strategy based on relation type
|
|
82
|
+
let defaultStrategy = 'populate';
|
|
83
|
+
if (relationType === 'oneToMany') {
|
|
84
|
+
defaultStrategy = 'lookup';
|
|
85
|
+
}
|
|
86
|
+
else if (relationType === 'manyToMany') {
|
|
87
|
+
defaultStrategy = foreignKey ? 'lookup' : 'populate';
|
|
88
|
+
}
|
|
89
|
+
// Determine if foreign key is array
|
|
90
|
+
let isForeignKeyArray = false;
|
|
91
|
+
if (foreignKey) {
|
|
92
|
+
const sourceModel = this.models.get(modelName);
|
|
93
|
+
if (sourceModel) {
|
|
94
|
+
const foreignKeyField = sourceModel.fields.find(f => f.name === foreignKey);
|
|
95
|
+
if (foreignKeyField) {
|
|
96
|
+
isForeignKeyArray = foreignKeyField.isArray;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const relation = {
|
|
101
|
+
type: relationType,
|
|
102
|
+
field: field.name,
|
|
103
|
+
target: field.type,
|
|
104
|
+
foreignKey,
|
|
105
|
+
foreignKeyLocation,
|
|
106
|
+
joinCollection,
|
|
107
|
+
strategy: field.relationStrategy ?? defaultStrategy,
|
|
108
|
+
index: field.relationIndex ?? true,
|
|
109
|
+
isForeignKeyArray,
|
|
110
|
+
onDelete: field.onDelete ?? 'NoAction',
|
|
111
|
+
onUpdate: field.onUpdate,
|
|
112
|
+
relationName: field.relationName,
|
|
113
|
+
};
|
|
114
|
+
return relation;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=GraphQLRelationAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphQLRelationAnalyzer.js","sourceRoot":"","sources":["../../src/engine/GraphQLRelationAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LenzEngine.d.ts","sourceRoot":"","sources":["../../src/engine/LenzEngine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LenzEngine.d.ts","sourceRoot":"","sources":["../../src/engine/LenzEngine.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAU;IAIT,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,SAAS,CAAgB;gBAEb,OAAO,EAAE,eAAe;IAItC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YA6FjB,wBAAwB;YAMxB,yBAAyB;IA0BvC,aAAa;;;;;;;;CAId"}
|
|
@@ -3,7 +3,7 @@ import { CodeGenerator } from './CodeGenerator.js';
|
|
|
3
3
|
import { promises as fs, existsSync } from 'fs';
|
|
4
4
|
import { join, dirname } from 'path';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import {
|
|
6
|
+
import { CodeGenerationError, ConfigurationError, isLenzError } from '../errors/index.js';
|
|
7
7
|
export class LenzEngine {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
this.options = options;
|
|
@@ -36,25 +36,43 @@ export class LenzEngine {
|
|
|
36
36
|
clientName: this.options.clientName || 'LenzClient'
|
|
37
37
|
};
|
|
38
38
|
const generatedFiles = this.generator.generate(codeGenOptions);
|
|
39
|
-
// 4. Write files
|
|
39
|
+
// 4. Write files with cleanup on failure
|
|
40
|
+
const writtenFiles = [];
|
|
40
41
|
let fileCount = 0;
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
try {
|
|
43
|
+
for (const [filePath, content] of Object.entries(generatedFiles)) {
|
|
44
|
+
const fullPath = join(this.options.outputPath, filePath);
|
|
45
|
+
await this.ensureDirectoryStructure(dirname(fullPath));
|
|
46
|
+
await fs.writeFile(fullPath, content, 'utf-8');
|
|
47
|
+
writtenFiles.push(fullPath);
|
|
48
|
+
fileCount++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (writeError) {
|
|
52
|
+
// Clean up partially written files
|
|
53
|
+
console.warn(chalk.yellow(`⚠️ Write failed, cleaning up ${writtenFiles.length} written files...`));
|
|
54
|
+
for (const filePath of writtenFiles) {
|
|
55
|
+
await fs.unlink(filePath).catch(() => { });
|
|
56
|
+
}
|
|
57
|
+
throw writeError;
|
|
46
58
|
}
|
|
47
59
|
// 5. Generate package.json for the client
|
|
48
|
-
|
|
60
|
+
try {
|
|
61
|
+
await this.generateClientPackageJson();
|
|
62
|
+
}
|
|
63
|
+
catch (pkgError) {
|
|
64
|
+
console.warn(chalk.yellow(`⚠️ package.json generation failed, cleaning up ${writtenFiles.length} written files...`));
|
|
65
|
+
for (const filePath of writtenFiles) {
|
|
66
|
+
await fs.unlink(filePath).catch(() => { });
|
|
67
|
+
}
|
|
68
|
+
throw pkgError;
|
|
69
|
+
}
|
|
49
70
|
console.log(chalk.green(`✅ Generated ${fileCount} files to ${this.options.outputPath}`));
|
|
50
71
|
console.log(chalk.green('✨ Client is ready to use!'));
|
|
51
72
|
}
|
|
52
73
|
catch (error) {
|
|
53
74
|
console.log(chalk.red('❌ Generation failed:'));
|
|
54
|
-
|
|
55
|
-
const isLenzError = error instanceof SchemaValidationError || error instanceof SchemaParseError ||
|
|
56
|
-
error instanceof CodeGenerationError || error instanceof ConfigurationError;
|
|
57
|
-
if (isLenzError) {
|
|
75
|
+
if (isLenzError(error)) {
|
|
58
76
|
console.log(chalk.red(` ${error.code}: ${error.message}`));
|
|
59
77
|
if (error.details) {
|
|
60
78
|
console.log(chalk.gray(' Details:', JSON.stringify(error.details, null, 2)));
|
|
@@ -99,7 +117,9 @@ export class LenzEngine {
|
|
|
99
117
|
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8');
|
|
100
118
|
}
|
|
101
119
|
getSchemaInfo() {
|
|
102
|
-
|
|
120
|
+
if (!this.parser)
|
|
121
|
+
throw new Error('LenzEngine not yet initialized. Call generate() first.');
|
|
122
|
+
return this.parser.getSchemaInfo();
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
125
|
//# sourceMappingURL=LenzEngine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LenzEngine.js","sourceRoot":"","sources":["../../src/engine/LenzEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAqC,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"LenzEngine.js","sourceRoot":"","sources":["../../src/engine/LenzEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GraphQLModel, ModelRelation } from './GraphQLParser.js';
|
|
2
|
+
export declare class SchemaRelationValidator {
|
|
3
|
+
private models;
|
|
4
|
+
private relations;
|
|
5
|
+
constructor(models: GraphQLModel[], relations: ModelRelation[]);
|
|
6
|
+
/**
|
|
7
|
+
* Validate relations between models
|
|
8
|
+
*/
|
|
9
|
+
validateRelations(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Validate relation strategies and indexes
|
|
12
|
+
*/
|
|
13
|
+
validateRelationStrategies(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=SchemaRelationValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaRelationValidator.d.ts","sourceRoot":"","sources":["../../src/engine/SchemaRelationValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAM5B,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;gBADT,MAAM,EAAE,YAAY,EAAE,EACtB,SAAS,EAAE,aAAa,EAAE;IAGpC;;OAEG;IACH,iBAAiB,IAAI,IAAI;IA8FzB;;OAEG;IACH,0BAA0B,IAAI,IAAI;CAgFnC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { SchemaValidationError, RelationValidationError } from '../errors/index.js';
|
|
2
|
+
export class SchemaRelationValidator {
|
|
3
|
+
constructor(models, relations) {
|
|
4
|
+
this.models = models;
|
|
5
|
+
this.relations = relations;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Validate relations between models
|
|
9
|
+
*/
|
|
10
|
+
validateRelations() {
|
|
11
|
+
for (const relation of this.relations) {
|
|
12
|
+
// Find source model by reference equality (relation object was pushed into model.relations)
|
|
13
|
+
const sourceModel = this.models.find(m => m.relations.includes(relation));
|
|
14
|
+
const targetModel = this.models.find(m => m.name === relation.target);
|
|
15
|
+
if (!sourceModel) {
|
|
16
|
+
throw new RelationValidationError(`Source model for relation '${relation.field}' -> '${relation.target}' not found`, { relation });
|
|
17
|
+
}
|
|
18
|
+
if (!targetModel) {
|
|
19
|
+
throw new RelationValidationError(`Target model '${relation.target}' not found for relation`, { relation });
|
|
20
|
+
}
|
|
21
|
+
// Check if foreign key field exists and has correct type
|
|
22
|
+
if (relation.foreignKey) {
|
|
23
|
+
if (relation.type === 'oneToMany' && relation.foreignKeyLocation === 'target') {
|
|
24
|
+
// FK in target (e.g., Post.userId) — validate target model has the FK
|
|
25
|
+
if (targetModel) {
|
|
26
|
+
const fkInTarget = targetModel.fields.find(f => f.name === relation.foreignKey);
|
|
27
|
+
if (fkInTarget) {
|
|
28
|
+
if (fkInTarget.isArray || fkInTarget.type !== 'ID') {
|
|
29
|
+
throw new RelationValidationError(`Foreign key field '${relation.foreignKey}' in target model '${targetModel.name}' must be a single ID (type: ID!) for one-to-many relation`, { relation });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// FK not found in target either — might be auto-generated at runtime
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// FK in source (manyToOne, oneToOne, or oneToMany FK array)
|
|
37
|
+
const fieldInSource = sourceModel.fields.find(f => f.name === relation.foreignKey);
|
|
38
|
+
if (!fieldInSource) {
|
|
39
|
+
throw new RelationValidationError(`Foreign key field '${relation.foreignKey}' not found in source model '${sourceModel.name}'`, { relation });
|
|
40
|
+
}
|
|
41
|
+
if (relation.type === 'oneToMany') {
|
|
42
|
+
if (!fieldInSource.isArray || fieldInSource.type !== 'ID') {
|
|
43
|
+
throw new RelationValidationError(`Foreign key field '${relation.foreignKey}' in source model '${sourceModel.name}' must be an array of IDs (type: [ID!]!) for one-to-many relation`, { relation });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (relation.type === 'manyToOne' || relation.type === 'oneToOne') {
|
|
47
|
+
if (fieldInSource.isArray || fieldInSource.type !== 'ID') {
|
|
48
|
+
throw new RelationValidationError(`Foreign key field '${relation.foreignKey}' in source model '${sourceModel.name}' must be a single ID (type: ID!) for ${relation.type} relation`, { relation });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (relation.type === 'manyToMany') {
|
|
52
|
+
if (!fieldInSource.isArray || fieldInSource.type !== 'ID') {
|
|
53
|
+
throw new RelationValidationError(`Foreign key field '${relation.foreignKey}' in source model '${sourceModel.name}' must be an array of IDs (type: [ID!]!) for many-to-many relation`, { relation });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Check that relation field references correct ID field
|
|
59
|
+
const relationField = sourceModel.fields.find(f => f.name === relation.field);
|
|
60
|
+
if (!relationField) {
|
|
61
|
+
throw new RelationValidationError(`Relation field '${relation.field}' not found in source model '${sourceModel.name}'`, { relation });
|
|
62
|
+
}
|
|
63
|
+
// Validate relation field type matches target model
|
|
64
|
+
if (relationField.type !== relation.target) {
|
|
65
|
+
throw new RelationValidationError(`Relation field '${relation.field}' in model '${sourceModel.name}' has type '${relationField.type}', ` +
|
|
66
|
+
`but relation target is '${relation.target}'. The field type must match the target model name.`, { relation });
|
|
67
|
+
}
|
|
68
|
+
// END: FK field validation is complete above.
|
|
69
|
+
// Lines 104-150 were duplicate validation (removed in audit #6).
|
|
70
|
+
// Relation-specific FK type checks are handled at lines 43-83.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate relation strategies and indexes
|
|
75
|
+
*/
|
|
76
|
+
validateRelationStrategies() {
|
|
77
|
+
for (const relation of this.relations) {
|
|
78
|
+
// Validate strategy
|
|
79
|
+
if (relation.strategy !== 'populate' && relation.strategy !== 'lookup') {
|
|
80
|
+
throw new SchemaValidationError(`Invalid relation strategy '${relation.strategy}' for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
81
|
+
`Must be either 'populate' or 'lookup'.`);
|
|
82
|
+
}
|
|
83
|
+
// Validate index boolean
|
|
84
|
+
if (typeof relation.index !== 'boolean') {
|
|
85
|
+
throw new SchemaValidationError(`Invalid index value '${relation.index}' for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
86
|
+
`Must be a boolean.`);
|
|
87
|
+
}
|
|
88
|
+
// Validate onDelete
|
|
89
|
+
if (relation.onDelete && !['Cascade', 'SetNull', 'NoAction', 'Restrict'].includes(relation.onDelete)) {
|
|
90
|
+
throw new SchemaValidationError(`Invalid onDelete value '${relation.onDelete}' for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
91
|
+
`Must be 'Cascade', 'SetNull', 'Restrict', or 'NoAction'.`);
|
|
92
|
+
}
|
|
93
|
+
// Validate onUpdate
|
|
94
|
+
if (relation.onUpdate && !['Cascade', 'SetNull', 'NoAction', 'Restrict'].includes(relation.onUpdate)) {
|
|
95
|
+
throw new SchemaValidationError(`Invalid onUpdate value '${relation.onUpdate}' for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
96
|
+
`Must be 'Cascade', 'SetNull', 'Restrict', or 'NoAction'.`);
|
|
97
|
+
}
|
|
98
|
+
// Validate SetNull requires nullable FK
|
|
99
|
+
if (relation.onDelete === 'SetNull' && relation.foreignKey) {
|
|
100
|
+
const sourceModel = this.models.find(m => m.relations.some(r => r.field === relation.field && r.target === relation.target));
|
|
101
|
+
if (sourceModel) {
|
|
102
|
+
const fkField = sourceModel.fields.find(f => f.name === relation.foreignKey);
|
|
103
|
+
if (fkField && fkField.isRequired) {
|
|
104
|
+
throw new SchemaValidationError(`onDelete: SetNull on relation '${relation.field}' -> '${relation.target}' requires a nullable foreign key field. ` +
|
|
105
|
+
`Field '${relation.foreignKey}' in '${sourceModel.name}' is required.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Validate lookup strategy requirements
|
|
110
|
+
if (relation.strategy === 'lookup') {
|
|
111
|
+
if (relation.type === 'manyToMany') {
|
|
112
|
+
// For manyToMany, foreign key or join collection is required for lookup
|
|
113
|
+
if (!relation.foreignKey && !relation.joinCollection) {
|
|
114
|
+
throw new SchemaValidationError(`Lookup strategy for manyToMany relation '${relation.field}' -> '${relation.target}' requires either a foreign key field or join collection. ` +
|
|
115
|
+
`Add @relation(field: "...") directive with a foreign key field.`);
|
|
116
|
+
}
|
|
117
|
+
// lookup is now implemented for manyToMany with foreign key (array of IDs)
|
|
118
|
+
// and for join collection via RelationResolver
|
|
119
|
+
}
|
|
120
|
+
else if (!relation.foreignKey) {
|
|
121
|
+
// For other relation types (oneToMany, manyToOne, oneToOne), foreign key is required
|
|
122
|
+
throw new SchemaValidationError(`Lookup strategy requires a foreign key field for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
123
|
+
`Add @relation(field: "...") directive with a foreign key field.`);
|
|
124
|
+
}
|
|
125
|
+
// Warn about manual array synchronization requirement
|
|
126
|
+
const fkMsg = relation.foreignKey ? `(e.g., ${relation.foreignKey})` : '';
|
|
127
|
+
console.warn(`⚠️ Lookup strategy selected for relation '${relation.field}' -> '${relation.target}'. ` +
|
|
128
|
+
`Note: You must manually synchronize ID arrays ${fkMsg} when creating/updating/deleting related documents.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=SchemaRelationValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaRelationValidator.js","sourceRoot":"","sources":["../../src/engine/SchemaRelationValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,7 @@ export declare class SchemaValidator {
|
|
|
19
19
|
* Check if a field is a foreign key field (referenced by a relation)
|
|
20
20
|
*/
|
|
21
21
|
private isForeignKeyField;
|
|
22
|
+
private relationValidator;
|
|
22
23
|
/**
|
|
23
24
|
* Validate the entire schema
|
|
24
25
|
*/
|
|
@@ -43,26 +44,26 @@ export declare class SchemaValidator {
|
|
|
43
44
|
* Validate directives on a specific field
|
|
44
45
|
*/
|
|
45
46
|
private validateFieldDirectives;
|
|
46
|
-
/**
|
|
47
|
-
* Validate relations between models
|
|
48
|
-
*/
|
|
49
|
-
private validateRelations;
|
|
50
47
|
/**
|
|
51
48
|
* Check for circular dependencies between models
|
|
52
49
|
*/
|
|
53
50
|
private checkCircularDependencies;
|
|
54
|
-
/**
|
|
55
|
-
* Validate that required fields have values
|
|
56
|
-
*/
|
|
57
|
-
private validateRequiredFields;
|
|
58
51
|
/**
|
|
59
52
|
* Validate enum values
|
|
60
53
|
*/
|
|
61
54
|
private validateEnumValues;
|
|
62
55
|
/**
|
|
63
|
-
* Validate
|
|
56
|
+
* Validate embedded model usage
|
|
57
|
+
*/
|
|
58
|
+
private validateEmbeddedModels;
|
|
59
|
+
/**
|
|
60
|
+
* Validate model indexes (compound directive fields must exist)
|
|
61
|
+
*/
|
|
62
|
+
private validateIndexes;
|
|
63
|
+
/**
|
|
64
|
+
* Validate @default value types match the field type
|
|
64
65
|
*/
|
|
65
|
-
private
|
|
66
|
+
private validateDefaultValues;
|
|
66
67
|
/**
|
|
67
68
|
* Get validation warnings (non-critical issues)
|
|
68
69
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaValidator.d.ts","sourceRoot":"","sources":["../../src/engine/SchemaValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAY5B,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SchemaValidator.d.ts","sourceRoot":"","sources":["../../src/engine/SchemaValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAY5B,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,oBAAoB,CAIzB;gBAGD,MAAM,EAAE,YAAY,EAAE,EACtB,KAAK,EAAE,WAAW,EAAE,EACpB,SAAS,EAAE,aAAa,EAAE;IAQ5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,iBAAiB,CAA2B;IAEpD;;OAEG;IACH,QAAQ,CAAC,OAAO,GAAE,iBAAsB,GAAG,IAAI;IAoC/C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiC1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAsC1B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA6B/B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiEjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAsB1B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA+D7B;;OAEG;IACH,WAAW,IAAI,MAAM,EAAE;CA0BxB"}
|