prisma-ts-select 0.0.33
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 +725 -0
- package/assets/groupBy.gif +0 -0
- package/assets/joinUnsafeIgnoreType.gif +0 -0
- package/assets/joinUnsafeTypeEnforced.gif +0 -0
- package/assets/typesafe-join.gif +0 -0
- package/assets/typesafe-join.png +0 -0
- package/assets/whereNotNull.gif +0 -0
- package/assets/whereisNull.gif +0 -0
- package/built/extend.cjs +565 -0
- package/built/extend.d.cts +451 -0
- package/built/extend.d.ts +451 -0
- package/built/extend.js +563 -0
- package/dist/bin.cjs +5 -0
- package/dist/bin.d.cts +1 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +2 -0
- package/dist/chunk-G66FOFCO.cjs +195 -0
- package/dist/chunk-GBXPF5FT.js +187 -0
- package/dist/extend/extend.cjs +277 -0
- package/dist/extend/extend.d.cts +222 -0
- package/dist/extend/extend.d.ts +222 -0
- package/dist/extend/extend.js +275 -0
- package/dist/generator.cjs +4 -0
- package/dist/generator.d.cts +2 -0
- package/dist/generator.d.ts +2 -0
- package/dist/generator.js +1 -0
- package/package.json +170 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var generatorHelper = require('@prisma/generator-helper');
|
|
4
|
+
var internals = require('@prisma/internals');
|
|
5
|
+
var path2 = require('path');
|
|
6
|
+
var fs2 = require('fs');
|
|
7
|
+
var module$1 = require('module');
|
|
8
|
+
|
|
9
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
13
|
+
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
14
|
+
|
|
15
|
+
// src/generator.ts
|
|
16
|
+
|
|
17
|
+
// src/constants.ts
|
|
18
|
+
var GENERATOR_NAME = "prisma-ts-select";
|
|
19
|
+
function writeFileSafely(writeLocation, content) {
|
|
20
|
+
fs2__default.default.mkdirSync(path2__default.default.dirname(writeLocation), {
|
|
21
|
+
recursive: true
|
|
22
|
+
});
|
|
23
|
+
fs2__default.default.writeFileSync(writeLocation, content);
|
|
24
|
+
}
|
|
25
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('out.js', document.baseURI).href)));
|
|
26
|
+
var SupportedProviders = {
|
|
27
|
+
sqlite: true,
|
|
28
|
+
mysql: true,
|
|
29
|
+
postgresql: true,
|
|
30
|
+
cockroachdb: false,
|
|
31
|
+
mongodb: false,
|
|
32
|
+
postgres: false,
|
|
33
|
+
sqlserver: false
|
|
34
|
+
};
|
|
35
|
+
generatorHelper.generatorHandler({
|
|
36
|
+
onManifest() {
|
|
37
|
+
internals.logger.info(`${GENERATOR_NAME}:Registered`);
|
|
38
|
+
return {
|
|
39
|
+
defaultOutput: "../generated",
|
|
40
|
+
prettyName: GENERATOR_NAME
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
onGenerate: async (options) => {
|
|
44
|
+
const validDS = options.datasources.map((ds) => ds.provider).filter((type) => SupportedProviders[type]);
|
|
45
|
+
if (validDS.length === 0) {
|
|
46
|
+
throw new Error(`${GENERATOR_NAME}: Supported DataSource Providers are: ${Object.entries(SupportedProviders).reduce((acc, [name, supported]) => {
|
|
47
|
+
if (!supported) return acc;
|
|
48
|
+
acc.push(name);
|
|
49
|
+
return acc;
|
|
50
|
+
}, []).join(", ")}`);
|
|
51
|
+
}
|
|
52
|
+
const modelToId = {};
|
|
53
|
+
const models = options.dmmf.datamodel.models.reduce((acc, model) => {
|
|
54
|
+
const modelObj = acc[model.name] = acc[model.name] ?? {
|
|
55
|
+
fields: {},
|
|
56
|
+
relations: {}
|
|
57
|
+
};
|
|
58
|
+
for (const field of model.fields) {
|
|
59
|
+
if (field.kind !== "object") {
|
|
60
|
+
if (field.isId) modelToId[model.name] = [field.name, field.type];
|
|
61
|
+
modelObj.fields = modelObj.fields ?? {};
|
|
62
|
+
modelObj.fields[field.name] = (!field.isRequired ? "?" : "") + field.type;
|
|
63
|
+
} else {
|
|
64
|
+
if (field.relationFromFields && field.relationFromFields.length > 0 && (field.relationToFields && field.relationToFields.length > 0)) {
|
|
65
|
+
const fieldObj = modelObj.relations[field.type] = modelObj.relations[field.type] ?? {};
|
|
66
|
+
field.relationFromFields.forEach((relationFromField, i) => {
|
|
67
|
+
if (!field.relationToFields) return;
|
|
68
|
+
const relationToField = field.relationToFields[i];
|
|
69
|
+
if (!relationToField) return;
|
|
70
|
+
fieldObj[relationFromField] = fieldObj[relationFromField] || [];
|
|
71
|
+
fieldObj[relationFromField].push(relationToField);
|
|
72
|
+
const accModel = acc[field.type] = acc[field.type] ?? {};
|
|
73
|
+
const accModelRelations = accModel.relations = accModel.relations ?? {};
|
|
74
|
+
const accModelRelationToModel = accModelRelations[model.name] = accModelRelations[model.name] ?? {};
|
|
75
|
+
const relationFromFieldList = accModelRelationToModel[relationToField] = accModelRelationToModel[relationToField] ?? [];
|
|
76
|
+
relationFromFieldList.push(relationFromField);
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
if (!isManyToManyRelationShip(field)) continue;
|
|
80
|
+
debugger;
|
|
81
|
+
const joinTableName = "_" + field.relationName;
|
|
82
|
+
const joinTableModel = acc[joinTableName] = acc[joinTableName] ?? {
|
|
83
|
+
fields: {
|
|
84
|
+
"A": "",
|
|
85
|
+
"B": ""
|
|
86
|
+
},
|
|
87
|
+
relations: {}
|
|
88
|
+
};
|
|
89
|
+
const abJoin = [field.type, model.name].toSorted().indexOf(model.name) === 0 ? "A" : "B";
|
|
90
|
+
const [idName, idType] = getModelId(model.name);
|
|
91
|
+
joinTableModel.fields[abJoin] = idType;
|
|
92
|
+
{
|
|
93
|
+
const mr = joinTableModel.relations[model.name] = joinTableModel.relations[model.name] ?? {};
|
|
94
|
+
const mrt = mr[abJoin] = mr[abJoin] ?? [];
|
|
95
|
+
mrt.push(idName);
|
|
96
|
+
}
|
|
97
|
+
const m = modelObj.relations[joinTableName] = modelObj.relations[joinTableName] ?? {};
|
|
98
|
+
const mf = m[idName] = m[idName] ?? [];
|
|
99
|
+
mf.push(abJoin);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return acc;
|
|
104
|
+
}, {});
|
|
105
|
+
const pTSSelPath = path2__default.default.dirname(require2.resolve("prisma-ts-select"));
|
|
106
|
+
internals.logger.info("pTSSelPath", pTSSelPath);
|
|
107
|
+
const srcDir = path2__default.default.join(pTSSelPath, "extend");
|
|
108
|
+
const outDir = path2__default.default.join(pTSSelPath, "..", "built");
|
|
109
|
+
{
|
|
110
|
+
const file = "extend.js";
|
|
111
|
+
const contents = fs2__default.default.readFileSync(path2__default.default.join(srcDir, file), { encoding: "utf-8" });
|
|
112
|
+
writeFileSafely(
|
|
113
|
+
path2__default.default.join(outDir, file),
|
|
114
|
+
contents.replace(
|
|
115
|
+
"const DB = {};",
|
|
116
|
+
`const DB = ${JSON.stringify(models, null, 2)};`
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
{
|
|
121
|
+
const file = "extend.cjs";
|
|
122
|
+
const contents = fs2__default.default.readFileSync(path2__default.default.join(srcDir, file), { encoding: "utf-8" });
|
|
123
|
+
writeFileSafely(
|
|
124
|
+
path2__default.default.join(outDir, file),
|
|
125
|
+
contents.replace(
|
|
126
|
+
"const DB = {};",
|
|
127
|
+
`const DB = ${JSON.stringify(models, null, 2)};`
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const declaration = generateReadonlyDeclaration(models);
|
|
132
|
+
{
|
|
133
|
+
const file = "extend.d.ts";
|
|
134
|
+
const contents = fs2__default.default.readFileSync(path2__default.default.join(srcDir, file), { encoding: "utf-8" });
|
|
135
|
+
writeFileSafely(
|
|
136
|
+
path2__default.default.join(outDir, file),
|
|
137
|
+
contents.replace("declare const DB: DBType;", declaration)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
{
|
|
141
|
+
const file = "extend.d.cts";
|
|
142
|
+
const contents = fs2__default.default.readFileSync(path2__default.default.join(srcDir, file), { encoding: "utf-8" });
|
|
143
|
+
writeFileSafely(
|
|
144
|
+
path2__default.default.join(outDir, file),
|
|
145
|
+
contents.replace("declare const DB: DBType;", declaration)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
function isManyToManyRelationShip(field) {
|
|
149
|
+
if (!(field.kind === "object" && field.isList)) return false;
|
|
150
|
+
const { type, relationName } = field;
|
|
151
|
+
const typeModel = options.dmmf.datamodel.models.find((m) => m.name === type);
|
|
152
|
+
if (!typeModel) return false;
|
|
153
|
+
if (!typeModel.fields.find((f) => f.kind === "object" && f.isList && f.relationName === relationName)) return false;
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
function getModelId(name) {
|
|
157
|
+
if (!modelToId[name]) {
|
|
158
|
+
for (const m of options.dmmf.datamodel.models) {
|
|
159
|
+
if (m.name !== name) continue;
|
|
160
|
+
for (const f of m.fields) {
|
|
161
|
+
if (f.isId) {
|
|
162
|
+
modelToId[m.name] = [f.name, f.type];
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const remoteId = modelToId[name];
|
|
169
|
+
if (!remoteId) throw new Error(`Remote: Unable to find @id field for model, ${name}`);
|
|
170
|
+
return remoteId;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
function generateReadonlyDeclaration(db) {
|
|
175
|
+
const traverse = (obj, level = 0) => {
|
|
176
|
+
const indent = " ".repeat(level);
|
|
177
|
+
const lines = [];
|
|
178
|
+
if (obj === null) return lines.join("\n");
|
|
179
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
180
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
181
|
+
lines.push(`${indent}readonly ${key}: {`);
|
|
182
|
+
lines.push(traverse(value, level + 1));
|
|
183
|
+
lines.push(`${indent}};`);
|
|
184
|
+
} else if (Array.isArray(value)) {
|
|
185
|
+
lines.push(`${indent}readonly ${key}: [${value.map((v) => `"${v}"`).join(", ")}];`);
|
|
186
|
+
} else {
|
|
187
|
+
lines.push(`${indent}readonly ${key}: "${value}";`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return lines.join("\n");
|
|
191
|
+
};
|
|
192
|
+
return `declare const DB: {
|
|
193
|
+
${traverse(db, 1)}
|
|
194
|
+
};`;
|
|
195
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { generatorHandler } from '@prisma/generator-helper';
|
|
2
|
+
import { logger } from '@prisma/internals';
|
|
3
|
+
import path2 from 'node:path';
|
|
4
|
+
import fs2 from 'node:fs';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
|
|
7
|
+
// src/generator.ts
|
|
8
|
+
|
|
9
|
+
// src/constants.ts
|
|
10
|
+
var GENERATOR_NAME = "prisma-ts-select";
|
|
11
|
+
function writeFileSafely(writeLocation, content) {
|
|
12
|
+
fs2.mkdirSync(path2.dirname(writeLocation), {
|
|
13
|
+
recursive: true
|
|
14
|
+
});
|
|
15
|
+
fs2.writeFileSync(writeLocation, content);
|
|
16
|
+
}
|
|
17
|
+
var require2 = createRequire(import.meta.url);
|
|
18
|
+
var SupportedProviders = {
|
|
19
|
+
sqlite: true,
|
|
20
|
+
mysql: true,
|
|
21
|
+
postgresql: true,
|
|
22
|
+
cockroachdb: false,
|
|
23
|
+
mongodb: false,
|
|
24
|
+
postgres: false,
|
|
25
|
+
sqlserver: false
|
|
26
|
+
};
|
|
27
|
+
generatorHandler({
|
|
28
|
+
onManifest() {
|
|
29
|
+
logger.info(`${GENERATOR_NAME}:Registered`);
|
|
30
|
+
return {
|
|
31
|
+
defaultOutput: "../generated",
|
|
32
|
+
prettyName: GENERATOR_NAME
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
onGenerate: async (options) => {
|
|
36
|
+
const validDS = options.datasources.map((ds) => ds.provider).filter((type) => SupportedProviders[type]);
|
|
37
|
+
if (validDS.length === 0) {
|
|
38
|
+
throw new Error(`${GENERATOR_NAME}: Supported DataSource Providers are: ${Object.entries(SupportedProviders).reduce((acc, [name, supported]) => {
|
|
39
|
+
if (!supported) return acc;
|
|
40
|
+
acc.push(name);
|
|
41
|
+
return acc;
|
|
42
|
+
}, []).join(", ")}`);
|
|
43
|
+
}
|
|
44
|
+
const modelToId = {};
|
|
45
|
+
const models = options.dmmf.datamodel.models.reduce((acc, model) => {
|
|
46
|
+
const modelObj = acc[model.name] = acc[model.name] ?? {
|
|
47
|
+
fields: {},
|
|
48
|
+
relations: {}
|
|
49
|
+
};
|
|
50
|
+
for (const field of model.fields) {
|
|
51
|
+
if (field.kind !== "object") {
|
|
52
|
+
if (field.isId) modelToId[model.name] = [field.name, field.type];
|
|
53
|
+
modelObj.fields = modelObj.fields ?? {};
|
|
54
|
+
modelObj.fields[field.name] = (!field.isRequired ? "?" : "") + field.type;
|
|
55
|
+
} else {
|
|
56
|
+
if (field.relationFromFields && field.relationFromFields.length > 0 && (field.relationToFields && field.relationToFields.length > 0)) {
|
|
57
|
+
const fieldObj = modelObj.relations[field.type] = modelObj.relations[field.type] ?? {};
|
|
58
|
+
field.relationFromFields.forEach((relationFromField, i) => {
|
|
59
|
+
if (!field.relationToFields) return;
|
|
60
|
+
const relationToField = field.relationToFields[i];
|
|
61
|
+
if (!relationToField) return;
|
|
62
|
+
fieldObj[relationFromField] = fieldObj[relationFromField] || [];
|
|
63
|
+
fieldObj[relationFromField].push(relationToField);
|
|
64
|
+
const accModel = acc[field.type] = acc[field.type] ?? {};
|
|
65
|
+
const accModelRelations = accModel.relations = accModel.relations ?? {};
|
|
66
|
+
const accModelRelationToModel = accModelRelations[model.name] = accModelRelations[model.name] ?? {};
|
|
67
|
+
const relationFromFieldList = accModelRelationToModel[relationToField] = accModelRelationToModel[relationToField] ?? [];
|
|
68
|
+
relationFromFieldList.push(relationFromField);
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
if (!isManyToManyRelationShip(field)) continue;
|
|
72
|
+
debugger;
|
|
73
|
+
const joinTableName = "_" + field.relationName;
|
|
74
|
+
const joinTableModel = acc[joinTableName] = acc[joinTableName] ?? {
|
|
75
|
+
fields: {
|
|
76
|
+
"A": "",
|
|
77
|
+
"B": ""
|
|
78
|
+
},
|
|
79
|
+
relations: {}
|
|
80
|
+
};
|
|
81
|
+
const abJoin = [field.type, model.name].toSorted().indexOf(model.name) === 0 ? "A" : "B";
|
|
82
|
+
const [idName, idType] = getModelId(model.name);
|
|
83
|
+
joinTableModel.fields[abJoin] = idType;
|
|
84
|
+
{
|
|
85
|
+
const mr = joinTableModel.relations[model.name] = joinTableModel.relations[model.name] ?? {};
|
|
86
|
+
const mrt = mr[abJoin] = mr[abJoin] ?? [];
|
|
87
|
+
mrt.push(idName);
|
|
88
|
+
}
|
|
89
|
+
const m = modelObj.relations[joinTableName] = modelObj.relations[joinTableName] ?? {};
|
|
90
|
+
const mf = m[idName] = m[idName] ?? [];
|
|
91
|
+
mf.push(abJoin);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return acc;
|
|
96
|
+
}, {});
|
|
97
|
+
const pTSSelPath = path2.dirname(require2.resolve("prisma-ts-select"));
|
|
98
|
+
logger.info("pTSSelPath", pTSSelPath);
|
|
99
|
+
const srcDir = path2.join(pTSSelPath, "extend");
|
|
100
|
+
const outDir = path2.join(pTSSelPath, "..", "built");
|
|
101
|
+
{
|
|
102
|
+
const file = "extend.js";
|
|
103
|
+
const contents = fs2.readFileSync(path2.join(srcDir, file), { encoding: "utf-8" });
|
|
104
|
+
writeFileSafely(
|
|
105
|
+
path2.join(outDir, file),
|
|
106
|
+
contents.replace(
|
|
107
|
+
"const DB = {};",
|
|
108
|
+
`const DB = ${JSON.stringify(models, null, 2)};`
|
|
109
|
+
)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
{
|
|
113
|
+
const file = "extend.cjs";
|
|
114
|
+
const contents = fs2.readFileSync(path2.join(srcDir, file), { encoding: "utf-8" });
|
|
115
|
+
writeFileSafely(
|
|
116
|
+
path2.join(outDir, file),
|
|
117
|
+
contents.replace(
|
|
118
|
+
"const DB = {};",
|
|
119
|
+
`const DB = ${JSON.stringify(models, null, 2)};`
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const declaration = generateReadonlyDeclaration(models);
|
|
124
|
+
{
|
|
125
|
+
const file = "extend.d.ts";
|
|
126
|
+
const contents = fs2.readFileSync(path2.join(srcDir, file), { encoding: "utf-8" });
|
|
127
|
+
writeFileSafely(
|
|
128
|
+
path2.join(outDir, file),
|
|
129
|
+
contents.replace("declare const DB: DBType;", declaration)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
{
|
|
133
|
+
const file = "extend.d.cts";
|
|
134
|
+
const contents = fs2.readFileSync(path2.join(srcDir, file), { encoding: "utf-8" });
|
|
135
|
+
writeFileSafely(
|
|
136
|
+
path2.join(outDir, file),
|
|
137
|
+
contents.replace("declare const DB: DBType;", declaration)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
function isManyToManyRelationShip(field) {
|
|
141
|
+
if (!(field.kind === "object" && field.isList)) return false;
|
|
142
|
+
const { type, relationName } = field;
|
|
143
|
+
const typeModel = options.dmmf.datamodel.models.find((m) => m.name === type);
|
|
144
|
+
if (!typeModel) return false;
|
|
145
|
+
if (!typeModel.fields.find((f) => f.kind === "object" && f.isList && f.relationName === relationName)) return false;
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
function getModelId(name) {
|
|
149
|
+
if (!modelToId[name]) {
|
|
150
|
+
for (const m of options.dmmf.datamodel.models) {
|
|
151
|
+
if (m.name !== name) continue;
|
|
152
|
+
for (const f of m.fields) {
|
|
153
|
+
if (f.isId) {
|
|
154
|
+
modelToId[m.name] = [f.name, f.type];
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const remoteId = modelToId[name];
|
|
161
|
+
if (!remoteId) throw new Error(`Remote: Unable to find @id field for model, ${name}`);
|
|
162
|
+
return remoteId;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
function generateReadonlyDeclaration(db) {
|
|
167
|
+
const traverse = (obj, level = 0) => {
|
|
168
|
+
const indent = " ".repeat(level);
|
|
169
|
+
const lines = [];
|
|
170
|
+
if (obj === null) return lines.join("\n");
|
|
171
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
172
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
173
|
+
lines.push(`${indent}readonly ${key}: {`);
|
|
174
|
+
lines.push(traverse(value, level + 1));
|
|
175
|
+
lines.push(`${indent}};`);
|
|
176
|
+
} else if (Array.isArray(value)) {
|
|
177
|
+
lines.push(`${indent}readonly ${key}: [${value.map((v) => `"${v}"`).join(", ")}];`);
|
|
178
|
+
} else {
|
|
179
|
+
lines.push(`${indent}readonly ${key}: "${value}";`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return lines.join("\n");
|
|
183
|
+
};
|
|
184
|
+
return `declare const DB: {
|
|
185
|
+
${traverse(db, 1)}
|
|
186
|
+
};`;
|
|
187
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var extension = require('@prisma/client/extension');
|
|
4
|
+
var tsPattern = require('ts-pattern');
|
|
5
|
+
|
|
6
|
+
const DB = {};
|
|
7
|
+
class DbSelect {
|
|
8
|
+
constructor(db) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
}
|
|
11
|
+
from(database) {
|
|
12
|
+
return new _fJoin(this.db, { database, selects: [] });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class _fRun {
|
|
16
|
+
constructor(db, values) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
this.values = values;
|
|
19
|
+
this.values.limit = typeof this.values.limit === "number" ? this.values.limit : void 0;
|
|
20
|
+
this.values.offset = typeof this.values.offset === "number" ? this.values.offset : void 0;
|
|
21
|
+
}
|
|
22
|
+
run() {
|
|
23
|
+
return this.db.$queryRawUnsafe(
|
|
24
|
+
this.getSQL()
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
getTables() {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
getFields() {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
getSQL(formatted = false) {
|
|
34
|
+
function processCondition(condition, formatted2) {
|
|
35
|
+
return "(" + Object.keys(condition).map((field) => {
|
|
36
|
+
const value = condition[field];
|
|
37
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && "op" in value) {
|
|
38
|
+
switch (value.op) {
|
|
39
|
+
case "IN":
|
|
40
|
+
case "NOT IN":
|
|
41
|
+
const valuesList = value.values.map((v) => typeof v === "string" ? `'${v}'` : v).join(", ");
|
|
42
|
+
return `${String(field)} ${value.op} (${valuesList})`;
|
|
43
|
+
case "BETWEEN":
|
|
44
|
+
if (value.values.length > 2) throw new Error("Too many items supplied to op BETWEEN");
|
|
45
|
+
const [start, end] = value.values;
|
|
46
|
+
return `${String(field)} BETWEEN ${typeof start === "string" ? `'${start}'` : start} AND ${typeof end === "string" ? `'${end}'` : end}`;
|
|
47
|
+
case "LIKE":
|
|
48
|
+
case "NOT LIKE":
|
|
49
|
+
return `${String(field)} ${value.op} '${value.value}'`;
|
|
50
|
+
case "IS NULL":
|
|
51
|
+
case "IS NOT NULL":
|
|
52
|
+
return `${String(field)} ${value.op}`;
|
|
53
|
+
case ">":
|
|
54
|
+
case ">=":
|
|
55
|
+
case "<":
|
|
56
|
+
case "<=":
|
|
57
|
+
case "!=":
|
|
58
|
+
return `${String(field)} ${value.op} ${typeof value.value === "string" ? `'${value.value}'` : value.value}`;
|
|
59
|
+
default:
|
|
60
|
+
throw new Error(`Unsupported operation: ${value.op}`);
|
|
61
|
+
}
|
|
62
|
+
} else if (Array.isArray(value)) {
|
|
63
|
+
const valuesList = value.map((v) => typeof v === "string" ? `'${v}'` : v).join(", ");
|
|
64
|
+
return `${String(field)} IN (${valuesList})`;
|
|
65
|
+
} else if (value === null) {
|
|
66
|
+
return `${String(field)} IS NULL`;
|
|
67
|
+
} else {
|
|
68
|
+
return `${String(field)} = ${typeof value === "string" ? `'${value}'` : value}`;
|
|
69
|
+
}
|
|
70
|
+
}).join(" AND " + (" ")) + " )";
|
|
71
|
+
}
|
|
72
|
+
function processCriteria(main, joinType = "AND", formatted2 = false) {
|
|
73
|
+
const results = [];
|
|
74
|
+
for (const criteria of main) {
|
|
75
|
+
if (typeof criteria === "string") {
|
|
76
|
+
results.push(criteria);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
for (const criterion in criteria) {
|
|
80
|
+
results.push(tsPattern.match(criterion).returnType().with("$AND", (criterion2) => {
|
|
81
|
+
return "(" + //@ts-expect-error criterion
|
|
82
|
+
processCriteria(criteria[criterion2], "AND", formatted2) + ")";
|
|
83
|
+
}).with("$OR", (criterion2) => {
|
|
84
|
+
return "(" + //@ts-expect-error criterion
|
|
85
|
+
processCriteria(criteria[criterion2], "OR", formatted2) + ")";
|
|
86
|
+
}).with("$NOT", (criterion2) => {
|
|
87
|
+
return "(NOT(" + //@ts-expect-error criterion
|
|
88
|
+
processCriteria(criteria[criterion2], "AND", formatted2) + "))";
|
|
89
|
+
}).with("$NOR", (criterion2) => {
|
|
90
|
+
return "(NOT(" + //@ts-expect-error criterion
|
|
91
|
+
processCriteria(criteria[criterion2], "OR", formatted2) + "))";
|
|
92
|
+
}).with(tsPattern.P.string, () => {
|
|
93
|
+
return processCondition(criteria);
|
|
94
|
+
}).exhaustive());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return results.join((formatted2 ? "\n" : " ") + joinType + (formatted2 ? "\n" : " "));
|
|
98
|
+
}
|
|
99
|
+
const whereClause = this.values.where !== void 0 ? processCriteria(this.values.where, "AND", formatted) : void 0;
|
|
100
|
+
const havingClause = this.values.having !== void 0 ? processCriteria(this.values.having, "AND", formatted) : void 0;
|
|
101
|
+
return [
|
|
102
|
+
this.values.selects.length === 0 ? "" : "SELECT " + (this.values.selectDistinct === true ? "DISTINCT " : "") + this.values.selects.join(", "),
|
|
103
|
+
`FROM ${this.values.database}`,
|
|
104
|
+
this.values.tables?.map(({
|
|
105
|
+
table,
|
|
106
|
+
local,
|
|
107
|
+
remote
|
|
108
|
+
}) => `JOIN ${table} ON ${local} = ${remote}`).join(formatted ? "\n" : " ") ?? "",
|
|
109
|
+
!whereClause ? "" : `WHERE ${whereClause}`,
|
|
110
|
+
!this.values.groupBy?.length ? "" : `GROUP BY ${this.values.groupBy.join(", ")}`,
|
|
111
|
+
!havingClause ? "" : `HAVING ${havingClause}`,
|
|
112
|
+
!(this.values.orderBy && this.values.orderBy.length > 0) ? "" : "ORDER BY " + this.values.orderBy.join(", "),
|
|
113
|
+
!this.values.limit ? "" : `LIMIT ${this.values.limit}`,
|
|
114
|
+
!this.values.offset ? "" : `OFFSET ${this.values.offset}`
|
|
115
|
+
].filter(Boolean).join(formatted ? "\n" : " ").trim() + ";";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
class _fOffset extends _fRun {
|
|
119
|
+
offset(offset) {
|
|
120
|
+
return new _fRun(this.db, { ...this.values, offset });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
class _fLimit extends _fRun {
|
|
124
|
+
limit(limit) {
|
|
125
|
+
return new _fOffset(this.db, { ...this.values, limit });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
class _fOrderBy extends _fLimit {
|
|
129
|
+
orderBy(orderBy) {
|
|
130
|
+
return new _fLimit(this.db, { ...this.values, orderBy });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
class _fSelect extends _fOrderBy {
|
|
134
|
+
select(select) {
|
|
135
|
+
return new _fSelect(this.db, {
|
|
136
|
+
...this.values,
|
|
137
|
+
selects: [...this.values.selects, select]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
class _fSelectDistinct extends _fSelect {
|
|
142
|
+
selectDistinct() {
|
|
143
|
+
return new _fSelect(this.db, { ...this.values, selectDistinct: true });
|
|
144
|
+
}
|
|
145
|
+
selectAll() {
|
|
146
|
+
const selects = function(values) {
|
|
147
|
+
if (values.tables && values.tables.length > 0) {
|
|
148
|
+
return [values.database, ...values.tables.map((t) => t.table)].reduce((acc, table) => {
|
|
149
|
+
return acc.concat(Object.keys(DB[table].fields).map((field) => `${table}.${field} AS \`${table}.${field}\``));
|
|
150
|
+
}, []);
|
|
151
|
+
}
|
|
152
|
+
return Object.keys(DB[values.database].fields);
|
|
153
|
+
}(this.values);
|
|
154
|
+
return new _fOrderBy(this.db, {
|
|
155
|
+
...this.values,
|
|
156
|
+
selects
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//TODO
|
|
160
|
+
// selectAllOmit() {
|
|
161
|
+
// throw new Error("Not implemented yet")
|
|
162
|
+
// }
|
|
163
|
+
}
|
|
164
|
+
class _fHaving extends _fSelectDistinct {
|
|
165
|
+
// TODO Allowed Fields
|
|
166
|
+
// - specified in groupBy
|
|
167
|
+
having(criteria) {
|
|
168
|
+
return new _fSelectDistinct(this.db, {
|
|
169
|
+
...this.values,
|
|
170
|
+
having: [criteria]
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
class _fGroupBy extends _fHaving {
|
|
175
|
+
//TODO this should only accept columns for tables in play
|
|
176
|
+
groupBy(groupBy) {
|
|
177
|
+
return new _fHaving(this.db, { ...this.values, groupBy });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
class _fWhere extends _fGroupBy {
|
|
181
|
+
whereNotNull(col) {
|
|
182
|
+
return new _fWhere(this.db, {
|
|
183
|
+
...this.values,
|
|
184
|
+
where: [
|
|
185
|
+
...this.values.where || [],
|
|
186
|
+
{
|
|
187
|
+
$AND: (
|
|
188
|
+
//@ts-expect-error todo comeback to, col is a string or never
|
|
189
|
+
[{ [col]: { op: "IS NOT NULL" } }]
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
whereIsNull(col) {
|
|
196
|
+
return new _fWhere(this.db, {
|
|
197
|
+
...this.values,
|
|
198
|
+
where: [
|
|
199
|
+
...this.values.where || [],
|
|
200
|
+
{
|
|
201
|
+
$AND: (
|
|
202
|
+
//@ts-expect-error todo comeback to, col is a string or never
|
|
203
|
+
[{ [col]: { op: "IS NULL" } }]
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
where(criteria) {
|
|
210
|
+
return new _fGroupBy(this.db, {
|
|
211
|
+
...this.values,
|
|
212
|
+
where: [...this.values.where || [], criteria]
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
whereRaw(where) {
|
|
216
|
+
return new _fGroupBy(this.db, {
|
|
217
|
+
...this.values,
|
|
218
|
+
where: [...this.values.where || [], where.replace(/^\s*where\s*/i, "").trim()]
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
class _fJoin extends _fWhere {
|
|
223
|
+
join(table, field, reference) {
|
|
224
|
+
return new _fJoin(this.db, {
|
|
225
|
+
...this.values,
|
|
226
|
+
tables: [...this.values.tables || [], { table, local: field, remote: reference }]
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
joinUnsafeTypeEnforced(table, field, reference) {
|
|
230
|
+
return new _fJoin(this.db, {
|
|
231
|
+
...this.values,
|
|
232
|
+
tables: [...this.values.tables || [], {
|
|
233
|
+
table,
|
|
234
|
+
local: `${String(table)}.${String(field)}`,
|
|
235
|
+
remote: reference
|
|
236
|
+
}]
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
joinUnsafeIgnoreType(table, field, reference) {
|
|
240
|
+
return new _fJoin(this.db, {
|
|
241
|
+
...this.values,
|
|
242
|
+
tables: [...this.values.tables || [], {
|
|
243
|
+
table,
|
|
244
|
+
local: `${String(table)}.${String(field)}`,
|
|
245
|
+
remote: reference
|
|
246
|
+
}]
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// innerJoin(table: TTables, col1:string, col2:string){
|
|
250
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
251
|
+
// }
|
|
252
|
+
// leftJoin(table: TTables, col1:string, col2:string){
|
|
253
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
254
|
+
// }
|
|
255
|
+
// rightJoin(table: TTables, col1:string, col2:string){
|
|
256
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
257
|
+
// }
|
|
258
|
+
// fullJoin(table: TTables, col1:string, col2:string){
|
|
259
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
260
|
+
// }
|
|
261
|
+
// crossJoin(table: TTables, col1:string, col2:string){
|
|
262
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
263
|
+
// }
|
|
264
|
+
// outerJoin(table: TTables, col1:string, col2:string){
|
|
265
|
+
// return new _fJoin<TDBBase>(this.db, {...this.values, tables: [...this.values.tables || [], table]});
|
|
266
|
+
// }
|
|
267
|
+
}
|
|
268
|
+
var extend_default = {
|
|
269
|
+
client: {
|
|
270
|
+
$from(table) {
|
|
271
|
+
const client = extension.Prisma.getExtensionContext(this);
|
|
272
|
+
return new DbSelect(client).from(table);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
module.exports = extend_default;
|