From 7bcca786b3854a8bcfe30a29cf339e0f2acff61a Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Wed, 8 Jun 2022 16:53:30 -0300 Subject: [PATCH 1/6] :sparkles: Add migration for 1.0 --- bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py | 193 +++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py diff --git a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py new file mode 100644 index 0000000..010eab3 --- /dev/null +++ b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py @@ -0,0 +1,193 @@ +"""Migrate the BDC-Catalog to v1.0.0 + +See more in CHANGES.rst + +Revision ID: d01f09b5dd8b +Revises: 561ebe6266ad +Create Date: 2022-06-08 12:06:57.476168 + +""" +from alembic import op +import geoalchemy2.types +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from bdc_db.sqltypes import JSONB + +# revision identifiers, used by Alembic. +revision = 'd01f09b5dd8b' +down_revision = '561ebe6266ad' +branch_labels = () +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('processors', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(length=64), nullable=False), + sa.Column('facility', sa.String(length=255), nullable=False), + sa.Column('level', sa.String(length=32), nullable=False), + sa.Column('version', sa.String(length=32), nullable=False), + sa.Column('uri', sa.String(length=255), nullable=True), + sa.Column('metadata', JSONB('bdc-catalog/processor.json', astext_type=sa.Text()), nullable=True, comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('processors_pkey')), + sa.UniqueConstraint('name', 'version', name=op.f('processors_name_key')), + schema='bdc' + ) + op.create_table('items_processors', + sa.Column('item_id', sa.Integer(), nullable=False), + sa.Column('processor_id', sa.Integer(), nullable=False), + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.ForeignKeyConstraint(['item_id'], ['bdc.items.id'], name=op.f('items_processors_item_id_items_fkey'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['processor_id'], ['bdc.processors.id'], name=op.f('items_processors_processor_id_processors_fkey'), onupdate='CASCADE', ondelete='CASCADE'), + sa.PrimaryKeyConstraint('item_id', 'processor_id', name=op.f('items_processors_pkey')), + schema='bdc' + ) + op.drop_column('items', 'application_id', schema='bdc') + op.drop_table('applications', schema='bdc') + op.add_column('bands', sa.Column('scale_mult', sa.Numeric(), nullable=True, comment='The scale value multiplier'), schema='bdc') + op.add_column('bands', sa.Column('scale_add', sa.Numeric(), nullable=True, comment='The value to sum in scale mult'), schema='bdc') + op.create_index(op.f('idx_bdc_bands_resolution_unit_id'), 'bands', ['resolution_unit_id'], unique=False, schema='bdc') + op.drop_column('bands', 'center_wavelength', schema='bdc') + op.drop_column('bands', 'full_width_half_max', schema='bdc') + op.drop_column('bands', 'resolution_x', schema='bdc') + op.drop_column('bands', 'resolution_y', schema='bdc') + op.drop_column('bands', 'scale', schema='bdc') + + bind = op.get_bind() + collection_category_type = postgresql.ENUM('eo', 'sar', 'lidar', 'unknown', name='collection_category_type') + collection_category_type.create(bind) + + provider_role_type = postgresql.ENUM('licensor', 'producer', 'processor', 'host', name='provider_role_type') + provider_role_type.create(bind) + + op.add_column('collections', sa.Column('keywords', sa.ARRAY(sa.String()), nullable=True), schema='bdc') + op.add_column('collections', sa.Column('properties', JSONB('bdc-catalog/collection-properties.json'), nullable=True, comment='Contains the properties offered by STAC collections'), schema='bdc') + op.add_column('collections', sa.Column('summaries', JSONB('bdc-catalog/collection-summaries.json'), nullable=True, comment='Contains the STAC Collection summaries.'), schema='bdc') + op.add_column('collections', sa.Column('item_assets', JSONB('bdc-catalog/collection-item-assets.json'), nullable=True, comment='Contains the STAC Extension Item Assets.'), schema='bdc') + op.add_column('collections', sa.Column('is_available', sa.Boolean(), nullable=False), schema='bdc') + op.add_column('collections', sa.Column('category', sa.Enum('eo', 'sar', 'lidar', 'unknown', name='collection_category_type'), nullable=False), schema='bdc') + op.add_column('collections', sa.Column('spatial_extent', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') + op.alter_column('collections', 'version', + existing_type=sa.INTEGER(), + type_=sa.String(), + existing_nullable=False, + schema='bdc') + op.drop_index('idx_bdc_collections_extent', table_name='collections', schema='bdc') + op.create_index(op.f('idx_bdc_collections_category'), 'collections', ['category'], unique=False, schema='bdc') + op.create_index(op.f('idx_bdc_collections_is_available'), 'collections', ['is_available'], unique=False, schema='bdc') + op.create_index(op.f('idx_bdc_collections_is_public'), 'collections', ['is_public'], unique=False, schema='bdc') + op.create_index(op.f('idx_bdc_collections_spatial_extent'), 'collections', ['spatial_extent'], unique=False, schema='bdc', postgresql_using='gist') + op.create_index(op.f('idx_bdc_collections_start_date'), 'collections', ['start_date', 'end_date'], unique=False, schema='bdc') + op.drop_column('collections', 'extent', schema='bdc') + op.add_column('collections_providers', sa.Column('roles', sa.ARRAY(sa.Enum('licensor', 'producer', 'processor', 'host', name='provider_role_type')), nullable=False), schema='bdc') + op.create_index(op.f('idx_bdc_collections_providers_roles'), 'collections_providers', ['roles'], unique=False, schema='bdc') + op.drop_column('collections_providers', 'active', schema='bdc') + op.drop_column('collections_providers', 'priority', schema='bdc') + op.add_column('items', sa.Column('is_public', sa.Boolean(), server_default=sa.text('true'), nullable=False), schema='bdc') + op.add_column('items', sa.Column('is_available', sa.Boolean(), server_default=sa.text('false'), nullable=False), schema='bdc') + op.add_column('items', sa.Column('bbox', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') + op.add_column('items', sa.Column('footprint', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') + op.drop_index('idx_bdc_items_geom', table_name='items', schema='bdc') + op.drop_index('idx_bdc_items_min_convex_hull', table_name='items', schema='bdc') + op.create_index(op.f('idx_bdc_items_bbox'), 'items', ['bbox'], unique=False, schema='bdc', postgresql_using='gist') + op.create_index(op.f('idx_bdc_items_footprint'), 'items', ['footprint'], unique=False, schema='bdc', postgresql_using='gist') + op.create_index(op.f('idx_bdc_items_is_available'), 'items', ['is_available'], unique=False, schema='bdc') + op.create_index(op.f('idx_bdc_items_is_public'), 'items', ['is_public'], unique=False, schema='bdc') + op.create_index(op.f('idx_bdc_items_metadata'), 'items', ['metadata'], unique=False, schema='bdc') + op.drop_constraint('items_srid_spatial_ref_sys_fkey', 'items', schema='bdc', type_='foreignkey') + + op.execute('ALTER TABLE bdc.items DROP CONSTRAINT IF EXISTS items_application_id_applications_fkey') + + op.create_foreign_key(op.f('items_srid_spatial_ref_sys_fkey'), 'items', 'spatial_ref_sys', ['srid'], ['srid'], source_schema='bdc', referent_schema='public', onupdate='CASCADE', ondelete='CASCADE') + + op.execute('ALTER TABLE bdc.items DROP COLUMN IF EXISTS application_id') + + op.drop_column('items', 'geom', schema='bdc') + op.drop_column('items', 'min_convex_hull', schema='bdc') + op.add_column('providers', sa.Column('url', sa.String(length=255), nullable=True), schema='bdc') + op.drop_column('providers', 'credentials', schema='bdc') + op.drop_column('providers', 'uri', schema='bdc') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('providers', sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True), schema='bdc') + op.add_column('providers', sa.Column('credentials', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True, comment='Follow the JSONSchema @jsonschemas/provider-credentials.json'), schema='bdc') + op.drop_column('providers', 'url', schema='bdc') + op.add_column('items', sa.Column('min_convex_hull', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') + op.add_column('items', sa.Column('geom', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') + op.add_column('items', sa.Column('application_id', sa.INTEGER(), autoincrement=False, nullable=True), schema='bdc') + op.drop_constraint(op.f('items_srid_spatial_ref_sys_fkey'), 'items', schema='bdc', type_='foreignkey') + op.create_foreign_key('items_srid_spatial_ref_sys_fkey', 'items', 'spatial_ref_sys', ['srid'], ['srid'], source_schema='bdc', onupdate='CASCADE', ondelete='CASCADE') + op.drop_index(op.f('idx_bdc_items_metadata'), table_name='items', schema='bdc') + op.drop_index(op.f('idx_bdc_items_is_public'), table_name='items', schema='bdc') + op.drop_index(op.f('idx_bdc_items_is_available'), table_name='items', schema='bdc') + op.drop_index(op.f('idx_bdc_items_footprint'), table_name='items', schema='bdc', postgresql_using='gist') + op.drop_index(op.f('idx_bdc_items_bbox'), table_name='items', schema='bdc', postgresql_using='gist') + op.create_index('idx_bdc_items_min_convex_hull', 'items', ['min_convex_hull'], unique=False, schema='bdc') + op.create_index('idx_bdc_items_geom', 'items', ['geom'], unique=False, schema='bdc') + op.drop_column('items', 'footprint', schema='bdc') + op.drop_column('items', 'bbox', schema='bdc') + op.drop_column('items', 'is_available', schema='bdc') + op.drop_column('items', 'is_public', schema='bdc') + op.add_column('collections_providers', sa.Column('priority', sa.SMALLINT(), autoincrement=False, nullable=False), schema='bdc') + op.add_column('collections_providers', sa.Column('active', sa.BOOLEAN(), autoincrement=False, nullable=False), schema='bdc') + op.drop_index(op.f('idx_bdc_collections_providers_roles'), table_name='collections_providers', schema='bdc') + op.drop_column('collections_providers', 'roles', schema='bdc') + op.add_column('collections', sa.Column('extent', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') + op.drop_index(op.f('idx_bdc_collections_start_date'), table_name='collections', schema='bdc') + op.drop_index(op.f('idx_bdc_collections_spatial_extent'), table_name='collections', schema='bdc', postgresql_using='gist') + op.drop_index(op.f('idx_bdc_collections_is_public'), table_name='collections', schema='bdc') + op.drop_index(op.f('idx_bdc_collections_is_available'), table_name='collections', schema='bdc') + op.drop_index(op.f('idx_bdc_collections_category'), table_name='collections', schema='bdc') + op.create_index('idx_bdc_collections_extent', 'collections', ['extent'], unique=False, schema='bdc') + op.alter_column('collections', 'version', + existing_type=sa.String(), + type_=sa.INTEGER(), + existing_nullable=False, + schema='bdc') + op.drop_column('collections', 'spatial_extent', schema='bdc') + op.drop_column('collections', 'category', schema='bdc') + + bind = op.get_bind() + collection_category_type = postgresql.ENUM('eo', 'sar', 'lidar', 'unknown', name='collection_category_type') + collection_category_type.drop(bind, checkfirst=False) + postgresql.ENUM(name='provider_role_type').drop(bind) + + op.drop_column('collections', 'is_available', schema='bdc') + op.drop_column('collections', 'item_assets', schema='bdc') + op.drop_column('collections', 'summaries', schema='bdc') + op.drop_column('collections', 'properties', schema='bdc') + op.drop_column('collections', 'keywords', schema='bdc') + op.add_column('bands', sa.Column('scale', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + op.add_column('bands', sa.Column('resolution_y', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + op.add_column('bands', sa.Column('resolution_x', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + op.add_column('bands', sa.Column('full_width_half_max', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + op.add_column('bands', sa.Column('center_wavelength', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + op.drop_index(op.f('idx_bdc_bands_resolution_unit_id'), table_name='bands', schema='bdc') + op.drop_column('bands', 'scale_add', schema='bdc') + op.drop_column('bands', 'scale_mult', schema='bdc') + op.create_table('applications', + sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('bdc.applications_id_seq'::regclass)"), autoincrement=True, nullable=False), + sa.Column('name', sa.VARCHAR(length=64), autoincrement=False, nullable=False), + sa.Column('version', sa.VARCHAR(length=32), autoincrement=False, nullable=False), + sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True), + sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True, comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), + sa.Column('created', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False), + sa.Column('updated', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint('id', name='applications_pkey'), + sa.UniqueConstraint('name', 'version', name='applications_name_key'), + schema='bdc' + ) + op.add_column('items', sa.Column('application_id', sa.Integer(), nullable=True), + schema='bdc') + op.create_foreign_key('items_application_id_applications_fkey', 'items', 'applications', ['application_id'], ['id'], source_schema='bdc', referent_schema='bdc', onupdate='CASCADE', ondelete='CASCADE') + op.drop_table('items_processors', schema='bdc') + op.drop_table('processors', schema='bdc') + # ### end Alembic commands ### From fbe01ce41b48fbd1d840b9a218b945fe95ee6033 Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Tue, 14 Jun 2022 09:40:55 -0300 Subject: [PATCH 2/6] :construction: Add migration for 1.0, review revision id after lccs-db release --- bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py | 256 +++++++++++++-------- bdc_catalog/models/collection.py | 4 +- 2 files changed, 156 insertions(+), 104 deletions(-) diff --git a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py index 010eab3..b0a1c16 100644 --- a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py +++ b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py @@ -1,4 +1,4 @@ -"""Migrate the BDC-Catalog to v1.0.0 +"""BDC-Catalog to v1.0.0 See more in CHANGES.rst @@ -16,7 +16,7 @@ # revision identifiers, used by Alembic. revision = 'd01f09b5dd8b' -down_revision = '561ebe6266ad' +down_revision = '561ebe6266ad' # TODO: Change this revision code when LCCS-DB releases a new version. branch_labels = () depends_on = None @@ -24,39 +24,44 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.create_table('processors', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(length=64), nullable=False), - sa.Column('facility', sa.String(length=255), nullable=False), - sa.Column('level', sa.String(length=32), nullable=False), - sa.Column('version', sa.String(length=32), nullable=False), - sa.Column('uri', sa.String(length=255), nullable=True), - sa.Column('metadata', JSONB('bdc-catalog/processor.json', astext_type=sa.Text()), nullable=True, comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), - sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), - sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('processors_pkey')), - sa.UniqueConstraint('name', 'version', name=op.f('processors_name_key')), - schema='bdc' + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(length=64), nullable=False), + sa.Column('facility', sa.String(length=255), nullable=False), + sa.Column('level', sa.String(length=32), nullable=False), + sa.Column('version', sa.String(length=32), nullable=False), + sa.Column('uri', sa.String(length=255), nullable=True), + sa.Column('metadata', JSONB('bdc-catalog/processor.json', astext_type=sa.Text()), nullable=True, comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('processors_pkey')), + sa.UniqueConstraint('name', 'version', name=op.f('processors_name_key')), + schema='bdc' ) op.create_table('items_processors', - sa.Column('item_id', sa.Integer(), nullable=False), - sa.Column('processor_id', sa.Integer(), nullable=False), - sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), - sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), - sa.ForeignKeyConstraint(['item_id'], ['bdc.items.id'], name=op.f('items_processors_item_id_items_fkey'), onupdate='CASCADE', ondelete='CASCADE'), - sa.ForeignKeyConstraint(['processor_id'], ['bdc.processors.id'], name=op.f('items_processors_processor_id_processors_fkey'), onupdate='CASCADE', ondelete='CASCADE'), - sa.PrimaryKeyConstraint('item_id', 'processor_id', name=op.f('items_processors_pkey')), - schema='bdc' + sa.Column('item_id', sa.Integer(), nullable=False), + sa.Column('processor_id', sa.Integer(), nullable=False), + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.ForeignKeyConstraint(['item_id'], ['bdc.items.id'], name=op.f('items_processors_item_id_items_fkey'), onupdate='CASCADE', ondelete='CASCADE'), + sa.ForeignKeyConstraint(['processor_id'], ['bdc.processors.id'], name=op.f('items_processors_processor_id_processors_fkey'), onupdate='CASCADE', ondelete='CASCADE'), + sa.PrimaryKeyConstraint('item_id', 'processor_id', name=op.f('items_processors_pkey')), + schema='bdc' ) op.drop_column('items', 'application_id', schema='bdc') op.drop_table('applications', schema='bdc') - op.add_column('bands', sa.Column('scale_mult', sa.Numeric(), nullable=True, comment='The scale value multiplier'), schema='bdc') - op.add_column('bands', sa.Column('scale_add', sa.Numeric(), nullable=True, comment='The value to sum in scale mult'), schema='bdc') - op.create_index(op.f('idx_bdc_bands_resolution_unit_id'), 'bands', ['resolution_unit_id'], unique=False, schema='bdc') - op.drop_column('bands', 'center_wavelength', schema='bdc') - op.drop_column('bands', 'full_width_half_max', schema='bdc') - op.drop_column('bands', 'resolution_x', schema='bdc') - op.drop_column('bands', 'resolution_y', schema='bdc') - op.drop_column('bands', 'scale', schema='bdc') + + # Bands + with op.batch_alter_table('bands', schema='bdc') as bands_op: + bands_op.alter_column(column_name='scale', new_column_name='scale_mult') + bands_op.add_column(sa.Column('scale_add', sa.Numeric(), nullable=True, + comment='The value to sum in scale mult')) + bands_op.drop_column('center_wavelength') + bands_op.drop_column('full_width_half_max') + bands_op.drop_column('resolution_x') + bands_op.drop_column('resolution_y') + + op.create_index(op.f('idx_bdc_bands_resolution_unit_id'), 'bands', ['resolution_unit_id'], unique=False, + schema='bdc') bind = op.get_bind() collection_category_type = postgresql.ENUM('eo', 'sar', 'lidar', 'unknown', name='collection_category_type') @@ -65,33 +70,55 @@ def upgrade(): provider_role_type = postgresql.ENUM('licensor', 'producer', 'processor', 'host', name='provider_role_type') provider_role_type.create(bind) - op.add_column('collections', sa.Column('keywords', sa.ARRAY(sa.String()), nullable=True), schema='bdc') - op.add_column('collections', sa.Column('properties', JSONB('bdc-catalog/collection-properties.json'), nullable=True, comment='Contains the properties offered by STAC collections'), schema='bdc') - op.add_column('collections', sa.Column('summaries', JSONB('bdc-catalog/collection-summaries.json'), nullable=True, comment='Contains the STAC Collection summaries.'), schema='bdc') - op.add_column('collections', sa.Column('item_assets', JSONB('bdc-catalog/collection-item-assets.json'), nullable=True, comment='Contains the STAC Extension Item Assets.'), schema='bdc') - op.add_column('collections', sa.Column('is_available', sa.Boolean(), nullable=False), schema='bdc') - op.add_column('collections', sa.Column('category', sa.Enum('eo', 'sar', 'lidar', 'unknown', name='collection_category_type'), nullable=False), schema='bdc') - op.add_column('collections', sa.Column('spatial_extent', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') - op.alter_column('collections', 'version', - existing_type=sa.INTEGER(), - type_=sa.String(), - existing_nullable=False, - schema='bdc') + # Collections + with op.batch_alter_table('collections', schema='bdc') as collection_op: + collection_op.add_column(sa.Column('keywords', sa.ARRAY(sa.String()), nullable=True)) + collection_op.add_column(sa.Column('properties', JSONB('bdc-catalog/collection-properties.json'), + nullable=True, + comment='Contains the properties offered by STAC collections')) + collection_op.add_column(sa.Column('summaries', JSONB('bdc-catalog/collection-summaries.json'), + nullable=True, + comment='Contains the STAC Collection summaries.')) + collection_op.add_column(sa.Column('item_assets', JSONB('bdc-catalog/collection-item-assets.json'), + nullable=True, + comment='Contains the STAC Extension Item Assets.')) + collection_op.add_column(sa.Column('is_available', sa.Boolean(), nullable=False, server_default=sa.text('false'))) + collection_op.add_column(sa.Column('category', + sa.Enum('eo', 'sar', 'lidar', 'unknown', name='collection_category_type'), + nullable=False, + server_default='eo')) + collection_op.alter_column(column_name='extent', new_column_name='spatial_extent') + collection_op.alter_column(column_name='version', + existing_type=sa.INTEGER(), + type_=sa.String(), + existing_nullable=False,) + op.drop_index('idx_bdc_collections_extent', table_name='collections', schema='bdc') op.create_index(op.f('idx_bdc_collections_category'), 'collections', ['category'], unique=False, schema='bdc') op.create_index(op.f('idx_bdc_collections_is_available'), 'collections', ['is_available'], unique=False, schema='bdc') op.create_index(op.f('idx_bdc_collections_is_public'), 'collections', ['is_public'], unique=False, schema='bdc') op.create_index(op.f('idx_bdc_collections_spatial_extent'), 'collections', ['spatial_extent'], unique=False, schema='bdc', postgresql_using='gist') op.create_index(op.f('idx_bdc_collections_start_date'), 'collections', ['start_date', 'end_date'], unique=False, schema='bdc') - op.drop_column('collections', 'extent', schema='bdc') - op.add_column('collections_providers', sa.Column('roles', sa.ARRAY(sa.Enum('licensor', 'producer', 'processor', 'host', name='provider_role_type')), nullable=False), schema='bdc') + + # For Collection Providers table, identify version 0.8.0 before + op.execute('CREATE TABLE IF NOT EXISTS bdc.collections_providers_legacy AS ' + '(SELECT * FROM bdc.collections_providers)') + + op.add_column('collections_providers', + sa.Column('roles', sa.ARRAY(sa.Enum('licensor', 'producer', 'processor', 'host', + name='provider_role_type')), + nullable=False, server_default='{"host"}'), schema='bdc') op.create_index(op.f('idx_bdc_collections_providers_roles'), 'collections_providers', ['roles'], unique=False, schema='bdc') op.drop_column('collections_providers', 'active', schema='bdc') op.drop_column('collections_providers', 'priority', schema='bdc') - op.add_column('items', sa.Column('is_public', sa.Boolean(), server_default=sa.text('true'), nullable=False), schema='bdc') - op.add_column('items', sa.Column('is_available', sa.Boolean(), server_default=sa.text('false'), nullable=False), schema='bdc') - op.add_column('items', sa.Column('bbox', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') - op.add_column('items', sa.Column('footprint', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, spatial_index=False, from_text='ST_GeomFromEWKT', name='geometry'), nullable=True), schema='bdc') + + # Items + with op.batch_alter_table('items', schema='bdc') as item_op: + item_op.alter_column(column_name='geom', new_column_name='bbox') + item_op.alter_column(column_name='min_convex_hull', new_column_name='footprint') + item_op.add_column(sa.Column('is_public', sa.Boolean(), server_default=sa.text('true'), nullable=False)) + item_op.add_column(sa.Column('is_available', sa.Boolean(), server_default=sa.text('false'), nullable=False)) + op.drop_index('idx_bdc_items_geom', table_name='items', schema='bdc') op.drop_index('idx_bdc_items_min_convex_hull', table_name='items', schema='bdc') op.create_index(op.f('idx_bdc_items_bbox'), 'items', ['bbox'], unique=False, schema='bdc', postgresql_using='gist') @@ -107,8 +134,10 @@ def upgrade(): op.execute('ALTER TABLE bdc.items DROP COLUMN IF EXISTS application_id') - op.drop_column('items', 'geom', schema='bdc') - op.drop_column('items', 'min_convex_hull', schema='bdc') + # For Providers table 0.8.x + op.execute('CREATE TABLE IF NOT EXISTS bdc.providers_legacy AS ' + '(SELECT * FROM bdc.providers)') + op.add_column('providers', sa.Column('url', sa.String(length=255), nullable=True), schema='bdc') op.drop_column('providers', 'credentials', schema='bdc') op.drop_column('providers', 'uri', schema='bdc') @@ -117,77 +146,100 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('providers', sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True), schema='bdc') - op.add_column('providers', sa.Column('credentials', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True, comment='Follow the JSONSchema @jsonschemas/provider-credentials.json'), schema='bdc') - op.drop_column('providers', 'url', schema='bdc') - op.add_column('items', sa.Column('min_convex_hull', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') - op.add_column('items', sa.Column('geom', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') - op.add_column('items', sa.Column('application_id', sa.INTEGER(), autoincrement=False, nullable=True), schema='bdc') + with op.batch_alter_table('providers', schema='bdc') as provider_op: + provider_op.add_column(sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True)) + provider_op.add_column(sa.Column('credentials', postgresql.JSONB(astext_type=sa.Text()), + autoincrement=False, nullable=True, + comment='Follow the JSONSchema @jsonschemas/provider-credentials.json')) + provider_op.drop_column('url') + + with op.batch_alter_table('items', schema='bdc') as item_op: + item_op.alter_column(column_name='bbox', new_column_name='geom') + item_op.alter_column(column_name='footprint', new_column_name='min_convex_hull') + item_op.drop_column('is_available') + item_op.drop_column('is_public') + item_op.add_column(sa.Column('application_id', sa.INTEGER(), autoincrement=False, nullable=True)) + + op.create_table( + 'applications', + sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('bdc.applications_id_seq'::regclass)"), + autoincrement=True, nullable=False), + sa.Column('name', sa.VARCHAR(length=64), autoincrement=False, nullable=False), + sa.Column('version', sa.VARCHAR(length=32), autoincrement=False, nullable=False), + sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True), + sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True, + comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), + sa.Column('created', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, + nullable=False), + sa.Column('updated', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, + nullable=False), + sa.PrimaryKeyConstraint('id', name='applications_pkey'), + sa.UniqueConstraint('name', 'version', name='applications_name_key'), + schema='bdc' + ) + + op.create_foreign_key('items_application_id_applications_fkey', 'items', 'applications', ['application_id'], ['id'], + source_schema='bdc', referent_schema='bdc', onupdate='CASCADE', ondelete='CASCADE') + op.drop_constraint(op.f('items_srid_spatial_ref_sys_fkey'), 'items', schema='bdc', type_='foreignkey') op.create_foreign_key('items_srid_spatial_ref_sys_fkey', 'items', 'spatial_ref_sys', ['srid'], ['srid'], source_schema='bdc', onupdate='CASCADE', ondelete='CASCADE') op.drop_index(op.f('idx_bdc_items_metadata'), table_name='items', schema='bdc') - op.drop_index(op.f('idx_bdc_items_is_public'), table_name='items', schema='bdc') - op.drop_index(op.f('idx_bdc_items_is_available'), table_name='items', schema='bdc') + op.drop_index(op.f('idx_bdc_items_footprint'), table_name='items', schema='bdc', postgresql_using='gist') op.drop_index(op.f('idx_bdc_items_bbox'), table_name='items', schema='bdc', postgresql_using='gist') - op.create_index('idx_bdc_items_min_convex_hull', 'items', ['min_convex_hull'], unique=False, schema='bdc') - op.create_index('idx_bdc_items_geom', 'items', ['geom'], unique=False, schema='bdc') - op.drop_column('items', 'footprint', schema='bdc') - op.drop_column('items', 'bbox', schema='bdc') - op.drop_column('items', 'is_available', schema='bdc') - op.drop_column('items', 'is_public', schema='bdc') - op.add_column('collections_providers', sa.Column('priority', sa.SMALLINT(), autoincrement=False, nullable=False), schema='bdc') - op.add_column('collections_providers', sa.Column('active', sa.BOOLEAN(), autoincrement=False, nullable=False), schema='bdc') + op.create_index('idx_bdc_items_min_convex_hull', 'items', ['min_convex_hull'], unique=False, schema='bdc', postgresql_using='gist') + op.create_index('idx_bdc_items_geom', 'items', ['geom'], unique=False, schema='bdc', postgresql_using='gist') + + # Collection Providers/Providers: TODO: Use legacy tables to fill data + op.add_column('collections_providers', + sa.Column('priority', sa.SMALLINT(), autoincrement=False, nullable=False, server_default='1'), + schema='bdc') + op.add_column('collections_providers', + sa.Column('active', sa.BOOLEAN(), autoincrement=False, nullable=False, server_default='true'), + schema='bdc') op.drop_index(op.f('idx_bdc_collections_providers_roles'), table_name='collections_providers', schema='bdc') op.drop_column('collections_providers', 'roles', schema='bdc') - op.add_column('collections', sa.Column('extent', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', name='geometry'), autoincrement=False, nullable=True), schema='bdc') + op.add_column('collections', + sa.Column('extent', geoalchemy2.types.Geometry( + geometry_type='POLYGON', srid=4326, from_text='ST_GeomFromEWKT', + name='geometry', spatial_index=False + ), autoincrement=False, nullable=True), schema='bdc') op.drop_index(op.f('idx_bdc_collections_start_date'), table_name='collections', schema='bdc') op.drop_index(op.f('idx_bdc_collections_spatial_extent'), table_name='collections', schema='bdc', postgresql_using='gist') op.drop_index(op.f('idx_bdc_collections_is_public'), table_name='collections', schema='bdc') op.drop_index(op.f('idx_bdc_collections_is_available'), table_name='collections', schema='bdc') op.drop_index(op.f('idx_bdc_collections_category'), table_name='collections', schema='bdc') - op.create_index('idx_bdc_collections_extent', 'collections', ['extent'], unique=False, schema='bdc') - op.alter_column('collections', 'version', - existing_type=sa.String(), - type_=sa.INTEGER(), - existing_nullable=False, - schema='bdc') - op.drop_column('collections', 'spatial_extent', schema='bdc') - op.drop_column('collections', 'category', schema='bdc') + op.create_index('idx_bdc_collections_extent', 'collections', ['extent'], unique=False, schema='bdc', postgresql_using='gist') + + with op.batch_alter_table('collections', schema='bdc') as collection_op: + collection_op.alter_column('version', + existing_type=sa.String(), + type_=sa.INTEGER(), + existing_nullable=False, + postgresql_using='version::INTEGER') + collection_op.drop_column('spatial_extent') + collection_op.drop_column('category') + collection_op.drop_column('is_available') + collection_op.drop_column('item_assets') + collection_op.drop_column('summaries') + collection_op.drop_column('properties') + collection_op.drop_column('keywords') bind = op.get_bind() collection_category_type = postgresql.ENUM('eo', 'sar', 'lidar', 'unknown', name='collection_category_type') collection_category_type.drop(bind, checkfirst=False) postgresql.ENUM(name='provider_role_type').drop(bind) - op.drop_column('collections', 'is_available', schema='bdc') - op.drop_column('collections', 'item_assets', schema='bdc') - op.drop_column('collections', 'summaries', schema='bdc') - op.drop_column('collections', 'properties', schema='bdc') - op.drop_column('collections', 'keywords', schema='bdc') - op.add_column('bands', sa.Column('scale', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') - op.add_column('bands', sa.Column('resolution_y', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') - op.add_column('bands', sa.Column('resolution_x', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') - op.add_column('bands', sa.Column('full_width_half_max', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') - op.add_column('bands', sa.Column('center_wavelength', sa.NUMERIC(), autoincrement=False, nullable=True), schema='bdc') + with op.batch_alter_table('bands', schema='bdc') as band_op: + band_op.add_column(sa.Column('resolution_y', sa.NUMERIC(), autoincrement=False, nullable=True)) + band_op.add_column(sa.Column('resolution_x', sa.NUMERIC(), autoincrement=False, nullable=True)) + band_op.add_column(sa.Column('full_width_half_max', sa.NUMERIC(), autoincrement=False, nullable=True)) + band_op.add_column(sa.Column('center_wavelength', sa.NUMERIC(), autoincrement=False, nullable=True)) + band_op.drop_column('scale_add') + band_op.alter_column(column_name='scale_mult', new_column_name='scale') + op.drop_index(op.f('idx_bdc_bands_resolution_unit_id'), table_name='bands', schema='bdc') - op.drop_column('bands', 'scale_add', schema='bdc') - op.drop_column('bands', 'scale_mult', schema='bdc') - op.create_table('applications', - sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('bdc.applications_id_seq'::regclass)"), autoincrement=True, nullable=False), - sa.Column('name', sa.VARCHAR(length=64), autoincrement=False, nullable=False), - sa.Column('version', sa.VARCHAR(length=32), autoincrement=False, nullable=False), - sa.Column('uri', sa.VARCHAR(length=255), autoincrement=False, nullable=True), - sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True, comment='Follow the JSONSchema @jsonschemas/application-metadata.json'), - sa.Column('created', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False), - sa.Column('updated', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False), - sa.PrimaryKeyConstraint('id', name='applications_pkey'), - sa.UniqueConstraint('name', 'version', name='applications_name_key'), - schema='bdc' - ) - op.add_column('items', sa.Column('application_id', sa.Integer(), nullable=True), - schema='bdc') - op.create_foreign_key('items_application_id_applications_fkey', 'items', 'applications', ['application_id'], ['id'], source_schema='bdc', referent_schema='bdc', onupdate='CASCADE', ondelete='CASCADE') + op.drop_table('items_processors', schema='bdc') op.drop_table('processors', schema='bdc') # ### end Alembic commands ### diff --git a/bdc_catalog/models/collection.py b/bdc_catalog/models/collection.py index ed0b293..07042eb 100644 --- a/bdc_catalog/models/collection.py +++ b/bdc_catalog/models/collection.py @@ -57,8 +57,8 @@ class Collection(BaseModel): comment='Contains the STAC Collection summaries.') item_assets = Column('item_assets', JSONB('bdc-catalog/collection-item-assets.json'), comment='Contains the STAC Extension Item Assets.') - is_public = Column(Boolean(), nullable=False, default=True) - is_available = Column(Boolean(), nullable=False, default=False) + is_public = Column(Boolean(), nullable=False, default=True, server_default='True') + is_available = Column(Boolean(), nullable=False, default=False, server_default='False') category = Column(enum_collection_category, nullable=False) start_date = Column(TIMESTAMP(timezone=True)) end_date = Column(TIMESTAMP(timezone=True)) From 7d2720d79aae1ba6a30698431c38995e269a55f7 Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Thu, 21 Jul 2022 15:00:31 -0300 Subject: [PATCH 3/6] :arrow_up: Upgrade lccs-db to 0.8.1 --- bdc_catalog/ext.py | 13 ++++++------- bdc_catalog/models/collection.py | 10 +++++----- setup.py | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/bdc_catalog/ext.py b/bdc_catalog/ext.py index 649707d..f28d0b5 100644 --- a/bdc_catalog/ext.py +++ b/bdc_catalog/ext.py @@ -20,13 +20,12 @@ class BDCCatalog: """Image catalog extension. Examples: - >>> from flask import Flask - >>> app = Flask(__name__) - >>> catalog = BDCCatalog(app) - >>> # db Flask-SQLAlchemy instance - >>> db = catalog.db - >>> with app.app_context(): - >>> db.session.execute('SELECT 1') + >>> from flask import Flask # doctest: +SKIP + >>> app = Flask(__name__) # doctest: +SKIP + >>> catalog = BDCCatalog(app) # doctest: +SKIP + >>> db = catalog.db # doctest: +SKIP + >>> with app.app_context(): # doctest: +SKIP + >>> db.session.execute('SELECT 1') # doctest: +SKIP """ # Reference to BrazilDataCubeDB app instance diff --git a/bdc_catalog/models/collection.py b/bdc_catalog/models/collection.py index 07042eb..02c3744 100644 --- a/bdc_catalog/models/collection.py +++ b/bdc_catalog/models/collection.py @@ -8,14 +8,14 @@ """Model for the main table of image collections and data cubes.""" -from typing import List, Optional, Union +from typing import List, Union -from geoalchemy2 import Geometry from bdc_db.sqltypes import JSONB +from geoalchemy2 import Geometry from lccs_db.models import LucClassificationSystem -from sqlalchemy import (ARRAY, TIMESTAMP, Boolean, Column, Enum, ForeignKey, Index, - Integer, PrimaryKeyConstraint, String, - Text, UniqueConstraint) +from sqlalchemy import (ARRAY, TIMESTAMP, Boolean, Column, Enum, ForeignKey, + Index, Integer, PrimaryKeyConstraint, String, Text, + UniqueConstraint) from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship from sqlalchemy.sql.functions import func diff --git a/setup.py b/setup.py index 98163a0..ff0ca06 100644 --- a/setup.py +++ b/setup.py @@ -51,8 +51,8 @@ 'Flask-Alembic>=2.0.0', 'GeoAlchemy2>=0.8.4', 'py-multihash>=2,<3', - 'bdc-db @ git+https://github.com/brazil-data-cube/bdc-db@v0.6.0', - 'lccs-db @ git+https://github.com/brazil-data-cube/lccs-db@v0.8.0', + 'bdc-db @ git+https://github.com/brazil-data-cube/bdc-db@v0.6.3', + 'lccs-db @ git+https://github.com/brazil-data-cube/lccs-db@v0.8.1', ] packages = find_packages() From 354ce6f689c8500411c0807aae6869ff44f4f773 Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Thu, 21 Jul 2022 15:01:03 -0300 Subject: [PATCH 4/6] :bug: Fix migration init and :heavy_check_mark: update tests --- bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py | 4 ++-- tests/conftest.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py index b0a1c16..30f9bbb 100644 --- a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py +++ b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py @@ -16,9 +16,9 @@ # revision identifiers, used by Alembic. revision = 'd01f09b5dd8b' -down_revision = '561ebe6266ad' # TODO: Change this revision code when LCCS-DB releases a new version. +down_revision = 'c68b17b1860b' branch_labels = () -depends_on = None +depends_on = '561ebe6266ad' # TODO: Change this revision code when LCCS-DB releases a new version. def upgrade(): diff --git a/tests/conftest.py b/tests/conftest.py index f0087bc..75fedfd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,9 +25,13 @@ def app(): def pytest_sessionstart(session): """Load BDC-Catalog and prepare database environment.""" - for command in ['init', 'create-namespaces', 'create-extension-postgis', 'create-schema']: + for command in ['init', 'create-namespaces', 'create-extension-postgis']: subprocess.call(f'bdc-catalog db {command}', shell=True) + subprocess.call(f'lccs-db db create-extension-hstore', shell=True) + # Create tables + subprocess.call(f'bdc-catalog db create-schema', shell=True) + def pytest_sessionfinish(session, exitstatus): """Destroy database created.""" From 388f267b48f139ced1dfa31451a34caa3bff05fd Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Thu, 21 Jul 2022 15:10:13 -0300 Subject: [PATCH 5/6] :bookmark: Prepare to release 1.0.0-alpha1 --- CHANGES.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 1a7ddec..b7d6ee2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,18 @@ Changes ======= +Version 1.0.0-alpha1 (2022-07-21) +-------------------------- + +- Add authorization control to items `#78 `_. +- Review JSONSchemas for collection metadata - instrument key `#68 `_. +- Use JSONSchemas to validate any JSONB field in bdc-catalog +- Fix timeline trigger related item end_date `#159 `_. +- Review field names for v1.0 `#140 `_. +- Review version property - use float/string instead int `#144 `_. +- Add new fields for 1.0 - properties according STAC and srid `#157 `_. + + Version 0.8.2 (2022-03-25) -------------------------- From a34fe1167d16b6fbabae61caa61e8bba9354835a Mon Sep 17 00:00:00 2001 From: "raphael.wcosta@gmail.com" Date: Thu, 21 Jul 2022 15:20:10 -0300 Subject: [PATCH 6/6] :zap: Remove extra dependency bdc-db since it already defined in lccs-dc --- bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py | 2 +- setup.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py index 30f9bbb..cc607ce 100644 --- a/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py +++ b/bdc_catalog/alembic/d01f09b5dd8b_v1_0_0.py @@ -18,7 +18,7 @@ revision = 'd01f09b5dd8b' down_revision = 'c68b17b1860b' branch_labels = () -depends_on = '561ebe6266ad' # TODO: Change this revision code when LCCS-DB releases a new version. +depends_on = '561ebe6266ad' # LCCS-DB stable 0.8.1 def upgrade(): diff --git a/setup.py b/setup.py index ff0ca06..4109374 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,6 @@ 'Flask-Alembic>=2.0.0', 'GeoAlchemy2>=0.8.4', 'py-multihash>=2,<3', - 'bdc-db @ git+https://github.com/brazil-data-cube/bdc-db@v0.6.3', 'lccs-db @ git+https://github.com/brazil-data-cube/lccs-db@v0.8.1', ]