diff --git a/src/main/java/ogc/rs/apiserver/ApiServerVerticle.java b/src/main/java/ogc/rs/apiserver/ApiServerVerticle.java index 6fc12202..b1b32c8c 100644 --- a/src/main/java/ogc/rs/apiserver/ApiServerVerticle.java +++ b/src/main/java/ogc/rs/apiserver/ApiServerVerticle.java @@ -898,6 +898,28 @@ private JsonObject buildCollectionFeatureResult(List success) { .put("templated","true"))) .put("itemType", "feature") .put("crs", collection.getJsonArray("crs")); + if (collection.getJsonArray("enclosure") != null && !collection.getJsonArray("enclosure").isEmpty()) { + collection.getJsonArray("enclosure") + .forEach(enclosureJson -> { + // Ensure the enclosure is not null + if (enclosureJson != null) { + JsonObject enclosure = new JsonObject(); + enclosure.mergeIn((JsonObject) enclosureJson); + String href = + hostName + ogcBasePath + "assets/" + enclosure.getString("id"); + enclosure.put("href", href); + enclosure.put("rel", "enclosure"); + enclosure.put("length", enclosure.getInteger("size")); + enclosure.remove("size"); + enclosure.remove("id"); + enclosure.remove("collections_id"); + // enclosure.remove("role"); + collection.getJsonArray("links").add(enclosure); + } + }); + collection.remove("enclosure"); + } + if (success.get(0).getJsonArray("type").contains("COVERAGE")) { collection .getJsonArray("links") diff --git a/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionMetadata.java b/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionMetadata.java index 5630823f..d6564c42 100644 --- a/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionMetadata.java +++ b/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionMetadata.java @@ -72,30 +72,4 @@ public JsonObject generateOgcOasBlock() { return block; } - /** - * - * Generate OpenAPI JSON block for all STAC routes that this collection can have. - * - * @return JSON object containing OpenAPI paths for all STAC routes for this collection. - */ - public JsonObject generateStacOasBlock() { - JsonObject block = new JsonObject(); - - /* GET /stac/collections/ */ - JsonObject collectionSpecific = new JsonObject(); - - collectionSpecific.put("tags", new JsonArray().add(title)); - collectionSpecific.put("summary", STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_SUMMARY.get()); - collectionSpecific.put("operationId", STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OPERATION_ID.get()); - collectionSpecific.put("responses", - new JsonObject() - .put("200", new JsonObject().put("$ref", "#/components/responses/stacCollection")) - .put("404", new JsonObject().put("$ref", "#/components/responses/NotFound")) - .put("500", new JsonObject().put("$ref", "#/components/responses/ServerError"))); - - block.put(STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_ENDPOINT.get(), - new JsonObject().put("get", collectionSpecific)); - - return block; - } } diff --git a/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionsEntity.java b/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionsEntity.java index 4b666c42..80126be0 100644 --- a/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionsEntity.java +++ b/src/main/java/ogc/rs/apiserver/router/gisentities/ogccollections/OgcCollectionsEntity.java @@ -60,22 +60,6 @@ public void giveOgcRoutes(OgcRouterBuilder ogcRouterBuilder) { @Override public void giveStacRoutes(StacRouterBuilder stacRouterBuilder) { - RouterBuilder builder = stacRouterBuilder.routerBuilder; - ApiServerVerticle apiServerVerticle = stacRouterBuilder.apiServerVerticle; - FailureHandler failureHandler = stacRouterBuilder.failureHandler; - - List collectionSpecificOpIds = builder.operations().stream() - .filter(op -> op.getOperationId().matches(OgcCollectionMetadata.STAC_OP_ID_PREFIX_REGEX)) - .map(op -> op.getOperationId()).collect(Collectors.toList()); - - collectionSpecificOpIds.forEach(opId -> { - if (opId.matches(OgcCollectionMetadata.STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OP_ID_REGEX)) { - builder.operation(opId).handler(apiServerVerticle::getStacCollection) - .handler(apiServerVerticle::putCommonResponseHeaders) - .handler(apiServerVerticle::buildResponse) - .failureHandler(failureHandler); - } - }); } @Override @@ -108,16 +92,13 @@ public Future generateNewSpecFragments(JsonObject existingOgcSpec, Future result = metadataObjList.compose(list -> { List ogcFrags = new ArrayList(); - List stacFrags = new ArrayList(); list.forEach(obj -> { ogcFrags.add(obj.generateOgcOasBlock()); - stacFrags.add(obj.generateStacOasBlock()); }); OasFragments fragments = new OasFragments(); fragments.setOgc(ogcFrags); - fragments.setStac(stacFrags); return Future.succeededFuture(fragments); }); diff --git a/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionMetadata.java b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionMetadata.java new file mode 100644 index 00000000..680d510d --- /dev/null +++ b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionMetadata.java @@ -0,0 +1,85 @@ +package ogc.rs.apiserver.router.gisentities.staccollections; + +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; + +import java.util.UUID; +import java.util.function.Supplier; + +/** Class used to hold STAC Collection metadata */ +public class StacCollectionMetadata { + public static final String STAC_OP_ID_PREFIX_REGEX = "^itemlessStacCollection-.*"; + public static final String STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OP_ID_REGEX = + "^itemlessStacCollection-.*-get-specific-collection$"; + public static final String STAC_GET_ITEMS_COLLECTION_OP_ID_REGEX = + "^itemlessStacCollection-.*-get-items$"; + + private UUID id; + private String title; + private String description; + + private final Supplier STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_SUMMARY = + () -> "Metadata about " + description; + private final Supplier STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OPERATION_ID = + () -> "itemlessStacCollection-" + id.toString() + "-get-specific-collection"; + private final Supplier STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_ENDPOINT = + () -> "/stac/collections/" + id.toString(); + + private final Supplier STAC_GET_COLLECTION_ITEMS_SUMMARY = + () -> "Get items from " + description; + private final Supplier STAC_GET_COLLECTION_ITEMS_OPERATION_ID = + () -> "itemlessStacCollection-" + id.toString() + "-get-items"; + private final Supplier STAC_GET_COLLECTION_ITEMS_ENDPOINT = + () -> "/stac/collections/" + id.toString() + "/items"; + + public StacCollectionMetadata(JsonObject obj) { + id = UUID.fromString(obj.getString("id")); + title = obj.getString("title", "Undefined title"); + description = obj.getString("description", "Undefined description"); + } + + public UUID getId() { + return id; + } + + /** + * Generate OpenAPI JSON block for all STAC routes that this collection can have. + * + * @return JSON object containing OpenAPI paths for all STAC routes for this collection. + */ + public JsonObject generateStacOasBlock() { + JsonObject block = new JsonObject(); + + /* GET /stac/collections/ */ + JsonObject collectionSpecific = new JsonObject(); + + collectionSpecific.put("tags", new JsonArray().add(title)); + collectionSpecific.put("summary", STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_SUMMARY.get()); + collectionSpecific.put("operationId", STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OPERATION_ID.get()); + collectionSpecific.put( + "responses", + new JsonObject() + .put("200", new JsonObject().put("$ref", "#/components/responses/stacCollection")) + .put("404", new JsonObject().put("$ref", "#/components/responses/NotFound")) + .put("500", new JsonObject().put("$ref", "#/components/responses/ServerError"))); + + block.put( + STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_ENDPOINT.get(), + new JsonObject().put("get", collectionSpecific)); + + /* GET stac/collections//items */ + JsonObject stacItems = new JsonObject(); + stacItems.put("tags", new JsonArray().add(title)); + stacItems.put("summary", STAC_GET_COLLECTION_ITEMS_SUMMARY.get()); + stacItems.put("operationId", STAC_GET_COLLECTION_ITEMS_OPERATION_ID.get()); + stacItems.put( + "responses", + new JsonObject() + .put("200", new JsonObject().put("$ref", "#/components/responses/StacFeatures")) + .put("404", new JsonObject().put("$ref", "#/components/responses/NotFound")) + .put("500", new JsonObject().put("$ref", "#/components/responses/ServerError"))); + block.put(STAC_GET_COLLECTION_ITEMS_ENDPOINT.get(), new JsonObject().put("get", stacItems)); + + return block; + } +} diff --git a/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionsEntity.java b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionsEntity.java new file mode 100644 index 00000000..b9de31a9 --- /dev/null +++ b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/StacCollectionsEntity.java @@ -0,0 +1,139 @@ +package ogc.rs.apiserver.router.gisentities.staccollections; + +import com.google.auto.service.AutoService; +import io.vertx.core.Future; +import io.vertx.core.Promise; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.openapi.RouterBuilder; +import ogc.rs.apiserver.ApiServerVerticle; +import ogc.rs.apiserver.handlers.FailureHandler; +import ogc.rs.apiserver.router.gisentities.GisEntityInterface; +import ogc.rs.apiserver.router.gisentities.ogccollections.OgcCollectionMetadata; +import ogc.rs.apiserver.router.gisentities.ogccollections.OgcCollectionsEntity; +import ogc.rs.apiserver.router.routerbuilders.OgcRouterBuilder; +import ogc.rs.apiserver.router.routerbuilders.StacRouterBuilder; +import ogc.rs.apiserver.router.util.OasFragments; +import ogc.rs.database.DatabaseService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Class to handle creation of routes for /stac/collection/ for OGC collections. + */ +@AutoService(GisEntityInterface.class) +public class StacCollectionsEntity implements GisEntityInterface { + + private static final String UUID_REGEX = + "[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}"; + private static final String STAC_COLLECTION_PATH_REGEX = "^stac/collections/" + UUID_REGEX; + + private static final Logger LOGGER = LogManager.getLogger(StacCollectionsEntity.class); + + @Override + public void giveOgcRoutes(OgcRouterBuilder routerBuilder) {} + + @Override + public void giveStacRoutes(StacRouterBuilder stacRouterBuilder) { + RouterBuilder builder = stacRouterBuilder.routerBuilder; + ApiServerVerticle apiServerVerticle = stacRouterBuilder.apiServerVerticle; + FailureHandler failureHandler = stacRouterBuilder.failureHandler; + + List collectionSpecificOpIds = + builder.operations().stream() + .filter( + op -> op.getOperationId().matches(StacCollectionMetadata.STAC_OP_ID_PREFIX_REGEX)) + .map(op -> op.getOperationId()) + .collect(Collectors.toList()); + + collectionSpecificOpIds.forEach( + opId -> { + if (opId.matches( + StacCollectionMetadata.STAC_GET_SPECIFIC_ITEMLESS_COLLECTION_OP_ID_REGEX)) { + builder + .operation(opId) + .handler(apiServerVerticle::getStacCollection) + .handler(apiServerVerticle::putCommonResponseHeaders) + .handler(apiServerVerticle::buildResponse) + .failureHandler(failureHandler); + } else if (opId.matches(StacCollectionMetadata.STAC_GET_ITEMS_COLLECTION_OP_ID_REGEX)) { + builder + .operation(opId) + .handler(apiServerVerticle::getStacItems) + .handler(apiServerVerticle::putCommonResponseHeaders) + .handler(apiServerVerticle::buildResponse) + .failureHandler(failureHandler); + } + }); + } + + @Override + public Future generateNewSpecFragments( + JsonObject existingOgcSpec, + JsonObject existingStacSpec, + DatabaseService dbService, + JsonObject config) { + Promise promise = Promise.promise(); + Set existingCollectionIds = getExistingCollectionsFromOgcSpec(existingStacSpec); + + Future> stacCollectionMetadata = + dbService.getStacCollectionMetadataForOasSpec( + existingCollectionIds.stream().map(i -> i.toString()).collect(Collectors.toList())); + + Future> metadataObjList = + stacCollectionMetadata.compose( + res -> { + List list = + res.stream().map(i -> new StacCollectionMetadata(i)).collect(Collectors.toList()); + + List foundCollectionIds = + list.stream().map(obj -> obj.getId().toString()).collect(Collectors.toList()); + + if (foundCollectionIds.isEmpty()) { + LOGGER.info("No new STAC collections found!"); + } else { + LOGGER.info("New STAC collections found : {}", foundCollectionIds); + } + + return Future.succeededFuture(list); + }); + + Future result = + metadataObjList.compose( + list -> { + List stacFrags = new ArrayList(); + + list.forEach( + obj -> { + stacFrags.add(obj.generateStacOasBlock()); + }); + + OasFragments fragments = new OasFragments(); + fragments.setStac(stacFrags); + + return Future.succeededFuture(fragments); + }); + + result.onSuccess(i -> promise.complete(i)).onFailure(err -> promise.fail(err)); + return promise.future(); + } + + private Set getExistingCollectionsFromOgcSpec(JsonObject ogcSpec) { + Set existingIds = new HashSet(); + + ogcSpec + .getJsonObject("paths") + .forEach( + k -> { + String key = k.getKey(); + if (key.matches(STAC_COLLECTION_PATH_REGEX)) { + String collectionId = key.split("/")[2]; + existingIds.add(UUID.fromString(collectionId)); + } + }); + + return existingIds; + } +} diff --git a/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/package-info.java b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/package-info.java new file mode 100644 index 00000000..cf49bfab --- /dev/null +++ b/src/main/java/ogc/rs/apiserver/router/gisentities/staccollections/package-info.java @@ -0,0 +1 @@ +package ogc.rs.apiserver.router.gisentities.staccollections; \ No newline at end of file diff --git a/src/main/java/ogc/rs/database/DatabaseService.java b/src/main/java/ogc/rs/database/DatabaseService.java index 27a46c30..2822cfce 100644 --- a/src/main/java/ogc/rs/database/DatabaseService.java +++ b/src/main/java/ogc/rs/database/DatabaseService.java @@ -79,8 +79,16 @@ Future getFeature(String collectionId, Integer featureId, Map> getCollectionMetadataForOasSpec(List existingCollectionUuidIds); - - + + /** + * Get all STAC collections metadata to be used for OpenAPI spec generation. + * + * @param existingCollectionUuidIds UUID IDs of collections that are already part of the spec. + * @return list of {@link JsonObject}, which is cast to the required type by the caller. + */ + Future> getStacCollectionMetadataForOasSpec(List existingCollectionUuidIds); + + /** * Run STAC Item Search query given query params in {@link StacItemSearchParams} object. * diff --git a/src/main/java/ogc/rs/database/DatabaseServiceImpl.java b/src/main/java/ogc/rs/database/DatabaseServiceImpl.java index b9790df3..c3755e9e 100644 --- a/src/main/java/ogc/rs/database/DatabaseServiceImpl.java +++ b/src/main/java/ogc/rs/database/DatabaseServiceImpl.java @@ -42,6 +42,7 @@ public Future> getCollection(String collectionId) { LOGGER.info("getCollection"); Promise> result = Promise.promise(); Collector> collector = Collectors.mapping(Row::toJson, Collectors.toList()); + Collector> enclosureCollector = Collectors.mapping(Row::toJson, Collectors.toList()); client.withConnection(conn -> conn.preparedQuery("select collections_details.id, title, array_agg(distinct crs_to_srid.crs) as crs" + ", collections_details.crs as \"storageCrs\", description, datetime_key, bbox, temporal," + @@ -49,18 +50,35 @@ public Future> getCollection(String collectionId) { " from collections_details join collection_supported_crs" + " on collections_details.id = collection_supported_crs.collection_id join crs_to_srid" + " on crs_to_srid.id = collection_supported_crs.crs_id join collection_type" + - " on collections_details.id=collection_type.collection_id group by collections_details.id" + + " on collections_details.id=collection_type.collection_id where collection_type.type != 'STAC' group by collections_details.id" + " having collections_details.id = $1::uuid") .collecting(collector) - .execute(Tuple.of(UUID.fromString( collectionId))).map(SqlResult::value)) - .onSuccess(success -> { - LOGGER.debug("Built OGC Collection Response - {}", success); - result.complete(success); + .execute(Tuple.of(UUID.fromString( collectionId))).map(SqlResult::value) + .onSuccess(success -> { + String query = + "SELECT * from collections_enclosure where collections_id = $1::uuid"; + conn.preparedQuery(query) + .collecting(enclosureCollector) + .execute(Tuple.of(UUID.fromString(collectionId))) + .map(SqlResult::value) + .onSuccess( + enclosureResult-> { + if (!enclosureResult.isEmpty()) { + success.get(0).put("enclosure", enclosureResult); + } + result.complete(success); + }) + .onFailure( + failed -> { + LOGGER.error("Failed at getFeature- {}", failed.getMessage()); + result.fail("Error!"); + }); + }) .onFailure(fail -> { LOGGER.error("Failed at getCollection- {}",fail.getMessage()); result.fail("Error!"); - }); + })); return result.future(); } @@ -69,13 +87,14 @@ public Future> getCollections() { Promise> result = Promise.promise(); Collector> collector = Collectors.mapping(Row::toJson, Collectors.toList()); client.withConnection(conn -> - conn.preparedQuery("select collections_details.id, title, array_agg(distinct crs_to_srid.crs) as crs" + - ", collections_details.crs as \"storageCrs\", description, datetime_key, bbox, temporal" + - ", array_agg(distinct collection_type.type) as type" + - " from collections_details join collection_supported_crs" + - " on collections_details.id = collection_supported_crs.collection_id join crs_to_srid" + - " on crs_to_srid.id = collection_supported_crs.crs_id join collection_type" + - " on collections_details.id = collection_type.collection_id group by collections_details.id") + conn.preparedQuery("select collections_details.id, collections_details.title, array_agg(DISTINCT crs_to_srid.crs) as crs" + + " , collections_details.crs as \"storageCrs\", collections_details.description, collections_details.datetime_key, " + + " collections_details.bbox, collections_details.temporal, jsonb_agg(distinct(row_to_json(collections_enclosure.*)::jsonb " + + " - 'collections_id')) AS enclosure, ARRAY_AGG(DISTINCT collection_type.type) AS type FROM collections_details LEFT " + + " JOIN collections_enclosure ON collections_details.id = collections_enclosure.collections_id JOIN collection_supported_crs ON " + + " collections_details.id = collection_supported_crs.collection_id JOIN crs_to_srid ON crs_to_srid.id = " + + " collection_supported_crs.crs_id JOIN collection_type ON collections_details.id = collection_type.collection_id " + + " WHERE collection_type.type != 'STAC' GROUP BY collections_details.id;") .collecting(collector) .execute() .map(SqlResult::value)) @@ -279,7 +298,10 @@ public Future> getStacCollections() { client.withConnection( conn -> conn.preparedQuery( - "Select id, title, description, bbox, temporal,license from collections_details") + "Select collections_details.id, title, description," + + " bbox, temporal, license FROM collections_details JOIN collection_type " + + "ON collections_details.id = collection_type.collection_id WHERE " + + "collection_type.type = 'STAC' ") .collecting(collector) .execute() .map(SqlResult::value) @@ -369,14 +391,18 @@ public Future getStacCollection(String collectionId) { client.withConnection( conn -> conn.preparedQuery( - "SELECT id, title, description, bbox, temporal, license FROM collections_details where id = $1::uuid") + "SELECT collections_details.id, title, " + + "description, bbox, temporal, license FROM collections_details " + + "JOIN collection_type ON collections_details.id = collection_type.collection_id " + + "WHERE collection_type.type = 'STAC' AND collections_details.id = $1::uuid ") .collecting(collector) .execute(Tuple.of(UUID.fromString(collectionId))) .map(SqlResult::value) .onSuccess( success -> { LOGGER.debug("DB result - {}", success); - if (success.equals(0)) { + if (success.isEmpty()) { + LOGGER.debug("Stac Collection of id {} Not Found!", collectionId); result.fail(new OgcException(404, "Not found", "Collection not found")); } JsonObject collection = success.get(0); @@ -661,9 +687,27 @@ public Future getAssets(String assetId) { .onSuccess(successAsset -> { if (successAsset.isEmpty()) { LOGGER.error("Given asset is not present in either stac_collections_assets or " + - "stac_items_assets table"); - result.fail(new OgcException(404, "Not found", "Asset not found")); - } + "stac_items_assets table. Trying collections_enclosure table."); + client.withConnection(conn2 -> + conn2.preparedQuery("select * from collections_enclosure where id = $1::uuid") + .collecting(collector) + .execute(Tuple.of(UUID.fromString(assetId))) + .map(SqlResult::value) + .onSuccess(successAssetEnclosure -> { + if (successAssetEnclosure.isEmpty()) { + LOGGER.error(" Given asset is not present in either stac_collection_assets, " + + "stac_items_assets table or collections_enclosure"); + result.fail(new OgcException(404, "Not found", "Asset not found")); + } else { + LOGGER.debug("Asset Result: {}", successAsset.get(0)); + result.complete(successAsset.get(0)); + } + }) + .onFailure(failedAssetEnclosure -> { + LOGGER.error("Failed to get assets! - {}", failedAssetEnclosure.getMessage()); + result.fail("Error!"); + })); + } else { LOGGER.debug("Asset Result: {}", successAsset.get(0)); result.complete(successAsset.get(0)); @@ -936,7 +980,9 @@ public Future> getCollectionMetadataForOasSpec( Collectors.mapping(Row::toJson, Collectors.toList()); final String GET_COLLECTION_INFO = - " SELECT id, title, description FROM collections_details WHERE id != ALL($1::UUID[])"; + "SELECT collections_details.id, title, description FROM collections_details " + + "JOIN collection_type ON collections_details.id = collection_type.collection_id " + + "WHERE collections_details.id != ALL($1::UUID[]) AND collection_type.type != 'STAC'"; Future> newCollectionsJson = client.withConnection( @@ -958,4 +1004,42 @@ public Future> getCollectionMetadataForOasSpec( return result.future(); } + + @Override + public Future> getStacCollectionMetadataForOasSpec( + List existingCollectionUuidIds) { + + Promise> result = Promise.promise(); + + UUID[] existingCollectionIdsArr = + existingCollectionUuidIds.stream().map(i -> UUID.fromString(i)).toArray(UUID[]::new); + + Collector> collector = + Collectors.mapping(Row::toJson, Collectors.toList()); + + final String GET_STAC_COLLECTION_INFO = + "SELECT collections_details.id, title, description FROM collections_details JOIN " + + "collection_type ON collections_details.id = collection_type.collection_id WHERE " + + "collections_details.id != ALL($1::UUID[]) AND collection_type.type = 'STAC'"; + + Future> newCollectionsJson = + client.withConnection( + conn -> + conn.preparedQuery(GET_STAC_COLLECTION_INFO) + .collecting(collector) + .execute(Tuple.of(existingCollectionIdsArr)) + .map(res -> res.value())); + + newCollectionsJson + .onSuccess(succ -> result.complete(succ)) + .onFailure( + fail -> { + LOGGER.error( + "Something went wrong when querying DB for new OGC collections {}", + fail.getMessage()); + result.fail(fail); + }); + + return result.future(); + } } diff --git a/src/main/resources/db/migration/V18__add_collections_enclosure_table.sql b/src/main/resources/db/migration/V18__add_collections_enclosure_table.sql new file mode 100644 index 00000000..f69a622f --- /dev/null +++ b/src/main/resources/db/migration/V18__add_collections_enclosure_table.sql @@ -0,0 +1,20 @@ +CREATE TABLE collections_enclosure ( + id UUID PRIMARY KEY DEFAULT public.gen_random_uuid(), + collections_id UUID REFERENCES collections_details(id) NOT NULL, + title VARCHAR(255) NOT NULL, + href VARCHAR(255) NOT NULL, + type VARCHAR(50) NOT NULL, + size BIGINT NOT NULL, + CONSTRAINT unique_enclosure UNIQUE (collections_id, title) +); + +INSERT INTO collections_enclosure (id, collections_id, title, href, type, size) +SELECT id, stac_collections_id, title, href, type, size +FROM stac_collections_assets; + +CREATE INDEX idx_collections_enclosure_collections_id +ON collections_enclosure (collections_id); + +GRANT SELECT, INSERT, DELETE ON collections_enclosure TO ${ogcUser} + +