Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "zenstack",
"displayName": "ZenStack CLI and Language Tools",
"description": "ZenStack CLI and Language Tools",
"version": "0.1.45",
"version": "0.1.47",
"engines": {
"vscode": "^1.56.0"
},
Expand Down Expand Up @@ -48,7 +48,7 @@
"main": "./out/extension.js",
"scripts": {
"vscode:prepublish": "npm run build && npm run lint",
"build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/ && cp src/generator/*.template.json ./out/generator/",
"build": "npm run langium:generate && tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/ && cp src/generator/*.template.json ./out/generator/",
"ts:watch": "tsc --watch",
"tsc-alias:watch": "tsc-alias --watch",
"lint": "eslint src --ext ts",
Expand All @@ -63,34 +63,37 @@
"change-case": "^4.1.2",
"chevrotain": "^9.1.0",
"colors": "^1.4.0",
"commander": "^8.0.0",
"langium": "^0.4.0",
"prisma": "^4.4.0",
"commander": "^8.3.0",
"langium": "^0.5.0",
"pluralize": "^8.0.0",
"prisma": "^4.5.0",
"promisify": "^0.0.3",
"ts-morph": "^16.0.0",
"uuid": "^9.0.0",
"vscode-jsonrpc": "^8.0.2",
"vscode-languageclient": "^7.0.0",
"vscode-languageserver": "^7.0.0",
"vscode-uri": "^3.0.2"
"vscode-languageclient": "^8.0.2",
"vscode-languageserver": "^8.0.2",
"vscode-uri": "^3.0.6"
},
"devDependencies": {
"@prisma/internals": "^4.4.0",
"@types/jest": "^29.0.3",
"@types/node": "^14.18.29",
"@prisma/internals": "^4.5.0",
"@types/jest": "^29.2.0",
"@types/node": "^14.18.32",
"@types/pluralize": "^0.0.29",
"@types/tmp": "^0.2.3",
"@types/uuid": "^8.3.4",
"@types/vscode": "^1.56.0",
"@typescript-eslint/eslint-plugin": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"@types/vscode": "^1.72.0",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"concurrently": "^7.4.0",
"eslint": "^7.19.0",
"jest": "^29.0.3",
"langium-cli": "^0.4.0",
"eslint": "^7.32.0",
"jest": "^29.2.1",
"langium-cli": "^0.5.0",
"tmp": "^0.2.1",
"ts-jest": "^29.0.1",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"tsc-alias": "^1.7.0",
"tsconfig-paths-jest": "^0.0.1",
"typescript": "^4.6.2"
"typescript": "^4.8.4"
}
}
5 changes: 4 additions & 1 deletion packages/schema/src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Command, Option } from 'commander';
import { NodeFileSystem } from 'langium/node';
import { Model } from '../language-server/generated/ast';
import { ZModelLanguageMetaData } from '../language-server/generated/module';
import { createZModelServices } from '../language-server/zmodel-module';
Expand All @@ -14,7 +15,7 @@ import path from 'path';
export const generateAction = async (options: {
schema: string;
}): Promise<void> => {
const services = createZModelServices().ZModel;
const services = createZModelServices(NodeFileSystem).ZModel;
const model = await extractAstNode<Model>(options.schema, services);

const context: Context = {
Expand Down Expand Up @@ -110,6 +111,8 @@ export default function (): void {
)
.addOption(schemaOption)
.option('--create-only', 'Create a migration without applying it')
.option('-n --name <name>', 'Name the migration')
.option('--skip-seed', 'Skip triggering seed')
.action(prismaAction('migrate'));

migrate
Expand Down
8 changes: 3 additions & 5 deletions packages/schema/src/generator/prisma/expression-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ import {
UnaryExpr,
} from '@lang/generated/ast';
import { CodeBlockWriter } from 'ts-morph';
import { GUARD_FIELD_NAME } from '../constants';
import { GeneratorError } from '../types';
import { TypedNode } from '@lang/types';
import PlainExpressionBuilder from './plain-expression-builder';

const AUX_GUARD_FIELD = 'zenstack_guard';

type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<=';

export default class ExpressionWriter {
Expand Down Expand Up @@ -136,7 +134,7 @@ export default class ExpressionWriter {
}

private guard(write: () => void) {
this.writer.write(`${AUX_GUARD_FIELD}: `);
this.writer.write(`${GUARD_FIELD_NAME}: `);
write();
}

Expand Down Expand Up @@ -293,7 +291,7 @@ export default class ExpressionWriter {
}

private isModelTyped(expr: Expression) {
return isDataModel((expr as TypedNode).$resolvedType?.decl);
return isDataModel(expr.$resolvedType?.decl);
}

mapOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') {
Expand Down
4 changes: 2 additions & 2 deletions packages/schema/src/generator/prisma/prisma-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export class FieldAttribute {

toString() {
return (
`@${this.name}(` +
`${this.name}(` +
this.args.map((a) => a.toString()).join(', ') +
`)`
);
Expand All @@ -211,7 +211,7 @@ export class ModelAttribute {

toString() {
return (
`@@${this.name}(` +
`${this.name}(` +
this.args.map((a) => a.toString()).join(', ') +
`)`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default class QueryGuardGenerator {
operation: PolicyOperationKind
) {
const attrs = model.attributes.filter(
(attr) => attr.decl.ref?.name === kind
(attr) => attr.decl.ref?.name === `@@${kind}`
);
return attrs
.filter((attr) => {
Expand Down
34 changes: 12 additions & 22 deletions packages/schema/src/generator/prisma/schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,7 @@ import {
ModelFieldType,
} from './prisma-builder';

const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver'];
const supportedAttrbutes = [
'id',
'index',
'relation',
'default',
'createdAt',
'updatedAt',
'unique',
];
const excludedAttributes = ['@@allow', '@@deny'];

export default class PrismaSchemaGenerator {
constructor(private readonly context: Context) {}
Expand Down Expand Up @@ -90,13 +81,6 @@ export default class PrismaSchemaGenerator {
'Datasource provider must be set to a string'
);
}
if (!supportedProviders.includes(provider)) {
throw new GeneratorError(
`Provider ${provider} is not supported. Supported providers: ${supportedProviders.join(
', '
)}`
);
}
break;
}

Expand Down Expand Up @@ -157,7 +141,11 @@ export default class PrismaSchemaGenerator {
'client',
'prisma-client-js',
path.join('../', this.context.generatedCodeDir, '.prisma'),
['fieldReference', 'interactiveTransactions']
[
'fieldReference',
'interactiveTransactions',
'referentialIntegrity',
]
);
}

Expand All @@ -169,7 +157,7 @@ export default class PrismaSchemaGenerator {

// add an "zenstack_guard" field for dealing with pure auth() related conditions
model.addField(GUARD_FIELD_NAME, 'Boolean', [
new PrismaFieldAttribute('default', [
new PrismaFieldAttribute('@default', [
new PrismaAttributeArg(
undefined,
new PrismaAttributeArgValue('Boolean', true)
Expand All @@ -180,8 +168,8 @@ export default class PrismaSchemaGenerator {
// add an "zenstack_transaction" field for tracking records created/updated with nested writes
model.addField(TRANSACTION_FIELD_NAME, 'String?');

for (const attr of decl.attributes.filter((attr) =>
supportedAttrbutes.includes(attr.decl.ref?.name!)
for (const attr of decl.attributes.filter(
(attr) => !excludedAttributes.includes(attr.decl.ref?.name!)
)) {
this.generateModelAttribute(model, attr);
}
Expand All @@ -195,7 +183,9 @@ export default class PrismaSchemaGenerator {
);

const attributes = field.attributes
.filter((attr) => supportedAttrbutes.includes(attr.decl.ref?.name!))
.filter(
(attr) => !excludedAttributes.includes(attr.decl.ref?.name!)
)
.map((attr) => this.makeFieldAttribute(attr));
model.addField(field.name, type, attributes);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/src/generator/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export function extractDataModelsWithAllowRules(model: Model) {
return model.declarations.filter(
(d) =>
isDataModel(d) &&
!!d.attributes.find((attr) => attr.decl.ref?.name === 'allow')
!!d.attributes.find((attr) => attr.decl.ref?.name === '@@allow')
) as DataModel[];
}
17 changes: 17 additions & 0 deletions packages/schema/src/language-server/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const SUPPORTED_PROVIDERS = [
'postgresql',
'mysql',
'sqlite',
'sqlserver',
];

export const SCALAR_TYPES = [
'String',
'Int',
'Float',
'Decimal',
'BigInt',
'Boolean',
'Bytes',
'DateTime',
];
35 changes: 24 additions & 11 deletions packages/schema/src/language-server/generated/ast.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/******************************************************************************
* This file was generated by langium-cli 0.4.0.
* This file was generated by langium-cli 0.5.0.
* DO NOT EDIT MANUALLY!
******************************************************************************/

/* eslint-disable @typescript-eslint/array-type */
/* eslint-disable @typescript-eslint/no-empty-interface */
import { AstNode, AstReflection, Reference, isAstNode, TypeMetaData } from 'langium';
import { AstNode, AstReflection, Reference, ReferenceInfo, isAstNode, TypeMetaData } from 'langium';

export type AbstractDeclaration = Attribute | DataModel | DataSource | Enum | Function;

Expand All @@ -15,6 +15,14 @@ export function isAbstractDeclaration(item: unknown): item is AbstractDeclaratio
return reflection.isInstance(item, AbstractDeclaration);
}

export type AttributeName = string;

export type BuiltinType = 'BigInt' | 'Boolean' | 'Bytes' | 'DateTime' | 'Decimal' | 'Float' | 'Int' | 'Json' | 'String';

export type DataModelAttributeName = string;

export type DataModelFieldAttributeName = string;

export type Expression = ArrayExpr | BinaryExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | NullExpr | ReferenceExpr | ThisExpr | UnaryExpr;

export const Expression = 'Expression';
Expand All @@ -23,6 +31,8 @@ export function isExpression(item: unknown): item is Expression {
return reflection.isInstance(item, Expression);
}

export type ExpressionType = 'Any' | 'Boolean' | 'DateTime' | 'Float' | 'Int' | 'Null' | 'String';

export type ReferenceTarget = DataModelField | EnumField | FunctionParam;

export const ReferenceTarget = 'ReferenceTarget';
Expand Down Expand Up @@ -64,7 +74,7 @@ export function isArrayExpr(item: unknown): item is ArrayExpr {

export interface Attribute extends AstNode {
readonly $container: Model;
name: string
name: AttributeName
params: Array<AttributeParam>
}

Expand All @@ -88,8 +98,8 @@ export function isAttributeArg(item: unknown): item is AttributeArg {

export interface AttributeParam extends AstNode {
readonly $container: Attribute;
default: boolean
name: string
positional: boolean
type: AttributeParamType
}

Expand All @@ -103,7 +113,8 @@ export interface AttributeParamType extends AstNode {
readonly $container: AttributeParam;
array: boolean
optional: boolean
type: 'Boolean' | 'DateTime' | 'FieldReference' | 'Int' | 'JSON' | 'String'
reference?: Reference<TypeDeclaration>
type?: 'ContextType' | 'FieldReference' | ExpressionType
}

export const AttributeParamType = 'AttributeParamType';
Expand Down Expand Up @@ -180,7 +191,7 @@ export interface DataModelFieldType extends AstNode {
array: boolean
optional: boolean
reference?: Reference<TypeDeclaration>
type?: 'Boolean' | 'DateTime' | 'Int' | 'JSON' | 'String'
type?: BuiltinType
}

export const DataModelFieldType = 'DataModelFieldType';
Expand Down Expand Up @@ -266,7 +277,7 @@ export interface FunctionParamType extends AstNode {
readonly $container: Function | FunctionParam;
array: boolean
reference?: Reference<TypeDeclaration>
type?: 'Boolean' | 'DateTime' | 'Int' | 'JSON' | 'String'
type?: ExpressionType
}

export const FunctionParamType = 'FunctionParamType';
Expand Down Expand Up @@ -380,8 +391,6 @@ export function isUnaryExpr(item: unknown): item is UnaryExpr {

export type ZModelAstType = 'AbstractDeclaration' | 'Argument' | 'ArrayExpr' | 'Attribute' | 'AttributeArg' | 'AttributeParam' | 'AttributeParamType' | 'BinaryExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'NullExpr' | 'ReferenceArg' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr';

export type ZModelAstReference = 'DataModelAttribute:decl' | 'DataModelFieldAttribute:decl' | 'DataModelFieldType:reference' | 'FunctionParamType:reference' | 'InvocationExpr:function' | 'MemberAccessExpr:member' | 'ReferenceExpr:target';

export class ZModelAstReflection implements AstReflection {

getAllTypes(): string[] {
Expand Down Expand Up @@ -428,8 +437,12 @@ export class ZModelAstReflection implements AstReflection {
}
}

getReferenceType(referenceId: ZModelAstReference): string {
getReferenceType(refInfo: ReferenceInfo): string {
const referenceId = `${refInfo.container.$type}:${refInfo.property}`;
switch (referenceId) {
case 'AttributeParamType:reference': {
return TypeDeclaration;
}
case 'DataModelAttribute:decl': {
return Attribute;
}
Expand Down Expand Up @@ -479,7 +492,7 @@ export class ZModelAstReflection implements AstReflection {
return {
name: 'AttributeParam',
mandatory: [
{ name: 'positional', type: 'boolean' }
{ name: 'default', type: 'boolean' }
]
};
}
Expand Down
Loading