@reldens/storage 0.81.0 → 0.82.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/CLAUDE.md +125 -3
- package/bin/reldens-storage.js +63 -8
- package/lib/entities-generator.js +4 -3
- package/lib/generators/models-generation.js +161 -8
- package/lib/prisma/prisma-data-server.js +38 -4
- package/lib/prisma/prisma-driver.js +216 -368
- package/lib/prisma/prisma-filter-processor.js +146 -0
- package/lib/prisma/prisma-metadata-loader.js +7 -0
- package/lib/prisma/prisma-query-builder.js +42 -0
- package/lib/prisma/prisma-relation-resolver.js +168 -168
- package/lib/prisma/prisma-schema-generator.js +40 -33
- package/lib/prisma/prisma-type-caster.js +29 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - PrismaFilterProcessor
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class PrismaFilterProcessor
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.typeCaster = sc.get(props, 'typeCaster', null);
|
|
15
|
+
this.fieldTypes = sc.get(props, 'fieldTypes', {});
|
|
16
|
+
this.referenceFields = sc.get(props, 'referenceFields', {});
|
|
17
|
+
this.jsonFields = sc.get(props, 'jsonFields', new Set());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
updateMetadata(metadata)
|
|
21
|
+
{
|
|
22
|
+
this.fieldTypes = sc.get(metadata, 'fieldTypes', this.fieldTypes);
|
|
23
|
+
this.referenceFields = sc.get(metadata, 'referenceFields', this.referenceFields);
|
|
24
|
+
this.jsonFields = sc.get(metadata, 'jsonFields', this.jsonFields);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
processFilters(filters)
|
|
28
|
+
{
|
|
29
|
+
if(!sc.isObject(filters)){
|
|
30
|
+
return filters;
|
|
31
|
+
}
|
|
32
|
+
let processedFilters = {};
|
|
33
|
+
for(let key of Object.keys(filters)){
|
|
34
|
+
let value = filters[key];
|
|
35
|
+
if('OR' === key && sc.isArray(value)){
|
|
36
|
+
processedFilters.OR = value.map(condition => this.processFilters(condition));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if(sc.hasOwn(value, 'operator') && sc.hasOwn(value, 'value')){
|
|
40
|
+
let operatorValue = this.processFilterValue(value.value, key);
|
|
41
|
+
processedFilters[key] = this.applyOperator(operatorValue, value.operator, key);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if(sc.isObject(value) && !sc.isArray(value)){
|
|
45
|
+
processedFilters[key] = this.processFilters(value);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
processedFilters[key] = this.processFilterValue(value, key);
|
|
49
|
+
}
|
|
50
|
+
return processedFilters;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
processFilterValue(value, key)
|
|
54
|
+
{
|
|
55
|
+
if(sc.isArray(value)){
|
|
56
|
+
if('id' === key){
|
|
57
|
+
return value.map(id => this.typeCaster.castToIdType(id)).filter(id => null !== id);
|
|
58
|
+
}
|
|
59
|
+
let fieldType = this.fieldTypes[key];
|
|
60
|
+
if(fieldType){
|
|
61
|
+
return value.map(val => this.typeCaster.castValue(val, fieldType, key))
|
|
62
|
+
.filter(val => this.typeCaster.isValidCastedValue(val));
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if('id' === key){
|
|
67
|
+
return this.typeCaster.castToIdType(value);
|
|
68
|
+
}
|
|
69
|
+
let fieldType = this.fieldTypes[key];
|
|
70
|
+
if(!fieldType){
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
let castedValue = this.typeCaster.castValue(value, fieldType, key);
|
|
74
|
+
if(this.typeCaster.isValidCastedValue(castedValue)){
|
|
75
|
+
return castedValue;
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
applyOperator(value, operator, fieldName = null)
|
|
81
|
+
{
|
|
82
|
+
let upperOperator = operator ? operator.toUpperCase() : '';
|
|
83
|
+
if('LIKE' === upperOperator){
|
|
84
|
+
return this.handleLikeOperator(value, fieldName);
|
|
85
|
+
}
|
|
86
|
+
let operatorsMap = {
|
|
87
|
+
'=': value,
|
|
88
|
+
'!=': {not: value},
|
|
89
|
+
'>': {gt: value},
|
|
90
|
+
'>=': {gte: value},
|
|
91
|
+
'<': {lt: value},
|
|
92
|
+
'<=': {lte: value},
|
|
93
|
+
'IN': {in: value},
|
|
94
|
+
'NOT IN': {notIn: value}
|
|
95
|
+
};
|
|
96
|
+
return operatorsMap[upperOperator] || value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
handleLikeOperator(value, fieldName)
|
|
100
|
+
{
|
|
101
|
+
let cleanValue = String(value).replace(/%/g, '');
|
|
102
|
+
if(this.isJsonField(fieldName)){
|
|
103
|
+
return this.handleJsonTextSearch(cleanValue);
|
|
104
|
+
}
|
|
105
|
+
if('id' === fieldName || sc.hasOwn(this.referenceFields, fieldName)){
|
|
106
|
+
let numericValue = Number(cleanValue);
|
|
107
|
+
if(!isNaN(numericValue)){
|
|
108
|
+
return numericValue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return {contains: cleanValue};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
handleJsonTextSearch(searchValue)
|
|
115
|
+
{
|
|
116
|
+
return {
|
|
117
|
+
string_contains: searchValue
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
isJsonField(fieldName)
|
|
122
|
+
{
|
|
123
|
+
if(!this.jsonFields){
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if(this.jsonFields.has(fieldName)){
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return this.typeCaster && this.typeCaster.isJsonFieldByName(fieldName);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
createSingleFilter(field, fieldValue, operator = null)
|
|
133
|
+
{
|
|
134
|
+
let filter = {};
|
|
135
|
+
let processedValue = this.processFilterValue(fieldValue, field);
|
|
136
|
+
if(null === operator){
|
|
137
|
+
filter[field] = processedValue;
|
|
138
|
+
return filter;
|
|
139
|
+
}
|
|
140
|
+
filter[field] = {operator, value: processedValue};
|
|
141
|
+
return this.processFilters(filter);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports.PrismaFilterProcessor = PrismaFilterProcessor;
|
|
@@ -57,9 +57,11 @@ class PrismaMetadataLoader
|
|
|
57
57
|
fieldTypes: {},
|
|
58
58
|
fieldDefaults: {},
|
|
59
59
|
idFieldType: 'String',
|
|
60
|
+
idFieldName: 'id',
|
|
60
61
|
referenceFields: {},
|
|
61
62
|
relationMetadata: {},
|
|
62
63
|
foreignKeyMappings: {},
|
|
64
|
+
foreignKeyTargetFields: {},
|
|
63
65
|
jsonFields: new Set()
|
|
64
66
|
};
|
|
65
67
|
for(let field of modelInfo.fields){
|
|
@@ -83,6 +85,7 @@ class PrismaMetadataLoader
|
|
|
83
85
|
}
|
|
84
86
|
if(field.isId){
|
|
85
87
|
metadata.idFieldType = field.type;
|
|
88
|
+
metadata.idFieldName = field.name;
|
|
86
89
|
}
|
|
87
90
|
if(field.hasDefaultValue){
|
|
88
91
|
metadata.fieldDefaults[field.name] = field.default;
|
|
@@ -110,8 +113,12 @@ class PrismaMetadataLoader
|
|
|
110
113
|
};
|
|
111
114
|
}
|
|
112
115
|
if('object' === field.kind && sc.hasOwn(field, 'relationFromFields') && sc.isArray(field.relationFromFields)){
|
|
116
|
+
let relationToFields = sc.get(field, 'relationToFields', []);
|
|
117
|
+
let index = 0;
|
|
113
118
|
for(let foreignKeyField of field.relationFromFields){
|
|
114
119
|
metadata.foreignKeyMappings[foreignKeyField] = field.name;
|
|
120
|
+
metadata.foreignKeyTargetFields[foreignKeyField] = relationToFields[index] || 'id';
|
|
121
|
+
index++;
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - PrismaQueryBuilder
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class PrismaQueryBuilder
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
buildQueryOptions(options, useLimit = true)
|
|
13
|
+
{
|
|
14
|
+
let select = sc.get(options, 'select', []);
|
|
15
|
+
let limit = sc.get(options, 'limit', 0);
|
|
16
|
+
let offset = sc.get(options, 'offset', 0);
|
|
17
|
+
let sortBy = sc.get(options, 'sortBy', false);
|
|
18
|
+
let sortDirection = sc.get(options, 'sortDirection', 'ASC');
|
|
19
|
+
let queryOptions = {};
|
|
20
|
+
if(0 < select.length){
|
|
21
|
+
queryOptions.select = {};
|
|
22
|
+
for(let field of select){
|
|
23
|
+
queryOptions.select[field] = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if(useLimit && 0 !== limit){
|
|
27
|
+
queryOptions.take = limit;
|
|
28
|
+
}
|
|
29
|
+
if(0 !== offset){
|
|
30
|
+
queryOptions.skip = offset;
|
|
31
|
+
}
|
|
32
|
+
if(false !== sortBy && false !== sortDirection){
|
|
33
|
+
queryOptions.orderBy = {
|
|
34
|
+
[sortBy]: sortDirection.toLowerCase()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return queryOptions;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports.PrismaQueryBuilder = PrismaQueryBuilder;
|
|
@@ -12,61 +12,36 @@ class PrismaRelationResolver
|
|
|
12
12
|
constructor(props)
|
|
13
13
|
{
|
|
14
14
|
this.relationMetadata = sc.get(props, 'relationMetadata', {});
|
|
15
|
-
this.relationAliases = sc.get(props, 'relationAliases', {});
|
|
16
15
|
this.metadataLoader = sc.get(props, 'metadataLoader', null);
|
|
16
|
+
this.allRelationMappings = sc.get(props, 'allRelationMappings', {});
|
|
17
|
+
this.foreignKeyMappings = sc.get(props, 'foreignKeyMappings', {});
|
|
18
|
+
this.foreignKeyTargetFields = sc.get(props, 'foreignKeyTargetFields', {});
|
|
19
|
+
this.typeCaster = sc.get(props, 'typeCaster', null);
|
|
20
|
+
this.currentModelMappings = {};
|
|
21
|
+
this.reverseModelMappings = {};
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
updateMetadata(metadata)
|
|
20
25
|
{
|
|
21
26
|
this.relationMetadata = sc.get(metadata, 'relationMetadata', this.relationMetadata);
|
|
22
|
-
this.
|
|
27
|
+
this.foreignKeyMappings = sc.get(metadata, 'foreignKeyMappings', this.foreignKeyMappings);
|
|
28
|
+
this.foreignKeyTargetFields = sc.get(metadata, 'foreignKeyTargetFields', this.foreignKeyTargetFields);
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
setCurrentModelMappings(mappings)
|
|
26
32
|
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let meta = this.relationMetadata[prismaRelation];
|
|
30
|
-
let relatedModel = meta.model.toLowerCase();
|
|
31
|
-
let aliases = this.generateRelationAliases(prismaRelation, relatedModel, normalizedTableName);
|
|
32
|
-
for(let alias of aliases){
|
|
33
|
-
this.relationAliases[alias] = prismaRelation;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return this.relationAliases;
|
|
33
|
+
this.currentModelMappings = mappings || {};
|
|
34
|
+
this.reverseModelMappings = this.buildReverseMappings(this.currentModelMappings);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
buildReverseMappings(mappings)
|
|
40
38
|
{
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if(fkHint){
|
|
46
|
-
aliases.push('related_'+relatedModel+'_'+fkHint);
|
|
47
|
-
aliases.push(relatedModel+'_'+fkHint);
|
|
39
|
+
let reverse = {};
|
|
40
|
+
for(let reldensName of Object.keys(mappings)){
|
|
41
|
+
let prismaName = mappings[reldensName];
|
|
42
|
+
reverse[prismaName] = reldensName;
|
|
48
43
|
}
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
extractForeignKeyHint(prismaRelation, relatedModel, tableName)
|
|
53
|
-
{
|
|
54
|
-
let toSuffix = 'To'+tableName;
|
|
55
|
-
if(!prismaRelation.toLowerCase().endsWith(toSuffix.toLowerCase())){
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
let withoutToSuffix = prismaRelation.slice(0, -toSuffix.length);
|
|
59
|
-
let prefix = relatedModel+'_';
|
|
60
|
-
if(withoutToSuffix.toLowerCase().startsWith(prefix.toLowerCase())){
|
|
61
|
-
withoutToSuffix = withoutToSuffix.slice(prefix.length);
|
|
62
|
-
if(withoutToSuffix.toLowerCase().startsWith(prefix.toLowerCase())){
|
|
63
|
-
withoutToSuffix = withoutToSuffix.slice(prefix.length);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if(withoutToSuffix.endsWith('_id')){
|
|
67
|
-
return withoutToSuffix.slice(0, -3);
|
|
68
|
-
}
|
|
69
|
-
return withoutToSuffix;
|
|
44
|
+
return reverse;
|
|
70
45
|
}
|
|
71
46
|
|
|
72
47
|
getAllRelations()
|
|
@@ -74,151 +49,148 @@ class PrismaRelationResolver
|
|
|
74
49
|
return Object.keys(this.relationMetadata || {});
|
|
75
50
|
}
|
|
76
51
|
|
|
77
|
-
|
|
52
|
+
mapToPrismaName(reldensName, modelName)
|
|
78
53
|
{
|
|
79
|
-
if(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if(sc.hasOwn(this.relationAliases, relationName)){
|
|
83
|
-
return this.relationAliases[relationName];
|
|
84
|
-
}
|
|
85
|
-
if(relationName.startsWith('related_')){
|
|
86
|
-
let withoutPrefix = relationName.substring(8);
|
|
87
|
-
if(sc.hasOwn(this.relationMetadata, withoutPrefix)){
|
|
88
|
-
return withoutPrefix;
|
|
54
|
+
if(!modelName){
|
|
55
|
+
if(sc.hasOwn(this.relationMetadata, reldensName)){
|
|
56
|
+
return reldensName;
|
|
89
57
|
}
|
|
90
|
-
if(sc.hasOwn(this.
|
|
91
|
-
return this.
|
|
58
|
+
if(sc.hasOwn(this.currentModelMappings, reldensName)){
|
|
59
|
+
return this.currentModelMappings[reldensName];
|
|
92
60
|
}
|
|
61
|
+
return null;
|
|
93
62
|
}
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return availableRelation;
|
|
98
|
-
}
|
|
99
|
-
if(availableRelation.endsWith(relationName.replace('related_', ''))){
|
|
100
|
-
return availableRelation;
|
|
101
|
-
}
|
|
63
|
+
let modelMappings = sc.get(this.allRelationMappings, modelName.toLowerCase(), {});
|
|
64
|
+
if(sc.hasOwn(modelMappings, reldensName)){
|
|
65
|
+
return modelMappings[reldensName];
|
|
102
66
|
}
|
|
103
|
-
return
|
|
67
|
+
return null;
|
|
104
68
|
}
|
|
105
69
|
|
|
106
|
-
|
|
70
|
+
mapToReldensName(prismaName)
|
|
107
71
|
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
for(let relation of relations){
|
|
111
|
-
if(-1 !== relation.indexOf('.')){
|
|
112
|
-
this.buildNestedInclude(relation, include, mapping);
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
let normalizedRelation = this.normalizeRelationName(relation);
|
|
116
|
-
if(!sc.hasOwn(this.relationMetadata, normalizedRelation)){
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
include[normalizedRelation] = true;
|
|
120
|
-
if(relation !== normalizedRelation){
|
|
121
|
-
mapping[normalizedRelation] = relation;
|
|
122
|
-
}
|
|
72
|
+
if(sc.hasOwn(this.reverseModelMappings, prismaName)){
|
|
73
|
+
return this.reverseModelMappings[prismaName];
|
|
123
74
|
}
|
|
124
|
-
return
|
|
75
|
+
return prismaName;
|
|
125
76
|
}
|
|
126
77
|
|
|
127
|
-
|
|
78
|
+
getRelatedModelName(prismaName, fromModelName)
|
|
128
79
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if(!sc.hasOwn(include, normalizedRoot) || true === include[normalizedRoot]){
|
|
136
|
-
include[normalizedRoot] = {include: {}};
|
|
137
|
-
}
|
|
138
|
-
if(rootPart !== normalizedRoot){
|
|
139
|
-
mapping[normalizedRoot] = rootPart;
|
|
140
|
-
}
|
|
141
|
-
if(0 === parts.length){
|
|
142
|
-
return;
|
|
80
|
+
if(!fromModelName){
|
|
81
|
+
let meta = sc.get(this.relationMetadata, prismaName, null);
|
|
82
|
+
if(meta){
|
|
83
|
+
return meta.model;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
143
86
|
}
|
|
144
|
-
let nestedPath = parts.join('.');
|
|
145
|
-
let relatedModel = this.relationMetadata[normalizedRoot].model;
|
|
146
|
-
this.buildNestedIncludeForModel(nestedPath, include[normalizedRoot].include, mapping, relatedModel);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
buildNestedIncludeForModel(relationPath, include, mapping, modelName)
|
|
150
|
-
{
|
|
151
87
|
if(!this.metadataLoader){
|
|
152
|
-
return;
|
|
88
|
+
return null;
|
|
153
89
|
}
|
|
154
90
|
let dmmf = this.metadataLoader.getDmmf();
|
|
155
91
|
if(!dmmf){
|
|
156
|
-
return;
|
|
92
|
+
return null;
|
|
157
93
|
}
|
|
158
|
-
let modelInfo =
|
|
159
|
-
|| dmmf.models?.find(m => m.name.toLowerCase() === modelName.toLowerCase());
|
|
94
|
+
let modelInfo = this.findModelInDmmf(dmmf, fromModelName);
|
|
160
95
|
if(!modelInfo){
|
|
161
|
-
return;
|
|
96
|
+
return null;
|
|
162
97
|
}
|
|
163
|
-
let relationFields = {};
|
|
164
|
-
let tableName = modelName.toLowerCase();
|
|
165
98
|
for(let field of modelInfo.fields){
|
|
166
|
-
if('object' === field.kind){
|
|
167
|
-
|
|
168
|
-
model: field.type,
|
|
169
|
-
isList: field.isList
|
|
170
|
-
};
|
|
99
|
+
if(field.name === prismaName && 'object' === field.kind){
|
|
100
|
+
return field.type;
|
|
171
101
|
}
|
|
172
102
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
findModelInDmmf(dmmf, modelName)
|
|
107
|
+
{
|
|
108
|
+
let lowerName = modelName.toLowerCase();
|
|
109
|
+
if(sc.hasOwn(dmmf.models, lowerName)){
|
|
110
|
+
return dmmf.models[lowerName];
|
|
178
111
|
}
|
|
179
|
-
if(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
112
|
+
if(sc.isArray(dmmf.models)){
|
|
113
|
+
for(let model of dmmf.models){
|
|
114
|
+
if(model.name.toLowerCase() === lowerName){
|
|
115
|
+
return model;
|
|
116
|
+
}
|
|
183
117
|
}
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
if(!sc.hasOwn(include, normalizedPart) || true === include[normalizedPart]){
|
|
187
|
-
include[normalizedPart] = {include: {}};
|
|
188
|
-
}
|
|
189
|
-
if(currentPart !== normalizedPart){
|
|
190
|
-
mapping[normalizedPart] = currentPart;
|
|
191
118
|
}
|
|
192
|
-
|
|
193
|
-
let nestedModel = relationFields[normalizedPart].model;
|
|
194
|
-
this.buildNestedIncludeForModel(nestedPath, include[normalizedPart].include, mapping, nestedModel);
|
|
119
|
+
return null;
|
|
195
120
|
}
|
|
196
121
|
|
|
197
|
-
|
|
122
|
+
convertForeignKeysToRelations(params, isCreate = false)
|
|
198
123
|
{
|
|
199
|
-
|
|
200
|
-
|
|
124
|
+
let data = {};
|
|
125
|
+
let relations = {};
|
|
126
|
+
for(let key of Object.keys(params)){
|
|
127
|
+
if(!sc.hasOwn(this.foreignKeyMappings, key)){
|
|
128
|
+
data[key] = params[key];
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
let relationName = this.foreignKeyMappings[key];
|
|
132
|
+
let value = params[key];
|
|
133
|
+
let targetField = sc.get(this.foreignKeyTargetFields, key, 'id');
|
|
134
|
+
if(!this.typeCaster){
|
|
135
|
+
relations[relationName] = {connect: {[targetField]: value}};
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if(this.typeCaster.isNullOrEmpty(value)){
|
|
139
|
+
if(isCreate){
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
relations[relationName] = {disconnect: true};
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
let fieldType = sc.get(this.typeCaster.fieldTypes, key, null);
|
|
146
|
+
let connectValue = fieldType
|
|
147
|
+
? this.typeCaster.castValue(value, fieldType, key)
|
|
148
|
+
: this.typeCaster.castToIdType(value);
|
|
149
|
+
relations[relationName] = {
|
|
150
|
+
connect: {[targetField]: connectValue}
|
|
151
|
+
};
|
|
201
152
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
153
|
+
return {...data, ...relations};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
buildIncludeObjectWithMapping(relations)
|
|
157
|
+
{
|
|
158
|
+
let include = {};
|
|
159
|
+
let mapping = {};
|
|
160
|
+
for(let relation of relations){
|
|
161
|
+
this.processRelationPath(relation, include, mapping);
|
|
205
162
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
163
|
+
return {include, mapping};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
processRelationPath(relationPath, include, mapping)
|
|
167
|
+
{
|
|
168
|
+
let parts = relationPath.split('.');
|
|
169
|
+
let currentInclude = include;
|
|
170
|
+
let currentModelName = null;
|
|
171
|
+
for(let i = 0; i < parts.length; i++){
|
|
172
|
+
let reldensName = parts[i];
|
|
173
|
+
let prismaName = this.mapToPrismaName(reldensName, currentModelName);
|
|
174
|
+
if(!prismaName){
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if(reldensName !== prismaName){
|
|
178
|
+
mapping[prismaName] = reldensName;
|
|
179
|
+
}
|
|
180
|
+
let isLastPart = (i === parts.length - 1);
|
|
181
|
+
if(isLastPart){
|
|
182
|
+
currentInclude[prismaName] = true;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if(!sc.hasOwn(currentInclude, prismaName) || true === currentInclude[prismaName]){
|
|
186
|
+
currentInclude[prismaName] = {include: {}};
|
|
187
|
+
}
|
|
188
|
+
currentModelName = this.getRelatedModelName(prismaName, currentModelName);
|
|
189
|
+
if(!currentModelName){
|
|
190
|
+
return;
|
|
219
191
|
}
|
|
192
|
+
currentInclude = currentInclude[prismaName].include;
|
|
220
193
|
}
|
|
221
|
-
return null;
|
|
222
194
|
}
|
|
223
195
|
|
|
224
196
|
transformRelationResults(result, includeConfig, relationMapping)
|
|
@@ -238,28 +210,56 @@ class PrismaRelationResolver
|
|
|
238
210
|
return item;
|
|
239
211
|
}
|
|
240
212
|
let transformed = {...item};
|
|
241
|
-
for(let
|
|
242
|
-
if(!sc.hasOwn(transformed,
|
|
213
|
+
for(let prismaName of Object.keys(includeConfig)){
|
|
214
|
+
if(!sc.hasOwn(transformed, prismaName)){
|
|
243
215
|
continue;
|
|
244
216
|
}
|
|
245
|
-
let
|
|
246
|
-
|
|
217
|
+
let relationValue = transformed[prismaName];
|
|
218
|
+
let nestedConfig = includeConfig[prismaName];
|
|
219
|
+
if(sc.isObject(nestedConfig) && sc.hasOwn(nestedConfig, 'include')){
|
|
220
|
+
relationValue = this.transformRelationResults(relationValue, nestedConfig.include, relationMapping);
|
|
221
|
+
}
|
|
222
|
+
let reldensName = sc.get(relationMapping, prismaName, null);
|
|
223
|
+
if(!reldensName){
|
|
224
|
+
reldensName = this.mapToReldensName(prismaName);
|
|
225
|
+
}
|
|
226
|
+
transformed[reldensName] = relationValue;
|
|
227
|
+
if(reldensName !== prismaName){
|
|
228
|
+
delete transformed[prismaName];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return transformed;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
buildCreateDataWithRelations(params, relations)
|
|
235
|
+
{
|
|
236
|
+
let createData = {};
|
|
237
|
+
for(let relation of relations){
|
|
238
|
+
let prismaName = this.mapToPrismaName(relation, null);
|
|
239
|
+
if(!prismaName){
|
|
247
240
|
continue;
|
|
248
241
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
relationValue = 0 < relationValue.length ? [...relationValue].shift() : null;
|
|
242
|
+
if(!sc.hasOwn(params, relation)){
|
|
243
|
+
continue;
|
|
252
244
|
}
|
|
253
|
-
|
|
254
|
-
|
|
245
|
+
let relationData = params[relation];
|
|
246
|
+
if(!this.typeCaster){
|
|
247
|
+
createData[prismaName] = sc.isArray(relationData)
|
|
248
|
+
? {connect: relationData.map(item => ({id: item.id}))}
|
|
249
|
+
: {connect: {id: relationData.id}};
|
|
250
|
+
continue;
|
|
255
251
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
252
|
+
if(sc.isArray(relationData)){
|
|
253
|
+
createData[prismaName] = {
|
|
254
|
+
connect: relationData.map(item => ({id: this.typeCaster.castToIdType(item.id)}))
|
|
255
|
+
};
|
|
256
|
+
continue;
|
|
260
257
|
}
|
|
258
|
+
createData[prismaName] = {
|
|
259
|
+
connect: {id: this.typeCaster.castToIdType(relationData.id)}
|
|
260
|
+
};
|
|
261
261
|
}
|
|
262
|
-
return
|
|
262
|
+
return createData;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
}
|