Skip to content
Snippets Groups Projects
Commit 1f2e8a52 authored by Timm Fitschen's avatar Timm Fitschen Committed by Henrik tom Wörden
Browse files

Use subtypes in select queries

Select queries would originally only select the returned properties by their names and would check if a property is a subtype of a selected property. This has changed now and select queries will also return subtypes of selected properties.
parent c9e63feb
No related branches found
No related tags found
No related merge requests found
......@@ -23,6 +23,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
* Select queries would originally only select the returned properties by their
names and would not check if a property is a subtype of a selected property. This
has changed now and select queries will also return subtypes of selected
properties.
### Deprecated
* `SERVER_SIDE_SCRIPTING_BIN_DIR` property is deprecated.
......
......@@ -351,6 +351,33 @@ Any result set can be filtered by logically combining POV filters or back refere
* REFERENCE:: This one is tricky: `REFERENCE TO` expresses a the state of _having_ a reference property. `REFERENCED BY` expresses the state of _being_ referenced by another entity.
* COUNT:: `COUNT` works like `FIND` but doesn't return the entities.
## Select Queries
In contrast to `FIND` queries, which always return the complete entity, there are `SELECT` queries which only return the entity with only those properties which are specified in the query. The syntax is very similar to `FIND` queries - just replace the `FIND` by `SELECT <comma separated list of selectors> FROM`:
`SELECT p1, p2, p3 FROM Record ename`
However, the `SELECT` query can also return properties of referenced entities and thereby are a means of joining entities together and return a custom view or projection:
`SELECT Conductor.Last Name FROM Experiment`
would return the conductor's last name, when `Conductor` is a reference property of `Experiment` and `Last Name` is a property of the `Conductor` records.
### Selectors
Selectors are strings of entity names which are separated by `.` (dot). E.g. `Conductor.Last Name` or `Conductor.Address` or even `Experiment.Conductor.Last name`. Selectors in a `SELECT` queries are separated by `,` (comma). E.g. `Conductor.First Name, Conductor.Last Name`.
### Evaluation of Selectors
The query will return all those properties which have the same name as
specified by the selector (case-insensitive). However, `SELECT` queries are
also capable of subtyping in the selectors:
`SELECT Person FROM Experiment` would return all `Person` properties but all `Conductors` as well, if `Conductor` is a child of `Person`.
Note: When a property `responsible` with data type `Person` exists, the above `SELECT` statement would not include records that use this property (since `responsible` is not a child of Person).
## Versioning
Since Caosdb 0.2 entities are optionally version controlled. The query language will be extended to include versioning in the future. A current minimal implementation introduces the `ANY VERSION OF` modifier which can be used to return all matching versions in the results of `COUNT`, `FIND`, and `SELECT` queries.
......
......@@ -29,19 +29,36 @@ import org.caosdb.server.database.exceptions.TransactionException;
public class IsSubType extends BackendTransaction {
private final Integer child;
private final Integer parent;
private Integer parent = null;
private String parentName = null;
public IsSubType(final Integer child, final Integer parent) {
this.child = child;
this.parent = parent;
}
private boolean isSubType;
public IsSubType(Integer child, String parent) {
this.parentName = parent;
this.child = child;
}
private Boolean isSubType = null;
@Override
public void execute() throws TransactionException {
final IsSubTypeImpl t = getImplementation(IsSubTypeImpl.class);
this.isSubType = t.execute(this.child, this.parent);
if (this.parent == null) {
this.isSubType = false;
for (Integer parent : execute(new GetIDByName(parentName, false)).getList()) {
this.isSubType = t.execute(this.child, parent);
if (this.isSubType) {
return;
}
}
} else {
this.isSubType = t.execute(this.child, this.parent);
}
}
public boolean isSubType() {
......
/*
* ** header v3.0
* This file is a part of the CaosDB Project.
* ** header v3.0 This file is a part of the CaosDB Project.
*
* Copyright (C) 2018 Research Group Biomedical Physics,
* Max-Planck-Institute for Dynamics and Self-Organization Göttingen
* Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
* Copyright (C) 2018 Research Group Biomedical Physics, Max-Planck-Institute for Dynamics and
* Self-Organization Göttingen Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> Copyright
* (C) 2020 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*
* ** end header
*/
......@@ -27,6 +23,7 @@ package org.caosdb.server.database.backend.transaction;
import java.util.LinkedList;
import java.util.List;
import org.caosdb.server.database.BackendTransaction;
import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
import org.caosdb.server.datatype.ReferenceDatatype;
import org.caosdb.server.datatype.ReferenceValue;
import org.caosdb.server.entity.EntityInterface;
......@@ -124,10 +121,9 @@ public class RetrieveFullEntity extends BackendTransaction {
*/
public void retrieveSubEntities(EntityInterface e, List<Selection> selections) {
for (final Selection s : selections) {
String propertyName = s.getSelector();
if (s.getSubselection() != null) {
String propertyName = s.getSelector();
// Find matching (i.e. referencing) Properties
for (Property p : e.getProperties()) {
// get reference properties by name.
......@@ -142,10 +138,47 @@ public class RetrieveFullEntity extends BackendTransaction {
ReferenceValue value = (ReferenceValue) p.getValue();
RetrieveEntity ref = new RetrieveEntity(value.getId());
// recursion! (Only for the matching selections)
// recursion! (Only for the matching selections)
retrieveFullEntity(ref, getSubSelects(selections, propertyName));
value.setEntity(ref, true);
}
continue;
}
try {
boolean isSubtype = execute(new IsSubType(p.getId(), propertyName)).isSubType();
if (isSubtype) {
if (p.getValue() != null) {
if (p.getDatatype() instanceof ReferenceDatatype) {
try {
p.parseValue();
} catch (Message m) {
p.addError(m);
}
ReferenceValue value = (ReferenceValue) p.getValue();
RetrieveEntity ref = new RetrieveEntity(value.getId());
// recursion! (Only for the matching selections)
retrieveFullEntity(ref, getSubSelects(selections, propertyName));
value.setEntity(ref, true);
p.setName(propertyName);
}
}
}
} catch (EntityDoesNotExistException exc) {
// unknown parent name.
}
}
} else {
for (Property p : e.getProperties()) {
if (!propertyName.equalsIgnoreCase(p.getName())) {
try {
boolean isSubtype = execute(new IsSubType(p.getId(), propertyName)).isSubType();
if (isSubtype) {
p.setName(propertyName);
}
} catch (EntityDoesNotExistException exc) {
// unknown parent name.
}
}
}
}
......
......@@ -57,12 +57,10 @@ import org.caosdb.server.utils.Observer;
import org.caosdb.server.utils.ServerMessages;
import org.reflections.Reflections;
/**
* This is a Job.
*
* @todo Describe me.
*
*/
public abstract class Job extends AbstractObservable implements Observer {
private Transaction<? extends TransactionContainer> transaction = null;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment