Skip to content

Commit

Permalink
Add/fix fields in CREATE MIGRATION
Browse files Browse the repository at this point in the history
1. `message` field is now reflected in `schema::Migration`
2. Added `generated_by` field to the migration
  • Loading branch information
tailhook committed Oct 19, 2022
1 parent 0e4a2d1 commit 2b40f25
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 6 deletions.
2 changes: 1 addition & 1 deletion edb/buildmeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
3 changes: 2 additions & 1 deletion edb/edgeql/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,8 @@ class CreateMigration(CreateObject, MigrationCommand):

body: NestedQLBlock
parent: typing.Optional[ObjectRef] = None
message: typing.Optional[str] = None
message: typing.Optional[Expr] = None
generated_by: typing.Optional[Expr] = None
metadata_only: bool = False


Expand Down
36 changes: 32 additions & 4 deletions edb/edgeql/parser/grammar/ddl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -2865,22 +2871,44 @@ def reduce_CreateMigration(self, *kids):
CREATE MIGRATION OptMigrationNameParentName
OptCreateMigrationCommandsBlock
"""
message = None
generated_by = None
for f in kids[3].val.fields:
match f.name:
case 'message':
message = f.value
case 'generated_by':
generated_by = f.value

self.val = qlast.CreateMigration(
name=kids[2].val.name,
parent=kids[2].val.parent,
body=kids[3].val.body,
message=message,
generated_by=generated_by,
)

def reduce_CreateAppliedMigration(self, *kids):
r"""%reduce
CREATE APPLIED MIGRATION OptMigrationNameParentName
OptCreateMigrationCommandsBlock
"""
message = None
generated_by = None
for f in kids[4].val.fields:
match f.name:
case 'message':
message = f.value
case 'generated_by':
generated_by = f.value

self.val = qlast.CreateMigration(
name=kids[3].val.name,
parent=kids[3].val.parent,
body=kids[4].val.body,
metadata_only=True,
message=message,
generated_by=generated_by,
)


Expand Down
3 changes: 3 additions & 0 deletions edb/lib/schema.edgeql
Original file line number Diff line number Diff line change
Expand Up @@ -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<DevMode, DDLStatement>;

# Base type for all schema entities.
CREATE ABSTRACT TYPE schema::Object EXTENDING std::BaseObject {
Expand Down Expand Up @@ -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;
};


Expand Down
24 changes: 24 additions & 0 deletions edb/schema/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from edb.edgeql import ast as qlast
from edb.edgeql import codegen as qlcodegen
from edb.edgeql import compiler as qlcompiler
from edb.edgeql import qltypes
from edb.edgeql import hasher as qlhasher
from edb.edgeql import parser as qlparser
Expand Down Expand Up @@ -60,6 +61,12 @@ class Migration(
allow_ddl_set=True,
)

generated_by = so.SchemaField(
str,
default=None,
allow_ddl_set=True,
)

script = so.SchemaField(
str,
)
Expand Down Expand Up @@ -160,6 +167,23 @@ def _cmd_from_ast(
cmd.set_attribute_value('script', ddl_text)
cmd.set_attribute_value('builtin', False)
cmd.set_attribute_value('internal', False)
if message := astnode.message:
value = qlcompiler.evaluate_ast_to_python_val(message, schema)
if value is not None and not isinstance(value, str):
raise errors.InvalidSyntaxError(
f'invalid value for `message` field, str expected',
context=message.context,
)
cmd.set_attribute_value('message', value)
if generated_by := astnode.generated_by:
value = qlcompiler.evaluate_ast_to_python_val(generated_by, schema)
if value is not None and not isinstance(value, str):
raise errors.InvalidSyntaxError(
f'invalid value for `generated_by` field, '
f'schema::MigrationGeneratedBy enum value expected',
context=generated_by.context,
)
cmd.set_attribute_value('generated_by', value)
if parent is not None:
cmd.set_attribute_value('parents', [parent])

Expand Down
5 changes: 5 additions & 0 deletions edb/server/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
20 changes: 20 additions & 0 deletions tests/test_edgeql_ddl.py
Original file line number Diff line number Diff line change
Expand Up @@ -12015,6 +12015,26 @@ async def test_edgeql_ddl_create_migration_01(self):
}]
)

async def test_edgeql_ddl_create_migration_02(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 {
Expand Down

0 comments on commit 2b40f25

Please sign in to comment.