Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for type modifier attributes #240

Merged
merged 2 commits into from
Mar 6, 2023
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-monorepo",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"description": "",
"scripts": {
"build": "pnpm -r build",
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/language",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"displayName": "ZenStack modeling language compiler",
"description": "ZenStack modeling language compiler",
"homepage": "https://zenstack.dev",
Expand Down
22 changes: 17 additions & 5 deletions packages/language/src/generated/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2035,11 +2035,23 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel
"value": "."
},
{
"$type": "RuleCall",
"rule": {
"$ref": "#/rules@53"
},
"arguments": []
"$type": "Alternatives",
"elements": [
{
"$type": "RuleCall",
"rule": {
"$ref": "#/rules@53"
},
"arguments": []
},
{
"$type": "RuleCall",
"rule": {
"$ref": "#/rules@48"
},
"arguments": []
}
]
}
],
"cardinality": "*"
Expand Down
5 changes: 3 additions & 2 deletions packages/language/src/zmodel.langium
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ FunctionParamType:
(type=ExpressionType | reference=[TypeDeclaration]) (array?='[' ']')?;

QualifiedName returns string:
ID ('.' ID)*;
// TODO: is this the right way to deal with token precedence?
ID ('.' (ID|BuiltinType))*;

// attribute-level attribute
AttributeAttributeName returns string:
Expand Down Expand Up @@ -221,7 +222,7 @@ ExpressionType returns string:
'String' | 'Int' | 'Float' | 'Boolean' | 'DateTime' | 'Null' | 'Any';

BuiltinType returns string:
'String'|'Boolean'|'Int'|'BigInt'|'Float'|'Decimal'|'DateTime'|'Json'|'Bytes';
'String' | 'Boolean' | 'Int' | 'BigInt' | 'Float' | 'Decimal' | 'DateTime' | 'Json' | 'Bytes';

hidden terminal WS: /\s+/;
terminal BOOLEAN returns boolean: /true|false/;
Expand Down
2 changes: 1 addition & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/next",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"displayName": "ZenStack Next.js integration",
"description": "ZenStack Next.js integration",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/react/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/react",
"displayName": "ZenStack plugin and runtime for ReactJS",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"description": "ZenStack plugin and runtime for ReactJS",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/trpc/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/trpc",
"displayName": "ZenStack plugin for tRPC",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"description": "ZenStack plugin for tRPC",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/runtime",
"displayName": "ZenStack Runtime Library",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"description": "Runtime of ZenStack for both client-side and server-side environments.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack Language Tools",
"description": "A toolkit for building secure CRUD apps with Next.js + Typescript",
"version": "1.0.0-alpha.55",
"version": "1.0.0-alpha.56",
"author": {
"name": "ZenStack Team"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export default class DataModelValidator implements AstValidator<DataModel> {
}

private validateFields(dm: DataModel, accept: ValidationAcceptor) {
// TODO: check conflict of @id and @@id

const idFields = dm.fields.filter((f) => f.attributes.find((attr) => attr.decl.ref?.name === '@id'));
if (idFields.length === 0) {
const { allows, denies, hasFieldValidation } = analyzePolicies(dm);
Expand Down
3 changes: 3 additions & 0 deletions packages/schema/src/language-server/validator/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ function isValidAttributeTarget(attrDecl: Attribute, targetDecl: DataModelField)
case 'IntField':
allowed = allowed || targetDecl.type.type === 'Int';
break;
case 'BigIntField':
allowed = allowed || targetDecl.type.type === 'BigInt';
break;
case 'FloatField':
allowed = allowed || targetDecl.type.type === 'Float';
break;
Expand Down
118 changes: 110 additions & 8 deletions packages/schema/src/res/stdlib.zmodel
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum ReferentialAction {
enum AttributeTargetField {
StringField
IntField
BigIntField
FloatField
DecimalField
BooleanField
Expand All @@ -51,43 +52,51 @@ enum AttributeTargetField {
/*
* Reads value from an environment variable.
*/
function env(name: String): String {}
function env(name: String): String {
}

/*
* Gets the current login user.
*/
function auth(): Any {}
function auth(): Any {
}

/*
* Gets current date-time (as DateTime type).
*/
function now(): DateTime {}
function now(): DateTime {
}

/*
* Generates a globally unique identifier based on the UUID specs.
*/
function uuid(): String {}
function uuid(): String {
}

/*
* Generates a globally unique identifier based on the CUID spec.
*/
function cuid(): String {}
function cuid(): String {
}

/*
* Creates a sequence of integers in the underlying database and assign the incremented
* values to the ID values of the created records based on the sequence.
*/
function autoincrement(): Int {}
function autoincrement(): Int {
}

/*
* Represents default values that cannot be expressed in the Prisma schema (such as random()).
*/
function dbgenerated(expr: String): Any {}
function dbgenerated(expr: String): Any {
}

/**
* Gets entities value before an update. Only valid when used in a "update" policy rule.
*/
function future(): Any {}
function future(): Any {
}

/**
* Marks an attribute to be only applicable to certain field types.
Expand All @@ -114,6 +123,11 @@ attribute @default(_ value: ContextType) @@@prisma
*/
attribute @unique(map: String?) @@@prisma

/*
* Defines a multi-field ID (composite ID) on the model.
*/
attribute @@id(_ fields: FieldReference[], name: String?, map: String?) @@@prisma

/*
* Defines a compound unique constraint for the specified fields.
*/
Expand Down Expand Up @@ -144,6 +158,94 @@ attribute @@map(_ name: String) @@@prisma
*/
attribute @updatedAt() @@@targetField([DateTimeField]) @@@prisma

// String type modifiers

attribute @db.String(_ x: Int?) @@@targetField([StringField]) @@@prisma
attribute @db.Text() @@@targetField([StringField]) @@@prisma
attribute @db.NText() @@@targetField([StringField]) @@@prisma
attribute @db.Char(_ x: Int) @@@targetField([StringField]) @@@prisma
attribute @db.NChar(_ x: Int) @@@targetField([StringField]) @@@prisma
attribute @db.VarChar(_ x: Int) @@@targetField([StringField]) @@@prisma
attribute @db.NVarChar(_ x: Int) @@@targetField([StringField]) @@@prisma
attribute @db.CatalogSingleChar() @@@targetField([StringField]) @@@prisma
attribute @db.TinyText() @@@targetField([StringField]) @@@prisma
attribute @db.MediumText() @@@targetField([StringField]) @@@prisma
attribute @db.LongText() @@@targetField([StringField]) @@@prisma
attribute @db.Bit(_ x: Int?) @@@targetField([StringField, BooleanField, BytesField]) @@@prisma
attribute @db.VarBit(_ x: Int?) @@@targetField([StringField]) @@@prisma
attribute @db.Uuid() @@@targetField([StringField]) @@@prisma
attribute @db.UniqueIdentifier() @@@targetField([StringField]) @@@prisma
attribute @db.Xml() @@@targetField([StringField]) @@@prisma
attribute @db.Inet() @@@targetField([StringField]) @@@prisma
attribute @db.Citext() @@@targetField([StringField]) @@@prisma

// Boolean type modifiers

attribute @db.Boolean() @@@targetField([BooleanField]) @@@prisma
attribute @db.TinyInt(_ x: Int?) @@@targetField([BooleanField]) @@@prisma
attribute @db.Bool() @@@targetField([BooleanField]) @@@prisma

// Int type modifiers

attribute @db.Int() @@@targetField([IntField]) @@@prisma
attribute @db.Integer() @@@targetField([IntField]) @@@prisma
attribute @db.SmallInt() @@@targetField([IntField]) @@@prisma
attribute @db.Oid() @@@targetField([IntField]) @@@prisma
attribute @db.UnsignedInt() @@@targetField([IntField]) @@@prisma
attribute @db.UnsignedSmallInt() @@@targetField([IntField]) @@@prisma
attribute @db.MediumInt() @@@targetField([IntField]) @@@prisma
attribute @db.UnsignedMediumInt() @@@targetField([IntField]) @@@prisma
attribute @db.UnsignedTinyInt() @@@targetField([IntField]) @@@prisma
attribute @db.Year() @@@targetField([IntField]) @@@prisma
attribute @db.Int4() @@@targetField([IntField]) @@@prisma
attribute @db.Int2() @@@targetField([IntField]) @@@prisma

// BigInt type modifiers

attribute @db.BigInt() @@@targetField([BigIntField]) @@@prisma
attribute @db.UnsignedBigInt() @@@targetField([BigIntField]) @@@prisma
attribute @db.Int8() @@@targetField([BigIntField]) @@@prisma

// Float/Decimal type modifiers
attribute @db.DoublePrecision() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Real() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Float() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Decimal() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Double() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Money() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.SmallMoney() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Float8() @@@targetField([FloatField, DecimalField]) @@@prisma
attribute @db.Float4() @@@targetField([FloatField, DecimalField]) @@@prisma

// DateTime type modifiers

attribute @db.DateTime(x: Int?) @@@targetField([DateTimeField]) @@@prisma
attribute @db.DateTime2() @@@targetField([DateTimeField]) @@@prisma
attribute @db.SmallDateTime() @@@targetField([DateTimeField]) @@@prisma
attribute @db.DateTimeOffset() @@@targetField([DateTimeField]) @@@prisma
attribute @db.Timestamp(_ x: Int?) @@@targetField([DateTimeField]) @@@prisma
attribute @db.Timestamptz(_ x: Int?) @@@targetField([DateTimeField]) @@@prisma
attribute @db.Date() @@@targetField([DateTimeField]) @@@prisma
attribute @db.Time(_ x: Int?) @@@targetField([DateTimeField]) @@@prisma
attribute @db.Timetz(_ x: Int?) @@@targetField([DateTimeField]) @@@prisma

// Json type modifiers

attribute @db.Json() @@@targetField([JsonField]) @@@prisma
attribute @db.JsonB() @@@targetField([JsonField]) @@@prisma

// Bytes type modifiers

attribute @db.Bytes() @@@targetField([BytesField]) @@@prisma
attribute @db.ByteA() @@@targetField([BytesField]) @@@prisma
attribute @db.LongBlob() @@@targetField([BytesField]) @@@prisma
attribute @db.Binary() @@@targetField([BytesField]) @@@prisma
attribute @db.VarBinary() @@@targetField([BytesField]) @@@prisma
attribute @db.TinyBlob() @@@targetField([BytesField]) @@@prisma
attribute @db.Blob() @@@targetField([BytesField]) @@@prisma
attribute @db.MediumBlob() @@@targetField([BytesField]) @@@prisma
attribute @db.Image() @@@targetField([BytesField]) @@@prisma

/*
* Defines an access policy that allows a set of operations when the given condition is true.
*/
Expand Down
Loading