Skip to content

Commit

Permalink
Add sys::Branch.last_migration (#7654)
Browse files Browse the repository at this point in the history
`select sys::Branch { name, last_migration }` will list all branch names
with the names of their latest migrations. Note that `last_migration`
could be an empty set if the branch is empty.
  • Loading branch information
fantix authored Aug 27, 2024
1 parent b812e38 commit 8f69dd0
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 38 deletions.
2 changes: 1 addition & 1 deletion edb/buildmeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
# The merge conflict there is a nice reminder that you probably need
# to write a patch in edb/pgsql/patches.py, and then you should preserve
# the old value.
EDGEDB_CATALOG_VERSION = 2024_08_23_00_00
EDGEDB_CATALOG_VERSION = 2024_08_27_00_00
EDGEDB_MAJOR_VERSION = 6


Expand Down
1 change: 1 addition & 0 deletions edb/lib/sys.edgeql
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ CREATE TYPE sys::Branch EXTENDING
ALTER PROPERTY name {
CREATE CONSTRAINT std::exclusive;
};
CREATE PROPERTY last_migration-> std::str;
};

CREATE ALIAS sys::Database := sys::Branch;
Expand Down
75 changes: 39 additions & 36 deletions edb/pgsql/dbops/databases.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,32 @@
from . import ddl


class Database(base.DBObject):
class AbstractDatabase(base.DBObject):
def get_type(self):
return 'DATABASE'

def is_shared(self) -> bool:
return True

def _get_id_expr(self) -> str:
raise NotImplementedError()

def get_oid(self) -> base.Query:
qry = textwrap.dedent(f'''\
SELECT
'pg_database'::regclass::oid AS classoid,
pg_database.oid AS objectoid,
0
FROM
pg_database
WHERE
datname = {self._get_id_expr()}
''')

return base.Query(text=qry)


class Database(AbstractDatabase):
def __init__(
self,
name: str,
Expand All @@ -50,28 +75,11 @@ def __init__(
self.lc_collate = lc_collate
self.lc_ctype = lc_ctype

def get_type(self):
return 'DATABASE'

def get_id(self):
return qi(self.name)

def is_shared(self) -> bool:
return True

def get_oid(self) -> base.Query:
qry = textwrap.dedent(f'''\
SELECT
'pg_database'::regclass::oid AS classoid,
pg_database.oid AS objectoid,
0
FROM
pg_database
WHERE
datname = {ql(self.name)}
''')

return base.Query(text=qry)
def _get_id_expr(self) -> str:
return ql(self.name)


class DatabaseWithTenant(Database):
Expand All @@ -81,24 +89,19 @@ def __init__(
) -> None:
super().__init__(name=name)

def get_id(self):
dyn_db = f"{V('edgedb')}.get_database_backend_name({ql(self.name)})"
return f"' || quote_ident({dyn_db}) || '"
def get_id(self) -> str:
return f"' || quote_ident({self._get_id_expr()}) || '"

def get_oid(self) -> base.Query:
qry = textwrap.dedent(f'''\
SELECT
'pg_database'::regclass::oid AS classoid,
pg_database.oid AS objectoid,
0
FROM
pg_database
WHERE
datname =
{V("edgedb")}.get_database_backend_name({ql(self.name)})
''')
def _get_id_expr(self) -> str:
return f'{V("edgedb")}.get_database_backend_name({ql(self.name)})'

return base.Query(text=qry)

class CurrentDatabase(AbstractDatabase):
def get_id(self) -> str:
return f"' || quote_ident({self._get_id_expr()}) || '"

def _get_id_expr(self) -> str:
return 'current_database()'


class DatabaseExists(base.Condition):
Expand Down
16 changes: 15 additions & 1 deletion edb/pgsql/delta.py
Original file line number Diff line number Diff line change
Expand Up @@ -7301,7 +7301,21 @@ def apply(


class MigrationCommand(MetaCommand):
pass
def apply(
self,
schema: s_schema.Schema,
context: sd.CommandContext,
) -> s_schema.Schema:
schema = super().apply(schema, context)
if last_mig := schema.get_last_migration():
last_mig_name = last_mig.get_name(schema).name
else:
last_mig_name = None
self.pgops.add(dbops.UpdateMetadata(
dbops.CurrentDatabase(),
{'last_migration': last_mig_name},
))
return schema


class CreateMigration(
Expand Down
1 change: 1 addition & 0 deletions edb/pgsql/metaschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -5098,6 +5098,7 @@ def _generate_branch_views(schema: s_schema.Schema) -> List[dbops.View]:
),
'computed_fields': 'ARRAY[]::text[]',
'builtin': "((d.description)->>'builtin')::bool",
'last_migration': "(d.description)->>'last_migration'",
}

view_query = f'''
Expand Down
22 changes: 22 additions & 0 deletions tests/test_edgeql_data_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ async def migrate(
explicit_modules=explicit_modules,
)
await self.fast_forward_describe_migration(user_input=user_input)
await self.assert_last_migration()

async def interact(self, parts, check_complete=True):
for part in parts:
Expand Down Expand Up @@ -243,6 +244,25 @@ async def interact(self, parts, check_complete=True):
'complete': True
})

async def assert_last_migration(self):
last_name = await self.con.query_single(
'''
select assert_single(
sys::Branch.last_migration
filter sys::Branch.name = sys::get_current_database());
'''
)
last_mig = await self.con.query_single(
'''
select assert_single(
schema::Migration { name } filter not exists .<parents);
'''
)
if last_mig:
self.assertEqual(last_mig.name, last_name)
else:
self.assertIsNone(last_name)


class TestEdgeQLDataMigration(EdgeQLDataMigrationTestCase):
async def test_edgeql_migration_simple_01(self):
Expand Down Expand Up @@ -12275,6 +12295,7 @@ async def test_edgeql_migration_reset_schema(self):
self.assertEqual(len(res), 2)

await self.con.query('reset schema to initial')
await self.assert_last_migration()

res = await self.con.query('''
select schema::ObjectType { name } filter .name ilike 'test::%'
Expand Down Expand Up @@ -12869,6 +12890,7 @@ async def assert_migration_history(self, exp_result):
res = serutils.serialize(res)
assert_data_shape.assert_data_shape(
res, exp_result, self.fail)
await self.assert_last_migration()


class TestEdgeQLMigrationRewrite(EdgeQLMigrationRewriteTestCase):
Expand Down

0 comments on commit 8f69dd0

Please sign in to comment.