/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.constellation.database.impl.repository; import org.constellation.database.api.domain.Page; import org.constellation.database.api.domain.PageImpl; import org.constellation.database.api.domain.Pageable; import org.constellation.database.api.jooq.tables.Data; import org.constellation.database.api.jooq.tables.pojos.Dataset; import org.constellation.database.api.jooq.tables.pojos.Metadata; import org.constellation.database.api.jooq.tables.pojos.MetadataXCsw; import org.constellation.database.api.jooq.tables.records.DatasetRecord; import org.constellation.database.api.jooq.tables.records.MetadataXCswRecord; import org.constellation.database.api.pojo.DatasetItem; import org.constellation.database.api.repository.DatasetRepository; import org.constellation.database.impl.jooq.util.JooqUtils; import org.jooq.CommonTableExpression; import org.jooq.Condition; import org.jooq.Field; import org.jooq.Record2; import org.jooq.UpdateConditionStep; import org.jooq.impl.DSL; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.List; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.constellation.database.api.jooq.Tables.CSTL_USER; import static org.constellation.database.api.jooq.Tables.DATA; import static org.constellation.database.api.jooq.Tables.DATASET; import static org.constellation.database.api.jooq.Tables.LAYER; import static org.constellation.database.api.jooq.Tables.METADATA; import static org.constellation.database.api.jooq.Tables.METADATA_X_CSW; import static org.constellation.database.api.jooq.Tables.SENSORED_DATA; /** * * @author Guilhem Legal */ @Component public class JooqDatasetRepository extends AbstractJooqRespository<DatasetRecord, Dataset> implements DatasetRepository { private static final CommonTableExpression<Record2<Integer, Integer>> FETCH_PAGE_WITH = DSL.name("w").fields("id", "count").as(DSL.select(DATA.DATASET_ID, DSL.count(DATA.ID)). from(DATA). where(isIncludedAndNotHiddenData(DATA)). groupBy(DATA.DATASET_ID)); private static final Field[] ITEM_FIELDS = new Field[]{ DATASET.ID.as("id"), DATASET.IDENTIFIER.as("name"), DATASET.DATE.as("creation_date"), DATASET.OWNER.as("owner_id"), CSTL_USER.LOGIN.as("owner_login"), FETCH_PAGE_WITH.field("count").as("data_count") }; public JooqDatasetRepository() { super(Dataset.class, DATASET); } @Override @Transactional(propagation = Propagation.MANDATORY) public Dataset insert(Dataset dataset) { DatasetRecord newRecord = dsl.newRecord(DATASET); newRecord.setIdentifier(dataset.getIdentifier()); newRecord.setOwner(dataset.getOwner()); newRecord.setDate(dataset.getDate()); newRecord.setFeatureCatalog(dataset.getFeatureCatalog()); newRecord.store(); return newRecord.into(Dataset.class); } @Override @Transactional(propagation = Propagation.MANDATORY) public int update(Dataset dataset) { DatasetRecord datasetRecord = new DatasetRecord(); datasetRecord.from(dataset); UpdateConditionStep<DatasetRecord> set = dsl.update(DATASET) .set(DATASET.IDENTIFIER, dataset.getIdentifier()) .set(DATASET.OWNER, dataset.getOwner()) .set(DATASET.DATE, dataset.getDate()) .set(DATASET.FEATURE_CATALOG, dataset.getFeatureCatalog()) .where(DATASET.ID.eq(dataset.getId())); return set.execute(); } @Override public Dataset findByMetadataId(String metadataId) { return dsl.select(DATASET.fields()).from(DATASET).join(METADATA).onKey(METADATA.DATASET_ID).where(METADATA.METADATA_ID.eq(metadataId)).fetchOneInto(Dataset.class); } @Override public Dataset findByIdentifier(String identifier) { return dsl.select().from(DATASET).where(DATASET.IDENTIFIER.eq(identifier)).fetchOneInto(Dataset.class); } @Override public Dataset findByIdentifierWithEmptyMetadata(String identifier) { List<Dataset> datas = dsl.select().from(DATASET).where(DATASET.IDENTIFIER.eq(identifier)).fetchInto(Dataset.class); for (Dataset dataset : datas) { Metadata m = dsl.select().from(METADATA).where(METADATA.DATASET_ID.eq(dataset.getId())).fetchOneInto(Metadata.class); if (m == null) { return dataset; } } return null; } @Override public Dataset findById(int id) { return dsl.select().from(DATASET).where(DATASET.ID.eq(id)).fetchOneInto(Dataset.class); } @Override @Transactional(propagation = Propagation.MANDATORY) public void remove(int id) { dsl.delete(DATASET).where(DATASET.ID.eq(id)).execute(); } @Override public List<Dataset> getCswLinkedDataset(final int cswId) { return dsl.select(DATASET.fields()).from(DATASET, METADATA, METADATA_X_CSW) .where(METADATA.ID.eq(METADATA_X_CSW.METADATA_ID)) .and(DATASET.ID.eq(METADATA.DATASET_ID)) .and(METADATA_X_CSW.CSW_ID.eq(cswId)).and(METADATA.DATASET_ID.isNotNull()).fetchInto(Dataset.class); } @Override @Transactional(propagation = Propagation.MANDATORY) public MetadataXCsw addDatasetToCSW(final int serviceID, final int datasetID) { final Metadata metadata = dsl.select().from(METADATA).where(METADATA.DATASET_ID.eq(datasetID)).fetchOneInto(Metadata.class); if (metadata != null) { final MetadataXCsw dxc = dsl.select().from(METADATA_X_CSW).where(METADATA_X_CSW.CSW_ID.eq(serviceID)).and(METADATA_X_CSW.METADATA_ID.eq(metadata.getId())).fetchOneInto(MetadataXCsw.class); if (dxc == null) { MetadataXCswRecord newRecord = dsl.newRecord(METADATA_X_CSW); newRecord.setCswId(serviceID); newRecord.setMetadataId(metadata.getId()); newRecord.store(); return newRecord.into(MetadataXCsw.class); } return dxc; } return null; } @Override @Transactional(propagation = Propagation.MANDATORY) public void removeDatasetFromCSW(int serviceID, int datasetID) { final Metadata metadata = dsl.select().from(METADATA).where(METADATA.DATASET_ID.eq(datasetID)).fetchOneInto(Metadata.class); if (metadata != null) { dsl.delete(METADATA_X_CSW).where(METADATA_X_CSW.CSW_ID.eq(serviceID)).and(METADATA_X_CSW.METADATA_ID.eq(metadata.getId())).execute(); } } @Override @Transactional(propagation = Propagation.MANDATORY) public void removeDatasetFromAllCSW(int datasetID) { final Metadata metadata = dsl.select().from(METADATA).where(METADATA.DATASET_ID.eq(datasetID)).fetchOneInto(Metadata.class); if (metadata != null) { dsl.delete(METADATA_X_CSW).where(METADATA_X_CSW.METADATA_ID.eq(metadata.getId())).execute(); } } @Override @Transactional(propagation = Propagation.MANDATORY) public void removeAllDatasetFromCSW(int serviceID) { dsl.delete(METADATA_X_CSW).where(METADATA_X_CSW.CSW_ID.eq(serviceID)).execute(); } @Override public boolean existsById(int datasetId) { return dsl.selectCount().from(DATASET) .where(DATASET.ID.eq(datasetId)) .fetchOne(0, Integer.class) > 0; } @Override public Page<DatasetItem> fetchPage(Pageable pageable, boolean excludeEmpty, String termFilter, Boolean hasVectorData, Boolean hasCoverageData, Boolean hasLayerData, Boolean hasSensorData) { // Query filters. Condition condition = DSL.trueCondition(); if (isNotBlank(termFilter)) { String likeExpr = '%' + termFilter + '%'; condition = condition.and(DATASET.IDENTIFIER.likeIgnoreCase(likeExpr).or(CSTL_USER.LOGIN.likeIgnoreCase(likeExpr)).or(DATA.NAME.likeIgnoreCase(likeExpr))); } if (excludeEmpty) { condition = condition.and(DSL.fieldByName(Integer.class, "w.count").greaterThan(0)); } if (hasVectorData != null) { Field<Integer> countVectorData = countDataOfType(DATASET.ID, "VECTOR"); condition = condition.and(hasVectorData ? countVectorData.greaterThan(0) : countVectorData.eq(0)); } if (hasCoverageData != null) { Field<Integer> countCoverageData = countDataOfType(DATASET.ID, "COVERAGE"); condition = condition.and(hasCoverageData ? countCoverageData.greaterThan(0) : countCoverageData.eq(0)); } if (hasLayerData != null) { Field<Integer> countLayerData = countLayerData(DATASET.ID); condition = condition.and(hasLayerData ? countLayerData.greaterThan(0) : countLayerData.eq(0)); } if (hasSensorData != null) { Field<Integer> countSensorData = countSensorData(DATASET.ID); condition = condition.and(hasSensorData ? countSensorData.greaterThan(0) : countSensorData.eq(0)); } // Content query. List<DatasetItem> content = dsl.with(FETCH_PAGE_WITH).selectDistinct(ITEM_FIELDS).from(DATASET) .join(FETCH_PAGE_WITH).on(DSL.fieldByName(Integer.class, "w.id").eq(DATASET.ID)) // dataset -> with .leftOuterJoin(CSTL_USER).on(CSTL_USER.ID.eq(DATASET.OWNER)) // dataset -> cstl_user .leftOuterJoin(DATA).on(DATA.DATASET_ID.eq(DATASET.ID)) // dataset -> data .where(condition) .orderBy(JooqUtils.sortFields(pageable, ITEM_FIELDS)) .limit(pageable.getPageSize()) .offset(pageable.getOffset()) .fetchInto(DatasetItem.class); // Total query. Long total = dsl.with(FETCH_PAGE_WITH).selectDistinct(DSL.countDistinct(DATASET.ID)).from(DATASET) .join(FETCH_PAGE_WITH).on(DSL.fieldByName(Integer.class, "w.id").eq(DATASET.ID)) // dataset -> with .leftOuterJoin(CSTL_USER).on(DATASET.OWNER.eq(CSTL_USER.ID)) // dataset -> cstl_user .leftOuterJoin(DATA).on(DATA.DATASET_ID.eq(DATASET.ID)) // dataset -> data .where(condition) .fetchOne(0, Long.class); return new PageImpl<>(pageable, content, total); } // ------------------------------------------------------------------------- // Private utility methods // ------------------------------------------------------------------------- private static Field<Integer> countDataOfType(Field<Integer> datasetId, String type) { return DSL.selectCount().from(DATA) .where(DATA.DATASET_ID.eq(datasetId)) .and(isIncludedAndNotHiddenData(DATA)) .and(DATA.TYPE.eq(type)) .asField(); } private static Field<Integer> countLayerData(Field<Integer> datasetId) { return DSL.selectCount().from(LAYER) .join(DATA).on(LAYER.DATA.eq(DATA.ID)) // layer -> data .where(DATA.DATASET_ID.eq(datasetId)) .and(isIncludedAndNotHiddenData(DATA)) .asField(); } private static Field<Integer> countSensorData(Field<Integer> datasetId) { return DSL.selectCount().from(SENSORED_DATA) .join(DATA).on(SENSORED_DATA.DATA.eq(DATA.ID)) // sensored_data -> data .where(DATA.DATASET_ID.eq(datasetId)) .and(isIncludedAndNotHiddenData(DATA)) .asField(); } private static Condition isIncludedAndNotHiddenData(Data dataTable) { return dataTable.INCLUDED.eq(true).and(dataTable.HIDDEN.eq(false)); } }