zenstack 0.1.0 → 0.1.2
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/out/cli/index.js +4 -51
- package/out/cli/index.js.map +1 -1
- package/out/cli/package.template.json +10 -0
- package/out/cli/tsconfig.template.json +17 -0
- package/out/generator/constants.js +6 -0
- package/out/generator/constants.js.map +1 -0
- package/out/generator/index.js +76 -0
- package/out/generator/index.js.map +1 -0
- package/out/generator/next-auth/index.js +3 -3
- package/out/generator/package.template.json +9 -0
- package/out/generator/prisma/expression-writer.js +287 -0
- package/out/generator/prisma/expression-writer.js.map +1 -0
- package/out/generator/prisma/index.js +8 -182
- package/out/generator/prisma/index.js.map +1 -1
- package/out/generator/prisma/plain-expression-builder.js +69 -0
- package/out/generator/prisma/plain-expression-builder.js.map +1 -0
- package/out/generator/prisma/prisma-builder.js +1 -1
- package/out/generator/prisma/prisma-builder.js.map +1 -1
- package/out/generator/prisma/query-gard-generator.js +159 -0
- package/out/generator/prisma/query-gard-generator.js.map +1 -0
- package/out/generator/prisma/schema-generator.js +202 -0
- package/out/generator/prisma/schema-generator.js.map +1 -0
- package/out/generator/query-guard/index.js +2 -0
- package/out/generator/query-guard/index.js.map +1 -0
- package/out/generator/react-hooks/index.js +1 -1
- package/out/generator/react-hooks/index.js.map +1 -1
- package/out/generator/server/data/expression-writer.js +42 -36
- package/out/generator/server/data/expression-writer.js.map +1 -1
- package/out/generator/server/data/plain-expression-builder.js +18 -2
- package/out/generator/server/data/plain-expression-builder.js.map +1 -1
- package/out/generator/service/index.js +51 -1
- package/out/generator/service/index.js.map +1 -1
- package/out/generator/tsconfig.template.json +17 -0
- package/out/utils/indent-string.js +3 -19
- package/out/utils/indent-string.js.map +1 -1
- package/package.json +7 -4
- package/src/cli/index.ts +5 -33
- package/src/generator/constants.ts +2 -0
- package/src/generator/index.ts +59 -0
- package/src/generator/next-auth/index.ts +3 -3
- package/src/generator/package.template.json +9 -0
- package/src/generator/{server/data → prisma}/expression-writer.ts +65 -63
- package/src/generator/prisma/index.ts +10 -309
- package/src/generator/{server/data → prisma}/plain-expression-builder.ts +22 -3
- package/src/generator/prisma/prisma-builder.ts +1 -1
- package/src/generator/prisma/query-gard-generator.ts +208 -0
- package/src/generator/prisma/schema-generator.ts +295 -0
- package/src/generator/react-hooks/index.ts +2 -4
- package/src/generator/service/index.ts +54 -1
- package/src/generator/tsconfig.template.json +17 -0
- package/src/utils/indent-string.ts +3 -38
- package/src/generator/server/data/data-generator.ts +0 -483
- package/src/generator/server/function/function-generator.ts +0 -32
- package/src/generator/server/index.ts +0 -57
- package/src/generator/server/server-code-generator.ts +0 -6
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// https://github.com/sindresorhus/indent-string
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
function indentString(string, count = 4
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof string}\``);
|
|
8
|
-
}
|
|
9
|
-
if (typeof count !== 'number') {
|
|
10
|
-
throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof count}\``);
|
|
11
|
-
}
|
|
12
|
-
if (count < 0) {
|
|
13
|
-
throw new RangeError(`Expected \`count\` to be at least 0, got \`${count}\``);
|
|
14
|
-
}
|
|
15
|
-
if (typeof indent !== 'string') {
|
|
16
|
-
throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof indent}\``);
|
|
17
|
-
}
|
|
18
|
-
if (count === 0) {
|
|
19
|
-
return string;
|
|
20
|
-
}
|
|
21
|
-
const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm;
|
|
22
|
-
return string.replace(regex, indent.repeat(count));
|
|
4
|
+
function indentString(string, count = 4) {
|
|
5
|
+
const indent = ' ';
|
|
6
|
+
return string.replace(/^(?!\s*$)/gm, indent.repeat(count));
|
|
23
7
|
}
|
|
24
8
|
exports.default = indentString;
|
|
25
9
|
//# sourceMappingURL=indent-string.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indent-string.js","sourceRoot":"","sources":["../../src/utils/indent-string.ts"],"names":[],"mappings":";AAAA,gDAAgD;;AAEhD,SAAwB,YAAY,
|
|
1
|
+
{"version":3,"file":"indent-string.js","sourceRoot":"","sources":["../../src/utils/indent-string.ts"],"names":[],"mappings":";AAAA,gDAAgD;;AAEhD,SAAwB,YAAY,CAAC,MAAc,EAAE,KAAK,GAAG,CAAC;IAC1D,MAAM,MAAM,GAAG,GAAG,CAAC;IACnB,OAAO,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/D,CAAC;AAHD,+BAGC"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "zenstack",
|
|
3
3
|
"displayName": "ZenStack CLI and Language Tools",
|
|
4
4
|
"description": "ZenStack CLI and Language Tools",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.2",
|
|
6
6
|
"engines": {
|
|
7
7
|
"vscode": "^1.56.0"
|
|
8
8
|
},
|
|
@@ -44,15 +44,17 @@
|
|
|
44
44
|
"src"
|
|
45
45
|
],
|
|
46
46
|
"bin": {
|
|
47
|
-
"
|
|
47
|
+
"zenstack": "./bin/cli"
|
|
48
48
|
},
|
|
49
49
|
"main": "./out/extension.js",
|
|
50
50
|
"dependencies": {
|
|
51
|
+
"@zenstackhq/runtime": "0.1.1",
|
|
51
52
|
"change-case": "^4.1.2",
|
|
52
53
|
"chevrotain": "^9.1.0",
|
|
53
54
|
"colors": "^1.4.0",
|
|
54
55
|
"commander": "^8.0.0",
|
|
55
56
|
"langium": "^0.4.0",
|
|
57
|
+
"prisma": "^4.4.0",
|
|
56
58
|
"promisify": "^0.0.3",
|
|
57
59
|
"ts-morph": "^16.0.0",
|
|
58
60
|
"vscode-jsonrpc": "^8.0.2",
|
|
@@ -82,13 +84,14 @@
|
|
|
82
84
|
},
|
|
83
85
|
"scripts": {
|
|
84
86
|
"vscode:prepublish": "npm run build && npm run lint",
|
|
85
|
-
"build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/",
|
|
87
|
+
"build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/ && cp src/generator/*.template.json ./out/generator/",
|
|
86
88
|
"ts:watch": "tsc --watch",
|
|
87
89
|
"tsc-alias:watch": "tsc-alias --watch",
|
|
88
90
|
"lint": "eslint src --ext ts",
|
|
89
91
|
"langium:generate": "langium generate",
|
|
90
92
|
"langium:watch": "langium generate --watch",
|
|
91
93
|
"watch": "concurrently --kill-others \"npm:langium:watch\" \"npm:ts:watch\" \"npm:tsc-alias:watch\"",
|
|
92
|
-
"test": "jest"
|
|
94
|
+
"test": "jest",
|
|
95
|
+
"npm-publish": "pnpm build && pnpm publish --no-git-checks --access public"
|
|
93
96
|
}
|
|
94
97
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -4,14 +4,7 @@ import { ZModelLanguageMetaData } from '../language-server/generated/module';
|
|
|
4
4
|
import { createZModelServices } from '../language-server/zmodel-module';
|
|
5
5
|
import { extractAstNode } from './cli-util';
|
|
6
6
|
import { Context } from '../generator/types';
|
|
7
|
-
import
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import colors from 'colors';
|
|
10
|
-
import PrismaGenerator from '../generator/prisma';
|
|
11
|
-
import ServiceGenerator from '../generator/service';
|
|
12
|
-
import ReactHooksGenerator from '../generator/react-hooks';
|
|
13
|
-
import NextAuthGenerator from '../generator/next-auth';
|
|
14
|
-
import ServerGenerator from '../generator/server';
|
|
7
|
+
import { ZenStackGenerator } from '../generator';
|
|
15
8
|
|
|
16
9
|
export const generateAction = async (
|
|
17
10
|
fileName: string,
|
|
@@ -22,34 +15,14 @@ export const generateAction = async (
|
|
|
22
15
|
|
|
23
16
|
const context: Context = {
|
|
24
17
|
schema: model,
|
|
25
|
-
outDir:
|
|
18
|
+
outDir: opts.destination || 'node_modules/.zenstack',
|
|
26
19
|
};
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
fs.mkdirSync(context.outDir);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
console.log(colors.bold('⌛️ Running ZenStack generators'));
|
|
33
|
-
|
|
34
|
-
const generators = [
|
|
35
|
-
new PrismaGenerator(),
|
|
36
|
-
new ServiceGenerator(),
|
|
37
|
-
new ReactHooksGenerator(),
|
|
38
|
-
new ServerGenerator(),
|
|
39
|
-
new NextAuthGenerator(),
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
for (const generator of generators) {
|
|
43
|
-
await generator.generate(context);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
console.log(
|
|
47
|
-
colors.green(colors.bold('👻 All generators completed successfully!'))
|
|
48
|
-
);
|
|
21
|
+
await new ZenStackGenerator().generate(context);
|
|
49
22
|
};
|
|
50
23
|
|
|
51
24
|
export type GenerateOptions = {
|
|
52
|
-
destination
|
|
25
|
+
destination?: string;
|
|
53
26
|
};
|
|
54
27
|
|
|
55
28
|
export default function (): void {
|
|
@@ -68,8 +41,7 @@ export default function (): void {
|
|
|
68
41
|
)
|
|
69
42
|
.option(
|
|
70
43
|
'-d, --destination <dir>',
|
|
71
|
-
'destination directory of generating'
|
|
72
|
-
'.zenstack'
|
|
44
|
+
'destination directory of generating'
|
|
73
45
|
)
|
|
74
46
|
.description(
|
|
75
47
|
'generates JavaScript code that prints "Hello, {name}!" for each greeting in a source file'
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Context } from './types';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import colors from 'colors';
|
|
4
|
+
import PrismaGenerator from './prisma';
|
|
5
|
+
import ServiceGenerator from './service';
|
|
6
|
+
import ReactHooksGenerator from './react-hooks';
|
|
7
|
+
import NextAuthGenerator from './next-auth';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
|
|
11
|
+
export class ZenStackGenerator {
|
|
12
|
+
async generate(context: Context) {
|
|
13
|
+
if (!fs.existsSync(context.outDir)) {
|
|
14
|
+
fs.mkdirSync(context.outDir);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log(colors.bold('⌛️ Running ZenStack generators'));
|
|
18
|
+
|
|
19
|
+
const generators = [
|
|
20
|
+
new PrismaGenerator(),
|
|
21
|
+
new ServiceGenerator(),
|
|
22
|
+
new ReactHooksGenerator(),
|
|
23
|
+
new NextAuthGenerator(),
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for (const generator of generators) {
|
|
27
|
+
await generator.generate(context);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// generate package.json
|
|
31
|
+
const packageJson = require(path.join(
|
|
32
|
+
__dirname,
|
|
33
|
+
'package.template.json'
|
|
34
|
+
));
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
path.join(context.outDir, 'package.json'),
|
|
37
|
+
JSON.stringify(packageJson, undefined, 4)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// compile ts sources
|
|
41
|
+
const tsConfig = require(path.join(
|
|
42
|
+
__dirname,
|
|
43
|
+
'tsconfig.template.json'
|
|
44
|
+
));
|
|
45
|
+
fs.writeFileSync(
|
|
46
|
+
path.join(context.outDir, 'tsconfig.json'),
|
|
47
|
+
JSON.stringify(tsConfig, undefined, 4)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
execSync(`npx tsc -p "${path.join(context.outDir, 'tsconfig.json')}"`);
|
|
51
|
+
console.log(colors.blue(' ✔️ Typescript source files transpiled'));
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
colors.green(
|
|
55
|
+
colors.bold('👻 All generators completed successfully!')
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -30,9 +30,9 @@ export default class NextAuthGenerator implements Generator {
|
|
|
30
30
|
|
|
31
31
|
generateAdapter(project: Project, context: Context) {
|
|
32
32
|
const content = `
|
|
33
|
-
import { ZenStackService } from '
|
|
33
|
+
import { ZenStackService } from '..';
|
|
34
34
|
import { Adapter } from 'next-auth/adapters';
|
|
35
|
-
import { Prisma } from '
|
|
35
|
+
import { Prisma } from '../.prisma';
|
|
36
36
|
|
|
37
37
|
export function NextAuthAdapter(service: ZenStackService): Adapter {
|
|
38
38
|
const db = service.db;
|
|
@@ -101,7 +101,7 @@ export default class NextAuthGenerator implements Generator {
|
|
|
101
101
|
|
|
102
102
|
generateAuthorize(project: Project, context: Context) {
|
|
103
103
|
const content = `
|
|
104
|
-
import { ZenStackService } from '
|
|
104
|
+
import { ZenStackService } from '..';
|
|
105
105
|
import { hash, compare } from 'bcryptjs';
|
|
106
106
|
|
|
107
107
|
async function hashPassword(password: string) {
|
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
isEnumField,
|
|
7
7
|
isMemberAccessExpr,
|
|
8
8
|
isReferenceExpr,
|
|
9
|
+
isThisExpr,
|
|
9
10
|
LiteralExpr,
|
|
10
11
|
MemberAccessExpr,
|
|
11
12
|
ReferenceExpr,
|
|
12
|
-
ThisExpr,
|
|
13
13
|
UnaryExpr,
|
|
14
14
|
} from '@lang/generated/ast';
|
|
15
15
|
import { CodeBlockWriter } from 'ts-morph';
|
|
16
|
-
import { GeneratorError } from '
|
|
16
|
+
import { GeneratorError } from '../types';
|
|
17
17
|
import { TypedNode } from '@lang/types';
|
|
18
18
|
import PlainExpressionBuilder from './plain-expression-builder';
|
|
19
19
|
|
|
@@ -49,20 +49,17 @@ export default class ExpressionWriter {
|
|
|
49
49
|
this.writeMemberAccess(expr as MemberAccessExpr);
|
|
50
50
|
break;
|
|
51
51
|
|
|
52
|
-
case ThisExpr:
|
|
53
|
-
throw new Error('Not implemented');
|
|
54
|
-
|
|
55
52
|
default:
|
|
56
53
|
throw new Error(`Not implemented: ${expr.$type}`);
|
|
57
54
|
}
|
|
58
55
|
};
|
|
59
56
|
|
|
60
|
-
this.
|
|
57
|
+
this.block(_write);
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
private writeReference(expr: ReferenceExpr) {
|
|
64
61
|
if (isEnumField(expr.target.ref)) {
|
|
65
|
-
throw new Error('
|
|
62
|
+
throw new Error('We should never get here');
|
|
66
63
|
} else {
|
|
67
64
|
this.writer.write(`${expr.target.ref!.name}: true`);
|
|
68
65
|
}
|
|
@@ -72,7 +69,7 @@ export default class ExpressionWriter {
|
|
|
72
69
|
this.writeFieldCondition(
|
|
73
70
|
expr.operand,
|
|
74
71
|
() => {
|
|
75
|
-
this.
|
|
72
|
+
this.block(() => {
|
|
76
73
|
this.writer.write(`${expr.member.ref?.name}: true`);
|
|
77
74
|
});
|
|
78
75
|
},
|
|
@@ -125,12 +122,17 @@ export default class ExpressionWriter {
|
|
|
125
122
|
);
|
|
126
123
|
}
|
|
127
124
|
|
|
128
|
-
private
|
|
125
|
+
private isFieldAccess(expr: Expression): boolean {
|
|
126
|
+
if (isThisExpr(expr)) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
if (isMemberAccessExpr(expr)) {
|
|
130
|
+
return this.isFieldAccess(expr.operand);
|
|
131
|
+
}
|
|
129
132
|
if (isReferenceExpr(expr) && isDataModelField(expr.target.ref)) {
|
|
130
133
|
return true;
|
|
131
|
-
} else {
|
|
132
|
-
return false;
|
|
133
134
|
}
|
|
135
|
+
return false;
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
private guard(write: () => void) {
|
|
@@ -143,11 +145,8 @@ export default class ExpressionWriter {
|
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
private writeComparison(expr: BinaryExpr, operator: ComparisonOperator) {
|
|
146
|
-
const leftIsFieldAccess =
|
|
147
|
-
|
|
148
|
-
const rightIsFieldAccess =
|
|
149
|
-
this.isFieldRef(expr.right) ||
|
|
150
|
-
this.isRelationFieldAccess(expr.right);
|
|
148
|
+
const leftIsFieldAccess = this.isFieldAccess(expr.left);
|
|
149
|
+
const rightIsFieldAccess = this.isFieldAccess(expr.right);
|
|
151
150
|
|
|
152
151
|
if (leftIsFieldAccess && rightIsFieldAccess) {
|
|
153
152
|
throw new GeneratorError(
|
|
@@ -177,27 +176,30 @@ export default class ExpressionWriter {
|
|
|
177
176
|
operator = this.negateOperator(operator);
|
|
178
177
|
}
|
|
179
178
|
|
|
180
|
-
const type = (fieldAccess as TypedNode).$resolvedType?.decl;
|
|
181
|
-
|
|
182
179
|
this.writeFieldCondition(
|
|
183
180
|
fieldAccess,
|
|
184
181
|
() => {
|
|
185
|
-
this.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
182
|
+
this.block(
|
|
183
|
+
() => {
|
|
184
|
+
if (this.isModelTyped(fieldAccess)) {
|
|
185
|
+
// comparing with an object, conver to "id" comparison instead
|
|
186
|
+
this.writer.write('id: ');
|
|
187
|
+
this.block(() => {
|
|
188
|
+
this.writeOperator(operator, () => {
|
|
189
|
+
this.plain(operand);
|
|
190
|
+
this.writer.write('?.id');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
} else {
|
|
190
194
|
this.writeOperator(operator, () => {
|
|
191
195
|
this.plain(operand);
|
|
192
|
-
this.writer.write('?.id');
|
|
193
196
|
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
});
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
// "this" expression is compiled away (to .id access), so we should
|
|
200
|
+
// avoid generating a new layer
|
|
201
|
+
!isThisExpr(fieldAccess)
|
|
202
|
+
);
|
|
201
203
|
},
|
|
202
204
|
'is'
|
|
203
205
|
);
|
|
@@ -210,7 +212,7 @@ export default class ExpressionWriter {
|
|
|
210
212
|
if (operator === '!=') {
|
|
211
213
|
// wrap a 'not'
|
|
212
214
|
this.writer.write('not: ');
|
|
213
|
-
this.
|
|
215
|
+
this.block(() => {
|
|
214
216
|
this.writeOperator('==', writeOperand);
|
|
215
217
|
});
|
|
216
218
|
} else {
|
|
@@ -227,7 +229,11 @@ export default class ExpressionWriter {
|
|
|
227
229
|
let selector: string;
|
|
228
230
|
let operand: Expression | undefined;
|
|
229
231
|
|
|
230
|
-
if (
|
|
232
|
+
if (isThisExpr(fieldAccess)) {
|
|
233
|
+
// pass on
|
|
234
|
+
writeCondition();
|
|
235
|
+
return;
|
|
236
|
+
} else if (isReferenceExpr(fieldAccess)) {
|
|
231
237
|
selector = fieldAccess.target.ref?.name!;
|
|
232
238
|
} else if (isMemberAccessExpr(fieldAccess)) {
|
|
233
239
|
selector = fieldAccess.member.ref?.name!;
|
|
@@ -243,26 +249,31 @@ export default class ExpressionWriter {
|
|
|
243
249
|
this.writeFieldCondition(
|
|
244
250
|
operand,
|
|
245
251
|
() => {
|
|
246
|
-
this.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
this.
|
|
252
|
+
this.block(
|
|
253
|
+
() => {
|
|
254
|
+
this.writer.write(selector + ': ');
|
|
255
|
+
if (this.isModelTyped(fieldAccess)) {
|
|
256
|
+
// expression is resolved to a model, generate relation query
|
|
257
|
+
this.block(() => {
|
|
258
|
+
this.writer.write(`${relationOp}: `);
|
|
259
|
+
writeCondition();
|
|
260
|
+
});
|
|
261
|
+
} else {
|
|
262
|
+
// generate plain query
|
|
252
263
|
writeCondition();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
// if operand is "this", it doesn't really generate a new layer of query,
|
|
267
|
+
// so we should avoid generating a new block
|
|
268
|
+
!isThisExpr(operand)
|
|
269
|
+
);
|
|
259
270
|
},
|
|
260
271
|
'is'
|
|
261
272
|
);
|
|
262
273
|
} else if (this.isModelTyped(fieldAccess)) {
|
|
263
274
|
// reference resolved to a model, generate relation query
|
|
264
275
|
this.writer.write(selector + ': ');
|
|
265
|
-
this.
|
|
276
|
+
this.block(() => {
|
|
266
277
|
this.writer.write(`${relationOp}: `);
|
|
267
278
|
writeCondition();
|
|
268
279
|
});
|
|
@@ -273,25 +284,16 @@ export default class ExpressionWriter {
|
|
|
273
284
|
}
|
|
274
285
|
}
|
|
275
286
|
|
|
276
|
-
private
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (isMemberAccessExpr(expr)) {
|
|
282
|
-
return this.isRelationFieldAccess(expr.operand);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
isReferenceExpr(expr) &&
|
|
287
|
-
isDataModelField(expr.target.ref) &&
|
|
288
|
-
expr.target.ref.type.reference &&
|
|
289
|
-
isDataModel(expr.target.ref.type.reference.ref)
|
|
290
|
-
) {
|
|
291
|
-
return true;
|
|
287
|
+
private block(write: () => void, condition = true) {
|
|
288
|
+
if (condition) {
|
|
289
|
+
this.writer.block(write);
|
|
290
|
+
} else {
|
|
291
|
+
write();
|
|
292
292
|
}
|
|
293
|
+
}
|
|
293
294
|
|
|
294
|
-
|
|
295
|
+
private isModelTyped(expr: Expression) {
|
|
296
|
+
return isDataModel((expr as TypedNode).$resolvedType?.decl);
|
|
295
297
|
}
|
|
296
298
|
|
|
297
299
|
mapOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') {
|