-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #236 from wri/feature-aliasing
Feature version aliasing
- Loading branch information
Showing
14 changed files
with
508 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from asyncpg import UniqueViolationError | ||
|
||
from app.errors import RecordAlreadyExistsError, RecordNotFoundError | ||
from app.models.orm.aliases import Alias as ORMAlias | ||
|
||
|
||
async def create_alias(alias: str, dataset: str, version: str) -> ORMAlias: | ||
try: | ||
new_alias: ORMAlias = await ORMAlias.create( | ||
alias=alias, dataset=dataset, version=version | ||
) | ||
except UniqueViolationError: | ||
raise RecordAlreadyExistsError( | ||
f"Alias {alias} already exists for dataset {dataset}" | ||
) | ||
|
||
return new_alias | ||
|
||
|
||
async def get_alias(dataset: str, alias: str) -> ORMAlias: | ||
alias_record: ORMAlias = await ORMAlias.get([alias, dataset]) | ||
if alias_record is None: | ||
raise RecordNotFoundError(f"Could not find requested alias {alias}.") | ||
|
||
return alias_record | ||
|
||
|
||
async def delete_alias(dataset, alias: str) -> ORMAlias: | ||
alias_record: ORMAlias = await get_alias(dataset, alias) | ||
await ORMAlias.delete.where(ORMAlias.dataset == dataset).where( | ||
ORMAlias.alias == alias | ||
).gino.status() | ||
|
||
return alias_record |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from .base import Base, db | ||
|
||
|
||
class Alias(Base): | ||
__tablename__ = "aliases" | ||
alias = db.Column(db.String, primary_key=True) | ||
dataset = db.Column(db.String, primary_key=True) | ||
version = db.Column(db.String, nullable=False) | ||
|
||
fk = db.ForeignKeyConstraint( | ||
["dataset", "version"], | ||
["versions.dataset", "versions.version"], | ||
name="fk", | ||
onupdate="CASCADE", | ||
ondelete="CASCADE", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
"""Add version column to all data tables.""" | ||
import os | ||
|
||
import click | ||
import sqlalchemy as sa | ||
|
||
|
||
def get_datasets(connection): | ||
datasets = connection.execute(sa.text("select * from public.versions")) | ||
return datasets.fetchall() | ||
|
||
|
||
def upgrade(connection): | ||
versions = get_datasets(connection) | ||
for version in versions: | ||
if not connection.engine.has_table(version.version, schema=version.dataset) or version.dataset == "nasa_viirs_fire_alerts": | ||
continue | ||
print(f"Adding version column to {version.dataset}.{version.version}") | ||
connection.execute( | ||
sa.text( | ||
f"""ALTER TABLE "{version.dataset}"."{version.version}" | ||
ADD COLUMN IF NOT EXISTS "version" VARCHAR | ||
""" | ||
) | ||
) | ||
|
||
null_rows = connection.execute( | ||
sa.text(f"""select count(*) from "{version.dataset}"."{version.version}" where version IS NULL""") | ||
).first() | ||
print('NULL rows', null_rows) | ||
if null_rows[0] == 0: | ||
print(f"{version.dataset}.{version.version} updated already") | ||
continue | ||
connection.execute( | ||
sa.text( | ||
f"""UPDATE "{version.dataset}"."{version.version}" SET version = '{version.version}' | ||
""" | ||
) | ||
) | ||
connection.execute( | ||
sa.text( | ||
f"""ALTER TABLE "{version.dataset}"."{version.version}" | ||
ALTER version SET NOT NULL | ||
""" | ||
) | ||
) | ||
|
||
|
||
def downgrade(connection): | ||
versions = get_datasets(connection) | ||
for version in versions: | ||
if not connection.engine.has_table(version.version, schema=version.dataset): | ||
continue | ||
print(f"Dropping version column from {version.dataset}.{version.version} table") | ||
connection.execute( | ||
sa.text( | ||
f"""ALTER TABLE "{version.dataset}"."{version.version}" | ||
DROP COLUMN IF EXISTS version | ||
""" | ||
) | ||
) | ||
|
||
|
||
@click.command() | ||
@click.argument("operation", type=click.Choice(["upgrade", "downgrade"])) | ||
def migrate(operation): | ||
db_user = os.environ["DB_USERNAME"] | ||
db_pass = os.environ["DB_PASSWORD"] | ||
db_host = os.environ["DB_HOST"] | ||
db_port = os.environ["DB_PORT"] | ||
db_name = os.environ["DB_NAME"] | ||
engine = sa.create_engine( | ||
f"postgresql://{db_user}:{db_pass}@{db_host}:{db_port}/{db_name}" # pragma: allowlist secret | ||
) | ||
|
||
with engine.connect() as connection: | ||
if operation == "upgrade": | ||
upgrade(connection) | ||
elif operation == "downgrade": | ||
downgrade(connection) | ||
else: | ||
raise ValueError("Operation not supported.") | ||
|
||
|
||
if __name__ == "__main__": | ||
migrate() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
"""Adding dataset version alias table. | ||
Revision ID: a5787f2eefe5 | ||
Revises: 4763f4b8141a | ||
Create Date: 2021-09-27 22:12:26.964711 | ||
""" | ||
import sqlalchemy as sa | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "a5787f2eefe5" | ||
down_revision = "4763f4b8141a" # pragma: allowlist secret | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
op.create_table( | ||
"aliases", | ||
sa.Column("alias", sa.String(), nullable=False), | ||
sa.Column("dataset", sa.String(), nullable=False), | ||
sa.Column("version", sa.String(), nullable=False), | ||
sa.Column( | ||
"created_on", sa.DateTime(), server_default=sa.text("now()"), nullable=True | ||
), | ||
sa.Column( | ||
"updated_on", sa.DateTime(), server_default=sa.text("now()"), nullable=True | ||
), | ||
sa.ForeignKeyConstraint( | ||
["dataset", "version"], | ||
["versions.dataset", "versions.version"], | ||
name="fk", | ||
onupdate="CASCADE", | ||
ondelete="CASCADE", | ||
), | ||
sa.PrimaryKeyConstraint("dataset", "alias"), | ||
) | ||
|
||
|
||
def downgrade(): | ||
op.drop_table("aliases") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from .base import StrictBaseModel | ||
from .responses import Response | ||
|
||
|
||
class Alias(StrictBaseModel): | ||
alias: str | ||
version: str | ||
dataset: str | ||
|
||
class Config: | ||
orm_mode = True | ||
|
||
|
||
class AliasResponse(Response): | ||
data: Alias | ||
|
||
|
||
class AliasCreateIn(StrictBaseModel): | ||
version: str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.