From 748d87367b6051eba90e2f7446f311501cd03ddd Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Fri, 21 Oct 2022 20:37:24 +0300 Subject: [PATCH] Add/fix fields in `CREATE MIGRATION` (#4550) 1. `message` field is now reflected in `schema::Migration` 2. Added `generated_by` field to the migration --- edb/buildmeta.py | 2 +- edb/edgeql/ast.py | 1 - edb/edgeql/parser/grammar/ddl.py | 16 ++++++++++++---- edb/lib/schema.edgeql | 3 +++ edb/schema/migrations.py | 6 ++++++ edb/server/compiler/compiler.py | 5 +++++ tests/test_edgeql_ddl.py | 20 ++++++++++++++++++++ 7 files changed, 47 insertions(+), 6 deletions(-) diff --git a/edb/buildmeta.py b/edb/buildmeta.py index 0d91368683a..a636d614326 100644 --- a/edb/buildmeta.py +++ b/edb/buildmeta.py @@ -44,7 +44,7 @@ # Increment this whenever the database layout or stdlib changes. -EDGEDB_CATALOG_VERSION = 2022_10_17_00_00 +EDGEDB_CATALOG_VERSION = 2022_10_19_00_00 EDGEDB_MAJOR_VERSION = 3 diff --git a/edb/edgeql/ast.py b/edb/edgeql/ast.py index d8ae907bcf5..07e9d59129c 100644 --- a/edb/edgeql/ast.py +++ b/edb/edgeql/ast.py @@ -759,7 +759,6 @@ class CreateMigration(CreateObject, MigrationCommand): body: NestedQLBlock parent: typing.Optional[ObjectRef] = None - message: typing.Optional[str] = None metadata_only: bool = False diff --git a/edb/edgeql/parser/grammar/ddl.py b/edb/edgeql/parser/grammar/ddl.py index b1257051f01..99ec84c7efc 100644 --- a/edb/edgeql/parser/grammar/ddl.py +++ b/edb/edgeql/parser/grammar/ddl.py @@ -332,15 +332,21 @@ def result(self) -> typing.Any: def _process_body(self, body): fields = [] stmts = [] + uniq_check = set() for stmt in body: if isinstance(stmt, qlast.SetField): - if stmt.name in self.allowed_fields: - fields.append(stmt) - else: + if stmt.name not in self.allowed_fields: raise errors.InvalidSyntaxError( f'unexpected field: {stmt.name!r}', context=stmt.context, ) + if stmt.name in uniq_check: + raise errors.InvalidSyntaxError( + f'duplicate `SET {stmt.name} := ...`', + context=stmt.context, + ) + uniq_check.add(stmt.name) + fields.append(stmt) else: stmts.append(stmt) @@ -2818,7 +2824,7 @@ class CreateMigrationBodyBlock(NestedQLBlock): @property def allowed_fields(self) -> typing.FrozenSet[str]: - return frozenset({'message'}) + return frozenset({'message', 'generated_by'}) @property def result(self) -> typing.Any: @@ -2869,6 +2875,7 @@ def reduce_CreateMigration(self, *kids): name=kids[2].val.name, parent=kids[2].val.parent, body=kids[3].val.body, + commands=kids[3].val.fields, ) def reduce_CreateAppliedMigration(self, *kids): @@ -2881,6 +2888,7 @@ def reduce_CreateAppliedMigration(self, *kids): parent=kids[3].val.parent, body=kids[4].val.body, metadata_only=True, + commands=kids[4].val.fields, ) diff --git a/edb/lib/schema.edgeql b/edb/lib/schema.edgeql index e1bd503bfd4..0401ad5aa86 100644 --- a/edb/lib/schema.edgeql +++ b/edb/lib/schema.edgeql @@ -49,6 +49,8 @@ CREATE SCALAR TYPE schema::AccessPolicyAction CREATE SCALAR TYPE schema::AccessKind EXTENDING enum<`Select`, UpdateRead, UpdateWrite, `Delete`, `Insert`>; +CREATE SCALAR TYPE schema::MigrationGeneratedBy + EXTENDING enum; # Base type for all schema entities. CREATE ABSTRACT TYPE schema::Object EXTENDING std::BaseObject { @@ -494,6 +496,7 @@ CREATE TYPE schema::Migration CREATE MULTI LINK parents -> schema::Migration; CREATE REQUIRED PROPERTY script -> str; CREATE PROPERTY message -> str; + CREATE PROPERTY generated_by -> schema::MigrationGeneratedBy; }; diff --git a/edb/schema/migrations.py b/edb/schema/migrations.py index a7bb90cd2cd..b4044d30293 100644 --- a/edb/schema/migrations.py +++ b/edb/schema/migrations.py @@ -60,6 +60,12 @@ class Migration( allow_ddl_set=True, ) + generated_by = so.SchemaField( + str, + default=None, + allow_ddl_set=True, + ) + script = so.SchemaField( str, ) diff --git a/edb/server/compiler/compiler.py b/edb/server/compiler/compiler.py index 1fde157f422..63030c055f5 100644 --- a/edb/server/compiler/compiler.py +++ b/edb/server/compiler/compiler.py @@ -864,6 +864,11 @@ def _compile_and_apply_ddl_stmt( body=qlast.NestedQLBlock( commands=[stmt], ), + generated_by=qlast.Path(steps=[ + qlast.ObjectRef(name='MigrationGeneratedBy', + module='schema'), + qlast.Ptr(ptr=qlast.ObjectRef(name='DDLStatement')), + ]), ) return self._compile_and_apply_ddl_stmt(ctx, cm) diff --git a/tests/test_edgeql_ddl.py b/tests/test_edgeql_ddl.py index 46722db9a2a..e8165e60d75 100644 --- a/tests/test_edgeql_ddl.py +++ b/tests/test_edgeql_ddl.py @@ -12070,6 +12070,26 @@ async def test_edgeql_ddl_create_migration_02(self): }; ''') + async def test_edgeql_ddl_create_migration_03(self): + await self.con.execute(f''' + CREATE MIGRATION + {{ + SET message := "migration2"; + SET generated_by := schema::MigrationGeneratedBy.DevMode; + CREATE TYPE Type2 {{ + CREATE PROPERTY field2 -> int32; + }}; + }}; + ''') + + await self.assert_query_result( + ''' + SELECT schema::Migration { generated_by } + FILTER .message = "migration2" + ''', + [{'generated_by': 'DevMode'}] + ) + async def test_edgeql_ddl_naked_backlink_in_computable(self): await self.con.execute(''' CREATE TYPE User {