diff --git a/pom.xml b/pom.xml index afbbfc74..8fc84ec4 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,13 @@ 2.6 + + + org.apache.poi + poi-ooxml + 5.2.5 + + org.hamcrest diff --git a/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java b/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java new file mode 100644 index 00000000..fd861648 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java @@ -0,0 +1,311 @@ +package cz.cvut.kbss.study.model.export; + +import java.net.URI; +import java.util.Date; +import java.util.List; + +public class ExportRecord { + + private URI uri; + + + private Date created; + + private Date modified; + + private String label; + + private String phase; + + private String institution; + + private String aircraftType; + + private String fuselage; + + private URI ac_comp; + + private String ac_compName; + + + private List path; + + private String failDate; + + + private String flightHours; + + private Integer numberOfAirframeOverhauls; + + private String classificationOfOccurrence; + + private String failureAscertainmentCircumstances; + + private String repeatedFailure; + + private String failureCause; + + private String consequence; + + private String mission; + + private String repair; + + private String repairDuration; + + private Double averageNumberOfMenDuringRepairment; + + private String failureDescription; + + private String descriptionOfCorrectiveAction; + + private String yearOfProductionOfDefectiveEquipment; + + private Integer numberOfOverhaulsOfDefectiveEquipment; + + private String serialNoOf; + + private String notes; + + private String fhaEvent; + + public URI getUri() { + return uri; + } + + public void setUri(URI uri) { + this.uri = uri; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getPhase() { + return phase; + } + + public void setPhase(String phase) { + this.phase = phase; + } + + public String getInstitution() { + return institution; + } + + public void setInstitution(String institution) { + this.institution = institution; + } + + public String getAircraftType() { + return aircraftType; + } + + public void setAircraftType(String aircraftType) { + this.aircraftType = aircraftType; + } + + public String getFuselage() { + return fuselage; + } + + public void setFuselage(String fuselage) { + this.fuselage = fuselage; + } + + public URI getAc_comp() { + return ac_comp; + } + + public void setAc_comp(URI ac_comp) { + this.ac_comp = ac_comp; + } + + public String getAc_compName() { + return ac_compName; + } + + public void setAc_compName(String ac_compName) { + this.ac_compName = ac_compName; + } + + public List getPath() { + return path; + } + + public void setPath(List path) { + this.path = path; + } + + public String getFailDate() { + return failDate; + } + + public void setFailDate(String failDate) { + this.failDate = failDate; + } + + public String getFlightHours() { + return flightHours; + } + + public void setFlightHours(String flightHours) { + this.flightHours = flightHours; + } + + public Integer getNumberOfAirframeOverhauls() { + return numberOfAirframeOverhauls; + } + + public void setNumberOfAirframeOverhauls(Integer numberOfAirframeOverhauls) { + this.numberOfAirframeOverhauls = numberOfAirframeOverhauls; + } + + public String getClassificationOfOccurrence() { + return classificationOfOccurrence; + } + + public void setClassificationOfOccurrence(String classificationOfOccurrence) { + this.classificationOfOccurrence = classificationOfOccurrence; + } + + public String getFailureAscertainmentCircumstances() { + return failureAscertainmentCircumstances; + } + + public void setFailureAscertainmentCircumstances(String failureAscertainmentCircumstances) { + this.failureAscertainmentCircumstances = failureAscertainmentCircumstances; + } + + public String getRepeatedFailure() { + return repeatedFailure; + } + + public void setRepeatedFailure(String repeatedFailure) { + this.repeatedFailure = repeatedFailure; + } + + public String getFailureCause() { + return failureCause; + } + + public void setFailureCause(String failureCause) { + this.failureCause = failureCause; + } + + public String getConsequence() { + return consequence; + } + + public void setConsequence(String consequence) { + this.consequence = consequence; + } + + public String getMission() { + return mission; + } + + public void setMission(String mission) { + this.mission = mission; + } + + public String getRepair() { + return repair; + } + + public void setRepair(String repair) { + this.repair = repair; + } + + public String getRepairDuration() { + return repairDuration; + } + + public void setRepairDuration(String repairDuration) { + this.repairDuration = repairDuration; + } + + public Double getAverageNumberOfMenDuringRepairment() { + return averageNumberOfMenDuringRepairment; + } + + public void setAverageNumberOfMenDuringRepairment(Double averageNumberOfMenDuringRepairment) { + this.averageNumberOfMenDuringRepairment = averageNumberOfMenDuringRepairment; + } + + public String getFailureDescription() { + return failureDescription; + } + + public void setFailureDescription(String failureDescription) { + this.failureDescription = failureDescription; + } + + public String getDescriptionOfCorrectiveAction() { + return descriptionOfCorrectiveAction; + } + + public void setDescriptionOfCorrectiveAction(String descriptionOfCorrectiveAction) { + this.descriptionOfCorrectiveAction = descriptionOfCorrectiveAction; + } + + public String getYearOfProductionOfDefectiveEquipment() { + return yearOfProductionOfDefectiveEquipment; + } + + public void setYearOfProductionOfDefectiveEquipment(String yearOfProductionOfDefectiveEquipment) { + this.yearOfProductionOfDefectiveEquipment = yearOfProductionOfDefectiveEquipment; + } + + public Integer getNumberOfOverhaulsOfDefectiveEquipment() { + return numberOfOverhaulsOfDefectiveEquipment; + } + + public void setNumberOfOverhaulsOfDefectiveEquipment(Integer numberOfOverhaulsOfDefectiveEquipment) { + this.numberOfOverhaulsOfDefectiveEquipment = numberOfOverhaulsOfDefectiveEquipment; + } + + public String getSerialNoOf() { + return serialNoOf; + } + + public void setSerialNoOf(String serialNoOf) { + this.serialNoOf = serialNoOf; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public String getFhaEvent() { + return fhaEvent; + } + + public void setFhaEvent(String fhaEvent) { + this.fhaEvent = fhaEvent; + } +} diff --git a/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java b/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java new file mode 100644 index 00000000..f83bebf1 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java @@ -0,0 +1,23 @@ +package cz.cvut.kbss.study.model.export; + +import cz.cvut.kbss.jopa.model.annotations.*; +import cz.cvut.kbss.study.model.AbstractEntity; + +@SparqlResultSetMappings(value = +@SparqlResultSetMapping(name = "NamedItem", entities = { + @EntityResult(entityClass = NamedItem.class) +}) +) +@OWLClass(iri = "http://named-item") +public class NamedItem extends AbstractEntity { + @OWLDataProperty(iri = "http://name") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/cz/cvut/kbss/study/model/export/Path.java b/src/main/java/cz/cvut/kbss/study/model/export/Path.java new file mode 100644 index 00000000..3b0d51ca --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/export/Path.java @@ -0,0 +1,67 @@ +package cz.cvut.kbss.study.model.export; + + +import cz.cvut.kbss.jopa.model.annotations.*; +import cz.cvut.kbss.study.model.AbstractEntity; + +import java.net.URI; + +@SparqlResultSetMappings(value = +@SparqlResultSetMapping(name = "Path", entities = { + @EntityResult(entityClass = Path.class) +}) +) +@OWLClass(iri = "http://path") +public class Path extends AbstractEntity { + + @OWLDataProperty(iri = "http://l1") + protected URI l1; + @OWLDataProperty(iri = "http://l2") + protected URI l2; + @OWLDataProperty(iri = "http://l3") + protected URI l3; + @OWLDataProperty(iri = "http://l4") + protected URI l4; + @OWLDataProperty(iri = "http://l5") + protected URI l5; + + public URI getL1() { + return l1; + } + + public void setL1(URI l1) { + this.l1 = l1; + } + + public URI getL2() { + return l2; + } + + public void setL2(URI l2) { + this.l2 = l2; + } + + public URI getL3() { + return l3; + } + + public void setL3(URI l3) { + this.l3 = l3; + } + + public URI getL4() { + return l4; + } + + public void setL4(URI l4) { + this.l4 = l4; + } + + public URI getL5() { + return l5; + } + + public void setL5(URI l5) { + this.l5 = l5; + } +} diff --git a/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java b/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java new file mode 100644 index 00000000..843f5cde --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java @@ -0,0 +1,299 @@ +package cz.cvut.kbss.study.model.export; + +import cz.cvut.kbss.jopa.model.annotations.*; +import cz.cvut.kbss.study.model.Vocabulary; + +import java.net.URI; +import java.util.Date; + +@SparqlResultSetMappings(value = +@SparqlResultSetMapping(name = "RawRecord", entities = { + @EntityResult(entityClass = RawRecord.class) +}) +) +@OWLClass(iri = Vocabulary.s_c_patient_record) +public class RawRecord { + @Id + private URI uri; + + @OWLDataProperty(iri = "http://created") + private Date created; + @OWLDataProperty(iri = "http://modified") + private Date modified; + @OWLDataProperty(iri = "http://label") + private String label; + @OWLObjectProperty(iri = "http://phase") + private URI phase; + @OWLObjectProperty(iri = "http://institution") + private URI institution; + @OWLObjectProperty(iri = "http://aircraftType") + private URI aircraftType; + @OWLObjectProperty(iri = "http://fuselage") + private String fuselage; + @OWLObjectProperty(iri = "http://ac_comp") + private URI ac_comp; + @OWLDataProperty(iri = "http://failDate") + private String failDate; + + @OWLDataProperty(iri = "http://flightHours") + private String flightHours; + @OWLDataProperty(iri = "http://numberOfAirframeOverhauls") + private Integer numberOfAirframeOverhauls; + @OWLObjectProperty(iri = "http://classificationOfOccurrence") + private URI classificationOfOccurrence; + @OWLObjectProperty(iri = "http://failureAscertainmentCircumstances") + private URI failureAscertainmentCircumstances; + @OWLObjectProperty(iri = "http://repeatedFailure") + private URI repeatedFailure; + @OWLObjectProperty(iri = "http://failureCause") + private URI failureCause; + @OWLObjectProperty(iri = "http://consequence") + private URI consequence; + @OWLObjectProperty(iri = "http://mission") + private URI mission; + @OWLObjectProperty(iri = "http://repair") + private URI repair; + @OWLDataProperty(iri = "http://repairDuration") + private String repairDuration; + @OWLDataProperty(iri = "http://averageNumberOfMenDuringRepairment") + private Double averageNumberOfMenDuringRepairment; + @OWLDataProperty(iri = "http://failureDescription") + private String failureDescription; + @OWLDataProperty(iri = "http://descriptionOfCorrectiveAction") + private String descriptionOfCorrectiveAction; + @OWLDataProperty(iri = "http://yearOfProductionOfDefectiveEquipment") + private String yearOfProductionOfDefectiveEquipment; + @OWLDataProperty(iri = "http://numberOfOverhaulsOfDefectiveEquipment") + private Integer numberOfOverhaulsOfDefectiveEquipment; + @OWLDataProperty(iri = "http://serialNoOf") + private String serialNoOf; + @OWLDataProperty(iri = "http://notes") + private String notes; + @OWLObjectProperty(iri = "http://fhaEvent") + private URI fhaEvent; + + + public URI getUri() { + return uri; + } + + public void setUri(URI uri) { + this.uri = uri; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public URI getPhase() { + return phase; + } + + public void setPhase(URI phase) { + this.phase = phase; + } + + public URI getInstitution() { + return institution; + } + + public void setInstitution(URI institution) { + this.institution = institution; + } + + public URI getAircraftType() { + return aircraftType; + } + + public void setAircraftType(URI aircraftType) { + this.aircraftType = aircraftType; + } + + public String getFuselage() { + return fuselage; + } + + public void setFuselage(String fuselage) { + this.fuselage = fuselage; + } + + public URI getAc_comp() { + return ac_comp; + } + + public void setAc_comp(URI ac_comp) { + this.ac_comp = ac_comp; + } + + public String getFailDate() { + return failDate; + } + + public void setFailDate(String failDate) { + this.failDate = failDate; + } + + public String getFlightHours() { + return flightHours; + } + + public void setFlightHours(String flightHours) { + this.flightHours = flightHours; + } + + public Integer getNumberOfAirframeOverhauls() { + return numberOfAirframeOverhauls; + } + + public void setNumberOfAirframeOverhauls(Integer numberOfAirframeOverhauls) { + this.numberOfAirframeOverhauls = numberOfAirframeOverhauls; + } + + public URI getClassificationOfOccurrence() { + return classificationOfOccurrence; + } + + public void setClassificationOfOccurrence(URI classificationOfOccurrence) { + this.classificationOfOccurrence = classificationOfOccurrence; + } + + public URI getFailureAscertainmentCircumstances() { + return failureAscertainmentCircumstances; + } + + public void setFailureAscertainmentCircumstances(URI failureAscertainmentCircumstances) { + this.failureAscertainmentCircumstances = failureAscertainmentCircumstances; + } + + public URI getRepeatedFailure() { + return repeatedFailure; + } + + public void setRepeatedFailure(URI repeatedFailure) { + this.repeatedFailure = repeatedFailure; + } + + public URI getFailureCause() { + return failureCause; + } + + public void setFailureCause(URI failureCause) { + this.failureCause = failureCause; + } + + public URI getConsequence() { + return consequence; + } + + public void setConsequence(URI consequence) { + this.consequence = consequence; + } + + public URI getMission() { + return mission; + } + + public void setMission(URI mission) { + this.mission = mission; + } + + public URI getRepair() { + return repair; + } + + public void setRepair(URI repair) { + this.repair = repair; + } + + public String getRepairDuration() { + return repairDuration; + } + + public void setRepairDuration(String repairDuration) { + this.repairDuration = repairDuration; + } + + public Double getAverageNumberOfMenDuringRepairment() { + return averageNumberOfMenDuringRepairment; + } + + public void setAverageNumberOfMenDuringRepairment(Double averageNumberOfMenDuringRepairment) { + this.averageNumberOfMenDuringRepairment = averageNumberOfMenDuringRepairment; + } + + public String getFailureDescription() { + return failureDescription; + } + + public void setFailureDescription(String failureDescription) { + this.failureDescription = failureDescription; + } + + public String getDescriptionOfCorrectiveAction() { + return descriptionOfCorrectiveAction; + } + + public void setDescriptionOfCorrectiveAction(String descriptionOfCorrectiveAction) { + this.descriptionOfCorrectiveAction = descriptionOfCorrectiveAction; + } + + public String getYearOfProductionOfDefectiveEquipment() { + return yearOfProductionOfDefectiveEquipment; + } + + public void setYearOfProductionOfDefectiveEquipment(String yearOfProductionOfDefectiveEquipment) { + this.yearOfProductionOfDefectiveEquipment = yearOfProductionOfDefectiveEquipment; + } + + public Integer getNumberOfOverhaulsOfDefectiveEquipment() { + return numberOfOverhaulsOfDefectiveEquipment; + } + + public void setNumberOfOverhaulsOfDefectiveEquipment(Integer numberOfOverhaulsOfDefectiveEquipment) { + this.numberOfOverhaulsOfDefectiveEquipment = numberOfOverhaulsOfDefectiveEquipment; + } + + public String getSerialNoOf() { + return serialNoOf; + } + + public void setSerialNoOf(String serialNoOf) { + this.serialNoOf = serialNoOf; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public URI getFhaEvent() { + return fhaEvent; + } + + public void setFhaEvent(URI fhaEvent) { + this.fhaEvent = fhaEvent; + } +} diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java new file mode 100644 index 00000000..416df4c1 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java @@ -0,0 +1,185 @@ +package cz.cvut.kbss.study.persistence.dao; + +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.study.model.Vocabulary; +import cz.cvut.kbss.study.model.export.NamedItem; +import cz.cvut.kbss.study.model.export.Path; +import org.springframework.stereotype.Repository; + +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Repository +public class CodeListValuesDao { + + private final EntityManager em; + + public CodeListValuesDao(EntityManager em) { + this.em = em; + } + + + + public List findClassificationOfOccurrence() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/classification-of-occurrence")); + } + + + public List findConsequence() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/consequence")); + } + + + public List findFailureAscertainmentCircumstances() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/failure-ascertainment-circumstances")); + } + + + public List findFailureCause() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/failure-cause")); + } + + + public List findFhaEvent() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/fha-event")); + } + + + public List findMission() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/mission")); + } + + + public List findRepair() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/repair")); + } + + + public List findRepeatedFailure() { + return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/repeated-failure")); + } + + public List findInstitutions(){ + return em.createNativeQuery(""" + PREFIX rm: + PREFIX rdfs: + + SELECT ?uri (str(?_name) as ?name) { + ?uri a ?type. + ?uri rdfs:label ?_name + } + """, NamedItem.class.getSimpleName()) + .setParameter("type", URI.create(Vocabulary.s_c_institution)) + .getResultList(); + } + + public List findItems(URI type){ + return em.createNativeQuery(""" + PREFIX rm: + PREFIX rdfs: + + SELECT ?uri (str(?_name) as ?name) { + SERVICE { + ?uri a ?type. + ?uri rdfs:label ?_name + } + } + """, NamedItem.class.getSimpleName()) + .setParameter("type", type) + .getResultList(); + } + + public List findItems(Collection items){ + String queryString = """ + PREFIX rm: + PREFIX rdfs: + + SELECT ?uri (str(?_name) as ?name) { + SERVICE { + ?uri rdfs:label ?_name + } + }VALUES ?uri { + ###items### + } + """; + if(items != null) { + queryString = queryString.replaceFirst( + "###items###", + items.stream().map(u -> "<%s>".formatted(u)).collect(Collectors.joining("\n")) + ); + } + return em.createNativeQuery(queryString, NamedItem.class.getSimpleName()) + .getResultList(); + } + + + + public List findAircraft(){ + return em.createNativeQuery(""" + PREFIX rdfs: + PREFIX form: + + SELECT ?uri ?name { + SERVICE { + ?uri a form:form-template. + ?uri rdfs:label ?name. + } + } + """, NamedItem.class.getSimpleName()).getResultList(); + } + + public List findAircraftParts(){ + return em.createNativeQuery(""" + PREFIX rdfs: + PREFIX form: + + SELECT ?uri ?name { + SERVICE { + ?uri a form:form-template. + ?uri rdfs:label ?name. + } + } + """, NamedItem.class.getSimpleName()).getResultList(); + } + + public List getBroaderPath(Collection elements){ + String queryString = """ + PREFIX skos: + SELECT ?l1 ?l2 ?l3 ?l4 ?l5 (?p as ?uri) { + SERVICE { + OPTIONAL{ + ?p skos:broader+ ?l1. + FILTER NOT EXISTS{ + ?l1 skos:broader ?l0 . + } + OPTIONAL{ + ?l2 skos:broader ?l1 . + ?p skos:broader+ ?l2. + OPTIONAL{ + ?l3 skos:broader ?l2 . + ?p skos:broader+ ?l3. + OPTIONAL{ + ?l4 skos:broader ?l3 . + ?p skos:broader+ ?l4. + OPTIONAL{ + ?l5 skos:broader ?l4 . + ?p skos:broader+ ?l5. + } + } + } + } + } + } + }VALUES ?p { + %s + } + """; + queryString = queryString.formatted(elements.stream().map(u -> "<%s>".formatted(u.toString())) + .collect(Collectors.joining("\n"))); + return em.createNativeQuery(queryString, Path.class.getSimpleName()) + .getResultList(); + } + +} diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java index 6fd233ef..a64d6e19 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java @@ -5,6 +5,7 @@ import cz.cvut.kbss.jopa.model.descriptors.Descriptor; import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor; import cz.cvut.kbss.jopa.model.metamodel.EntityType; +import cz.cvut.kbss.jopa.model.query.Query; import cz.cvut.kbss.jopa.model.query.TypedQuery; import cz.cvut.kbss.ontodriver.model.LangString; import cz.cvut.kbss.study.dto.PatientRecordDto; @@ -14,11 +15,13 @@ import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; +import cz.cvut.kbss.study.model.export.RawRecord; import cz.cvut.kbss.study.persistence.dao.util.QuestionSaver; import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams; import cz.cvut.kbss.study.persistence.dao.util.RecordSort; import cz.cvut.kbss.study.util.Constants; import cz.cvut.kbss.study.util.IdentificationUtils; +import cz.cvut.kbss.study.util.Utils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -38,6 +41,9 @@ @Repository public class PatientRecordDao extends OwlKeySupportingDao { + public static final String FIND_ALL_RAW_PATIENT_RECORDS = "find-raw-records.sparql"; + public static final String RECORDS_CLAUSE_TEMPLATE_VAR = "###RECORD_CLAUSE###"; + public PatientRecordDao(EntityManager em) { super(PatientRecord.class, em); } @@ -237,7 +243,40 @@ private Page findRecords(RecordFilterParams filters, Pageable pageSpec, C return new PageImpl<>(records, pageSpec, totalCount); } - private void setQueryParameters(TypedQuery query, Map queryParams) { + public Page findAllRecordsRaw(RecordFilterParams filters, Pageable pageSpec){ + final Map queryParams = new HashMap<>(); + final String whereClause = constructWhereClause(filters, queryParams); + + final String queryStringNoPaging = Utils.loadQuery(FIND_ALL_RAW_PATIENT_RECORDS) + .replaceFirst(RECORDS_CLAUSE_TEMPLATE_VAR, whereClause); + final String queryString = queryStringNoPaging + (pageSpec.isPaged() + ? resolveOrderBy(pageSpec.getSortOr(RecordSort.defaultSort())) + : "" + ); + + Query query = em.createNativeQuery(queryString, RawRecord.class.getSimpleName()); + queryParams.forEach(query::setParameter); + + if (pageSpec.isPaged()) { + query.setFirstResult((int) pageSpec.getOffset()); + query.setMaxResults(pageSpec.getPageSize()); + } + setQueryParameters(query, queryParams); + List result = query.getResultList(); + Integer totalCount = result.size(); + if(pageSpec.isPaged()){ + TypedQuery countQuery = em.createNativeQuery( + "SELECT (COUNT(?r) as ?cnt) WHERE {%s}".formatted(whereClause), + Integer.class); + + setQueryParameters(countQuery, queryParams); + totalCount = countQuery.getSingleResult(); + } + + return new PageImpl<>(result, pageSpec, totalCount); + } + + private void setQueryParameters(Query query, Map queryParams) { query.setParameter("type", typeUri) .setParameter("hasPhase", URI.create(Vocabulary.s_p_has_phase)) .setParameter("hasFormTemplate", URI.create(Vocabulary.s_p_has_form_template)) diff --git a/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java b/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java index 5bc4d9ff..7a5ad4a7 100644 --- a/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java +++ b/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java @@ -5,34 +5,32 @@ import cz.cvut.kbss.study.exception.NotFoundException; import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.RecordPhase; +import cz.cvut.kbss.study.model.export.RawRecord; +import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams; import cz.cvut.kbss.study.rest.event.PaginatedResultRetrievedEvent; import cz.cvut.kbss.study.rest.exception.BadRequestException; import cz.cvut.kbss.study.rest.util.RecordFilterMapper; import cz.cvut.kbss.study.rest.util.RestUtils; import cz.cvut.kbss.study.security.SecurityConstants; +import cz.cvut.kbss.study.service.ExcelRecordConverter; import cz.cvut.kbss.study.service.PatientRecordService; +import cz.cvut.kbss.study.util.Constants; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.io.InputStreamResource; import org.springframework.data.domain.Page; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.util.UriComponentsBuilder; +import java.io.InputStream; +import java.util.Comparator; import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; @RestController @PreAuthorize("hasRole('" + SecurityConstants.ROLE_USER + "')") @@ -42,10 +40,12 @@ public class PatientRecordController extends BaseController { private final PatientRecordService recordService; private final ApplicationEventPublisher eventPublisher; + private final ExcelRecordConverter excelRecordConverter; - public PatientRecordController(PatientRecordService recordService, ApplicationEventPublisher eventPublisher) { + public PatientRecordController(PatientRecordService recordService, ApplicationEventPublisher eventPublisher, ExcelRecordConverter excelRecordConverter) { this.recordService = recordService; this.eventPublisher = eventPublisher; + this.excelRecordConverter = excelRecordConverter; } @PreAuthorize("hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isMemberOfInstitution(#institutionKey)") @@ -62,15 +62,56 @@ public List getRecords( @PreAuthorize( "hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isMemberOfInstitution(#institutionKey)") - @GetMapping(value = "/export", produces = MediaType.APPLICATION_JSON_VALUE) - public List exportRecords( + @GetMapping(value = "/export", produces = {MediaType.APPLICATION_JSON_VALUE, Constants.MEDIA_TYPE_EXCEL}) + public ResponseEntity exportRecords( @RequestParam(name = "institution", required = false) String institutionKey, - @RequestParam MultiValueMap params, - UriComponentsBuilder uriBuilder, HttpServletResponse response) { + @RequestParam(required = false) MultiValueMap params, + UriComponentsBuilder uriBuilder, HttpServletRequest request, HttpServletResponse response) { + MediaType exportType = Stream.of( + Optional.ofNullable(params).map(p -> p.getFirst(Constants.EXPORT_TYPE_PARAM)), + Optional.ofNullable(request.getHeader(HttpHeaders.ACCEPT)) + ).filter(Optional::isPresent) + .findFirst() + .orElse(Optional.empty()) + .flatMap(s -> MediaType.parseMediaTypes(s).stream() + .max(Comparator.comparing(MediaType::getQualityValue)) + ).orElse(MediaType.APPLICATION_JSON) + .removeQualityValue(); + + return switch (exportType.toString()){ + case Constants.MEDIA_TYPE_EXCEL -> exportRecordsExcel(params, uriBuilder, response); + case MediaType.APPLICATION_JSON_VALUE -> exportRecordsAsJson(params, uriBuilder, response); + default -> throw new IllegalArgumentException("Unsupported export type: " + exportType); + }; + } + + protected ResponseEntity> exportRecordsAsJson( + MultiValueMap params, + UriComponentsBuilder uriBuilder, HttpServletResponse response){ final Page result = recordService.findAllFull(RecordFilterMapper.constructRecordFilter(params), - RestUtils.resolvePaging(params)); + RestUtils.resolvePaging(params)); eventPublisher.publishEvent(new PaginatedResultRetrievedEvent(this, uriBuilder, response, result)); - return result.getContent(); + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(result.getContent()); + } + + public ResponseEntity exportRecordsExcel(MultiValueMap params, + UriComponentsBuilder uriBuilder, HttpServletResponse response){ + RecordFilterParams filterParams = new RecordFilterParams(); + filterParams.setMinModifiedDate(null); + filterParams.setMaxModifiedDate(null); + RecordFilterMapper.constructRecordFilter(filterParams, params); + + Page result = recordService.exportRecords(filterParams, RestUtils.resolvePaging(params)); + + InputStream stream = excelRecordConverter.convert(result.getContent()); + eventPublisher.publishEvent(new PaginatedResultRetrievedEvent(this, uriBuilder, response, result)); + ContentDisposition contentDisposition = ContentDisposition.attachment().filename("export.xlsx").build(); + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(Constants.MEDIA_TYPE_EXCEL)) + .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()) + .body(new InputStreamResource(stream)); } @PreAuthorize("hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isRecordInUsersInstitution(#key)") diff --git a/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java b/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java index a3473cd0..4b13df8a 100644 --- a/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java +++ b/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java @@ -45,16 +45,18 @@ public class RecordFilterMapper { public static RecordFilterParams constructRecordFilter(String param, String value) { return constructRecordFilter(new LinkedMultiValueMap<>(Map.of(param, List.of(value)))); } - + public static RecordFilterParams constructRecordFilter(MultiValueMap params) { + final RecordFilterParams result = new RecordFilterParams(); + return constructRecordFilter(result, new LinkedMultiValueMap<>(params)); + } /** * Maps the specified parameters to a new {@link RecordFilterParams} instance. * * @param params Request parameters to map * @return New {@code RecordFilterParams} instance */ - public static RecordFilterParams constructRecordFilter(MultiValueMap params) { + public static RecordFilterParams constructRecordFilter(final RecordFilterParams result, MultiValueMap params) { Objects.requireNonNull(params); - final RecordFilterParams result = new RecordFilterParams(); getSingleValue(MIN_DATE_PARAM, params).ifPresent(s -> { try { result.setMinModifiedDate(LocalDate.parse(s)); diff --git a/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java b/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java new file mode 100644 index 00000000..dfea8f4c --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java @@ -0,0 +1,161 @@ +package cz.cvut.kbss.study.service; + +import cz.cvut.kbss.study.model.export.ExportRecord; +import cz.cvut.kbss.study.model.export.Path; +import cz.cvut.kbss.study.model.export.RawRecord; +import cz.cvut.kbss.study.persistence.dao.CodeListValuesDao; +import cz.cvut.kbss.study.util.Utils; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +public class ExcelRecordConverter { + + private final CodeListValuesDao codeListValuesDao; + + public ExcelRecordConverter(CodeListValuesDao codeListValuesDao) { + this.codeListValuesDao = codeListValuesDao; + } + + public InputStream convert(List rawRecords){ + try { + XSSFWorkbook workbook = new XSSFWorkbook(Utils.class.getClassLoader().getResourceAsStream("templates/record-export-template.xlsx")); + List exportRecords = findExportRecordsData(rawRecords); + addDataToExcel(workbook, exportRecords); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + workbook.write(output); + return new ByteArrayInputStream(output.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private List findExportRecordsData(List rawRecords){ + Map translatorMap = new HashMap<>(); + List paths = codeListValuesDao.getBroaderPath(rawRecords.stream().map(r -> r.getAc_comp()).collect(Collectors.toSet())); + Set uris = rawRecords.stream().flatMap(r -> Stream.of( + r.getClassificationOfOccurrence(), r.getConsequence(), r.getFailureAscertainmentCircumstances(), + r.getFailureCause(), r.getAc_comp(), r.getFhaEvent(), r.getMission(), r.getRepair(), + r.getRepeatedFailure())) + .distinct() + .filter(u -> u != null) + .collect(Collectors.toSet()); + + uris.addAll(paths.stream() + .flatMap(p -> Stream.of(p.getL1(), p.getL2(), p.getL3(), p.getL4(), p.getL5())) + .filter(u -> u != null).collect(Collectors.toSet()) + ); + + + codeListValuesDao.findItems(uris).forEach(i -> translatorMap.put(i.getUri(), i.getName())); + codeListValuesDao.findAircraft().forEach(i -> translatorMap.put(i.getUri(), i.getName())); + codeListValuesDao.findInstitutions().forEach(i -> translatorMap.put(i.getUri(), i.getName())); + + Map> pathMap = new HashMap<>(); + paths.forEach(p -> pathMap.put(p.getUri(), Arrays.asList( + translatorMap.get(p.getL1()), + translatorMap.get(p.getL2()), + translatorMap.get(p.getL3()), + translatorMap.get(p.getL4()), + translatorMap.get(p.getL5()) + ))); + + List exportRecords = new ArrayList<>(); + + for(RawRecord r : rawRecords){ + ExportRecord er = new ExportRecord(); + exportRecords.add(er); + er.setPath(pathMap.get(r.getAc_comp())); + er.setInstitution(translatorMap.get(r.getInstitution())); + er.setAircraftType(translatorMap.get(r.getAircraftType())); + er.setAc_compName(translatorMap.get(r.getAc_comp())); + er.setClassificationOfOccurrence(translatorMap.get(r.getClassificationOfOccurrence())); + er.setConsequence(translatorMap.get(r.getConsequence())); + er.setFailureCause(translatorMap.get(r.getFailureCause())); + er.setFhaEvent(translatorMap.get(r.getFhaEvent())); + er.setMission(translatorMap.get(r.getMission())); + er.setRepair(translatorMap.get(r.getRepair())); + er.setRepeatedFailure(translatorMap.get(r.getRepeatedFailure())); + + er.setFuselage(r.getFuselage()); + er.setUri(r.getUri()); + er.setCreated(r.getCreated()); + er.setModified(r.getModified()); + er.setLabel(r.getLabel()); + er.setFailDate(r.getFailDate()); + er.setFlightHours(r.getFlightHours()); + er.setNumberOfAirframeOverhauls(r.getNumberOfAirframeOverhauls()); + er.setRepairDuration(r.getRepairDuration()); + er.setAverageNumberOfMenDuringRepairment(r.getAverageNumberOfMenDuringRepairment()); + er.setFailureDescription(r.getFailureDescription()); + er.setDescriptionOfCorrectiveAction(r.getDescriptionOfCorrectiveAction()); + er.setNumberOfOverhaulsOfDefectiveEquipment(r.getNumberOfOverhaulsOfDefectiveEquipment()); + er.setSerialNoOf(r.getSerialNoOf()); + er.setNotes(r.getNotes()); + } + + return exportRecords; + } + + + private void addDataToExcel(XSSFWorkbook workbook, List data) throws IOException { + XSSFSheet s = workbook.getSheetAt(1); + + int rowIndex = 1; + for(ExportRecord rec : data) { + XSSFRow r = s.createRow(rowIndex++); + r.createCell(0).setCellValue(rowIndex); +// r.createCell(1).setCellValue(rowIndex); + r.createCell(2).setCellValue(rec.getCreated()); +// r.createCell(3).setCellValue(rec.ed); +// r.createCell(4).setCellValue(rec.); + r.createCell(5).setCellValue(rec.getModified()); + r.createCell(6).setCellValue(rec.getLabel()); + r.createCell(7).setCellValue(rec.getInstitution()); + r.createCell(8).setCellValue(rec.getAircraftType()); + r.createCell(10).setCellValue(rec.getFuselage()); + r.createCell(11).setCellValue(rec.getFailDate()); + r.createCell(12).setCellValue(rec.getFlightHours()); + r.createCell(13).setCellValue(rec.getNumberOfAirframeOverhauls()); + r.createCell(14).setCellValue(rec.getClassificationOfOccurrence()); + r.createCell(15).setCellValue(rec.getFailureAscertainmentCircumstances()); + r.createCell(16).setCellValue(rec.getRepeatedFailure()); + r.createCell(17).setCellValue(rec.getFailureCause()); + r.createCell(18).setCellValue(rec.getConsequence()); + r.createCell(19).setCellValue(rec.getMission()); + r.createCell(20).setCellValue(rec.getRepair()); + r.createCell(21).setCellValue(rec.getRepairDuration()); + r.createCell(22).setCellValue(rec.getAverageNumberOfMenDuringRepairment()); + r.createCell(23).setCellValue(rec.getFailureDescription()); + r.createCell(24).setCellValue(rec.getDescriptionOfCorrectiveAction()); + r.createCell(25).setCellValue(rec.getAc_compName()); + if (rec.getPath() != null){ + r.createCell(26).setCellValue(rec.getPath().get(0)); + r.createCell(27).setCellValue(rec.getPath().get(1)); + r.createCell(28).setCellValue(rec.getPath().get(2)); + r.createCell(29).setCellValue(rec.getPath().get(3)); + r.createCell(30).setCellValue(rec.getPath().get(4)); + } +// r.createCell(31).setCellValue(rec.get()); +// r.createCell(32).setCellValue(rec.get()); + r.createCell(31).setCellValue(rec.getYearOfProductionOfDefectiveEquipment()); + + Optional.ofNullable(rec.getNumberOfOverhaulsOfDefectiveEquipment()).ifPresent(v -> r.createCell(29).setCellValue(v)); + r.createCell(33).setCellValue(rec.getSerialNoOf()); + r.createCell(34).setCellValue(rec.getNotes()); + r.createCell(35).setCellValue(rec.getFhaEvent()); + } + } + +} diff --git a/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java b/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java index 91322af1..83eb8965 100644 --- a/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java +++ b/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java @@ -4,6 +4,7 @@ import cz.cvut.kbss.study.dto.RecordImportResult; import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.RecordPhase; +import cz.cvut.kbss.study.model.export.RawRecord; import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -77,4 +78,12 @@ public interface PatientRecordService extends BaseService { * repository */ RecordImportResult importRecords(List records, RecordPhase targetPhase); + + /** + * + * @param filters Record filtering criteria + * @param pageSpec Specification of page and sorting to retrieve + * @return List of matching records + */ + Page exportRecords(RecordFilterParams filters, Pageable pageSpec); } diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java index 8aaf2c9c..d524a105 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java @@ -6,6 +6,7 @@ import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.RecordPhase; import cz.cvut.kbss.study.model.User; +import cz.cvut.kbss.study.model.export.RawRecord; import cz.cvut.kbss.study.persistence.dao.OwlKeySupportingDao; import cz.cvut.kbss.study.persistence.dao.PatientRecordDao; import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams; @@ -36,12 +37,14 @@ public class RepositoryPatientRecordService extends KeySupportingRepositoryServi private final SecurityUtils securityUtils; private final UserService userService; + private final PatientRecordDao patientRecordDao; public RepositoryPatientRecordService(PatientRecordDao recordDao, SecurityUtils securityUtils, - UserService userService) { + UserService userService, PatientRecordDao patientRecordDao) { this.recordDao = recordDao; this.securityUtils = securityUtils; this.userService = userService; + this.patientRecordDao = patientRecordDao; } @Override @@ -125,4 +128,9 @@ public RecordImportResult importRecords(List records, RecordPhase LOG.debug("Importing records to target phase '{}'.", targetPhase); return importRecordsImpl(records, Optional.ofNullable(targetPhase)); } + + @Override + public Page exportRecords(RecordFilterParams filters, Pageable pageSpec){ + return patientRecordDao.findAllRecordsRaw(filters, pageSpec); + } } diff --git a/src/main/java/cz/cvut/kbss/study/util/Constants.java b/src/main/java/cz/cvut/kbss/study/util/Constants.java index 45369d2f..58289c76 100644 --- a/src/main/java/cz/cvut/kbss/study/util/Constants.java +++ b/src/main/java/cz/cvut/kbss/study/util/Constants.java @@ -53,9 +53,19 @@ private Constants() { */ public static final String SORT_PARAM = "sort"; + /** + * Name of the request parameter specifying record the export type. + */ + public static final String EXPORT_TYPE_PARAM = "exportType"; + /** * Represents the X-Total-Count HTTP header used to convey the total number of items in paged or otherwise * restricted response. */ public static final String X_TOTAL_COUNT_HEADER = "X-Total-Count"; + + /** + * Excel MIME type + */ + public static final String MEDIA_TYPE_EXCEL = "application/vnd.ms-excel"; } diff --git a/src/main/resources/query/find-raw-records.sparql b/src/main/resources/query/find-raw-records.sparql new file mode 100644 index 00000000..902cf11a --- /dev/null +++ b/src/main/resources/query/find-raw-records.sparql @@ -0,0 +1,203 @@ +PREFIX av: +PREFIX dc: +PREFIX doc: +PREFIX form: +PREFIX form-lt: +PREFIX owl: +PREFIX rdfs: +PREFIX skos: +PREFIX vs-f: +PREFIX vs-m: +PREFIX xsd: +PREFIX avadom: + +PREFIX avamod: +PREFIX rm: +PREFIX dcterms: +PREFIX spif: + +SELECT ?r (?r as ?uri) +?created ?label ?lastModified ?phase ?institution ?institutionKey ?formTemplate (IRI(str(?formTemplate)) as ?aircraftType) (str(?fus) as ?fuselage) ?ac_comp (str(?failDateStr) as ?failDate) +?flightHours ?numberOfAirframeOverhauls ?classificationOfOccurrence ?failureAscertainmentCircumstances (?repeatedFailureCode as ?repeatedFailure) ?failureCause ?consequence ?mission ?repair (str(?repairDurationStr) as ?repairDuration) ?averageNumberOfMenDuringRepairment ?failureDescription ?descriptionOfCorrectiveAction ?yearOfProductionOfDefectiveEquipment ?numberOfOverhaulsOfDefectiveEquipment ?serialNoOf ?notes ?fhaEvent +{ + ###RECORD_CLAUSE### + + ?r rm:has-question ?f. + ?f doc:has_related_question ?s1. + ?f doc:has_related_question ?s2. + FILTER(?s2 != ?s1) + ?s2 doc:has_related_question ?fhaEventQ. + ?fhaEventQ form:has-question-origin avamod:fha-event. + + ?s1 doc:has_related_question ?FUSq. + ?FUSq form:has-question-origin avamod:fuselage-no. + + ?s1 doc:has_related_question ?Cq. + ?Cq form:has-question-origin ?componentQuestionOrigin. + FILTER(contains(str(?componentQuestionOrigin), "http://vfn.cz/ontologies/ava-study/model/system-equipment-block-part-")) + + ?s1 doc:has_related_question ?failDateq. + ?failDateq form:has-question-origin avamod:date-of-failure-ascertainment. + + ?s1 doc:has_related_question ?FHq. + ?FHq form:has-question-origin avamod:flight-hours-of-airframe-since-the-service-beginning. + + ?s1 doc:has_related_question ?classificationOfOccurrenceQ. + ?classificationOfOccurrenceQ form:has-question-origin avamod:classification-of-occurrence. + + ?s1 doc:has_related_question ?failureAscertainmentCircumstancesQ. + ?failureAscertainmentCircumstancesQ form:has-question-origin avamod:failure-ascertainment-circumstances. + + ?s1 doc:has_related_question ?repeatedFailureQ. + ?repeatedFailureQ form:has-question-origin avamod:repeated-failure. + + ?s1 doc:has_related_question ?failureCauseQ. + ?failureCauseQ form:has-question-origin avamod:failure-cause . + + ?s1 doc:has_related_question ?consequenceQ. + ?consequenceQ form:has-question-origin avamod:consequence. + + ?s1 doc:has_related_question ?missionQ. + ?missionQ form:has-question-origin avamod:mission. + + ?s1 doc:has_related_question ?repairQ. + ?repairQ form:has-question-origin avamod:repair. + + ?s1 doc:has_related_question ?repairDurationQ. + ?repairDurationQ form:has-question-origin avamod:repair-duration. + + ?s1 doc:has_related_question ?averageNumberOfMenDuringRepairmentQ. + ?averageNumberOfMenDuringRepairmentQ form:has-question-origin avamod:average-number-of-men-during-repairment. + + ?s1 doc:has_related_question ?failureDescriptionQ. + ?failureDescriptionQ form:has-question-origin avamod:failure-description. + + ?s1 doc:has_related_question ?descriptionOfCorrectiveActionQ. + ?descriptionOfCorrectiveActionQ form:has-question-origin avamod:description-of-corrective-action. + + ?s1 doc:has_related_question ?numberOfAirframeOverhaulsQ. + ?numberOfAirframeOverhaulsQ form:has-question-origin avamod:number-of-airframe-overhauls. + + ?s1 doc:has_related_question ?yearOfProductionOfDefectiveEquipmentQ. + ?yearOfProductionOfDefectiveEquipmentQ form:has-question-origin avamod:year-of-production-of-defective-equipment. + + ?s1 doc:has_related_question ?numberOfOverhaulsOfDefectiveEquipmentQ. + ?numberOfOverhaulsOfDefectiveEquipmentQ form:has-question-origin avamod:number-of-overhauls-of-defective-equipment. + +# ?s1 doc:has_related_question ?serialNoOfQ. +# ?serialNoOfQ form:has-question-origin avamod:serial-no-of. + + ?s1 doc:has_related_question ?notesQ. + ?notesQ form:has-question-origin avamod:notes. + OPTIONAL { + # avamod:fuselage-no + ?FUSq doc:has_answer ?FUSa. + ?FUSa doc:has_data_value ?fus. + + #avamod:system-equipment-block-part-l-39ng.a1 + # ?comp - label of general component/system + # ?comp_iri - iri of component type specific to the aircraft + ?Cq doc:has_answer ?Ca. + ?Ca doc:has_object_value ?ac_comp. + + #avamod:date-of-failure-ascertainment + # ?failDate - creation date filter + ?failDateq doc:has_answer ?failDatea. + ?failDatea doc:has_data_value ?failDateStr. + # BIND(spif:parseDate(?failDateStr, "DD-MM-yyyy") as ?failDate) + # FILTER((!BOUND(?createdBefore) || ?createdBefore < ?failDate ) && (!BOUND(?createdAfter) || ?createdAfter >= ?failDate )) + + #avamod:flight-hours-of-airframe-since-the-service-beginning + + ?FHq doc:has_answer ?FHa. + ?FHa doc:has_data_value ?flightHours. + + #avamod:classification-of-occurrence + ?classificationOfOccurrenceQ doc:has_answer ?classificationOfOccurrenceA. + ?classificationOfOccurrenceA doc:has_object_value ?classificationOfOccurrence. + + #avamod:failure-ascertainment-circumstances + + ?failureAscertainmentCircumstancesQ doc:has_answer ?failureAscertainmentCircumstancesA. + ?failureAscertainmentCircumstancesA doc:has_object_value ?failureAscertainmentCircumstances. + + # during flight + # BIND(IF(BOUND(?failureAscertainmentCircumstances) && ?failureAscertainmentCircumstances = avadom:during-flight, 1, 0) as ?duringFlight) + + #avamod:repeated-failure + ?repeatedFailureQ doc:has_answer ?repeatedFailureA. + ?repeatedFailureA doc:has_object_value ?repeatedFailureCode. + + OPTIONAL{ + #avamod:failure-cause + ?failureCauseQ doc:has_answer ?failureCauseA. + ?failureCauseA doc:has_object_value ?failureCause. + } + #avamod:consequence + + ?consequenceQ doc:has_answer ?consequenceA. + ?consequenceA doc:has_object_value ?consequence. + + #avamod:mission + ?missionQ doc:has_answer ?missionA. + ?missionA doc:has_object_value ?mission. + + #avamod:repair + ?repairQ doc:has_answer ?repairA. + ?repairA doc:has_object_value ?repair. + + #avamod:repair-duration + ?repairDurationQ doc:has_answer ?repairDurationA. + ?repairDurationA doc:has_data_value ?repairDurationStr. + + #avamod:average-number-of-men-during-repairment + ?averageNumberOfMenDuringRepairmentQ doc:has_answer ?averageNumberOfMenDuringRepairmentA. + ?averageNumberOfMenDuringRepairmentA doc:has_data_value ?averageNumberOfMenDuringRepairmentStr. + BIND(xsd:decimal(str(?averageNumberOfMenDuringRepairmentStr)) as ?averageNumberOfMenDuringRepairment) + + #avamod:failure-description + ?failureDescriptionQ doc:has_answer ?failureDescriptionA. + ?failureDescriptionA doc:has_data_value ?failureDescription. + + #avamod:description-of-corrective-action + ?descriptionOfCorrectiveActionQ doc:has_answer ?descriptionOfCorrectiveActionA. + ?descriptionOfCorrectiveActionA doc:has_data_value ?descriptionOfCorrectiveAction. + + OPTIONAL { + #avamod:number-of-airframe-overhauls + ?numberOfAirframeOverhaulsQ doc:has_answer ?numberOfAirframeOverhaulsA. + ?numberOfAirframeOverhaulsA doc:has_data_value ?numberOfAirframeOverhaulsStr. + BIND(xsd:integer(str(?numberOfAirframeOverhaulsStr)) as ?numberOfAirframeOverhauls) + } + + OPTIONAL { + #avamod:year-of-production-of-defective-equipment + ?yearOfProductionOfDefectiveEquipmentQ doc:has_answer ?yearOfProductionOfDefectiveEquipmentA. + ?yearOfProductionOfDefectiveEquipmentA doc:has_data_value ?yearOfProductionOfDefectiveEquipment.# TODO - transform to more suitable datatype + FILTER(str(spif:trim(?yearOfProductionOfDefectiveEquipment)) != "" ) + } + + OPTIONAL { + #avamod:number-of-overhauls-of-defective-equipment + ?numberOfOverhaulsOfDefectiveEquipmentQ doc:has_answer ?numberOfOverhaulsOfDefectiveEquipmentA. + ?numberOfOverhaulsOfDefectiveEquipmentA doc:has_data_value ?numberOfOverhaulsOfDefectiveEquipment.# TODO - transform to more suitable datatype + FILTER(str(spif:trim(?numberOfOverhaulsOfDefectiveEquipment)) != "" ) + # } + # OPTIONAL{ + # #avamod:serial-no-of + # ?serialNoOfQ doc:has_answer ?serialNoOfA. + # ?serialNoOfA doc:has_data_value ?serialNoOf. + } + OPTIONAL{ + #avamod:notes + ?notesQ doc:has_answer ?notesA. + ?notesA doc:has_data_value ?notes. + FILTER(str(spif:trim(?notes)) != "" ) + } + OPTIONAL{ + #avamod:fha-event + ?fhaEventQ doc:has_answer ?fhaEventA. + ?fhaEventA doc:has_object_value ?fhaEvent. + } + } +} diff --git a/src/main/resources/templates/record-export-template.xlsx b/src/main/resources/templates/record-export-template.xlsx new file mode 100644 index 00000000..942bcbec Binary files /dev/null and b/src/main/resources/templates/record-export-template.xlsx differ