de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.PropertyFieldRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of FROST-Server.SQLjooq Show documentation
Show all versions of FROST-Server.SQLjooq Show documentation
SQL bindings for the FROST-Server.
/*
* Copyright (C) 2024 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
* Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils;
import static de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.Utils.getFieldOrNull;
import static de.fraunhofer.iosb.ilt.frostserver.util.Constants.NOT_IMPLEMENTED_MULTI_VALUE_PK;
import de.fraunhofer.iosb.ilt.frostserver.model.DefaultEntity;
import de.fraunhofer.iosb.ilt.frostserver.model.EntityChangedMessage;
import de.fraunhofer.iosb.ilt.frostserver.model.ModelRegistry;
import de.fraunhofer.iosb.ilt.frostserver.model.core.Entity;
import de.fraunhofer.iosb.ilt.frostserver.model.core.PkSingle;
import de.fraunhofer.iosb.ilt.frostserver.model.core.PkValue;
import de.fraunhofer.iosb.ilt.frostserver.model.ext.TimeInstant;
import de.fraunhofer.iosb.ilt.frostserver.model.ext.TimeInterval;
import de.fraunhofer.iosb.ilt.frostserver.model.ext.TimeValue;
import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.bindings.JsonValue;
import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.factories.EntityFactories;
import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.tables.StaMainTable;
import de.fraunhofer.iosb.ilt.frostserver.property.EntityProperty;
import de.fraunhofer.iosb.ilt.frostserver.property.EntityPropertyCustomSelect;
import de.fraunhofer.iosb.ilt.frostserver.property.EntityPropertyMain;
import de.fraunhofer.iosb.ilt.frostserver.property.NavigationPropertyMain;
import de.fraunhofer.iosb.ilt.frostserver.property.NavigationPropertyMain.NavigationPropertyEntity;
import de.fraunhofer.iosb.ilt.frostserver.property.NavigationPropertyMain.NavigationPropertyEntitySet;
import de.fraunhofer.iosb.ilt.frostserver.property.Property;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.time4j.Moment;
import org.apache.commons.lang3.NotImplementedException;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.impl.DSL;
/**
*
* @author hylke
* @param The table type this registry has fields for.
*/
public class PropertyFieldRegistry> {
private final T table;
/**
* The Fields that are allowed be appear in select statements.
*/
private final Map> epMapSelect;
/**
* The Fields that are allowed in where and orderby statements.
*/
private final Map>> epMapAll;
/**
* All select-able fields, by class.
*/
private final List> allSelectPropertyFields;
public static interface ExpressionFactory {
public Field get(T table);
}
/**
* Convert the given Record, holding data from the given Table, into the
* given Entity.
*
* @param The table type.
*/
public static interface ConverterRecordRead {
/**
* Convert the given Record, holding data from the given Table, into the
* given Entity. If possible, the data size is added to the DataSize
* object.
*
* @param table The table used to generate the Record.
* @param input The Record to read the data from.
* @param entity The entity to write the data to.
* @param dataSize The DataSize to use to register the amount of data.
*/
public void convert(T table, Record input, Entity entity, DataSize dataSize);
}
public static interface ConverterRecordInsert {
public void convert(T table, Entity entity, Map insertFields);
}
public static interface ConverterRecordUpdate {
public void convert(T table, Entity entity, Map updateFields, EntityChangedMessage message);
}
public static interface ConverterRecord extends ConverterRecordRead, ConverterRecordInsert, ConverterRecordUpdate {
// No own methods.
}
public static class ConverterRecordDeflt implements ConverterRecord {
private static final ConverterRecordInsert NULL_INSERT = (table, entity, insertFields) -> {
// Does nothing
};
private static final ConverterRecordUpdate NULL_UPDATE = (table, entity, updateFields, message) -> {
// Does nothing
};
private final ConverterRecordRead read;
private final ConverterRecordInsert insert;
private final ConverterRecordUpdate update;
public ConverterRecordDeflt(ConverterRecordRead read, ConverterRecordInsert insert, ConverterRecordUpdate update) {
this.read = read;
this.insert = (insert == null) ? NULL_INSERT : insert;
this.update = (update == null) ? NULL_UPDATE : update;
}
@Override
public void convert(T table, Record input, Entity entity, DataSize dataSize) {
read.convert(table, input, entity, dataSize);
}
@Override
public void convert(T table, Entity entity, Map insertFields) {
insert.convert(table, entity, insertFields);
}
@Override
public void convert(T table, Entity entity, Map updateFields, EntityChangedMessage message) {
update.convert(table, entity, updateFields, message);
}
}
public static class PropertyFields {
public final Property property;
public final boolean jsonType;
public final Map> fields = new LinkedHashMap<>();
public final ConverterRecord converter;
public PropertyFields(Property property, ConverterRecord converter) {
this(property, false, converter);
}
public PropertyFields(Property property, boolean jsonType, ConverterRecord converter) {
this.property = property;
this.converter = converter;
this.jsonType = jsonType;
}
public PropertyFields addField(String name, ExpressionFactory field) {
String key = name;
if (key == null) {
key = Integer.toString(fields.size());
}
fields.put(key, field);
return this;
}
@Override
public String toString() {
return property.getName();
}
}
public static class PropertyFactoryCombo {
public final Property property;
public final ExpressionFactory factory;
public PropertyFactoryCombo(Property property, ExpressionFactory factory) {
this.property = property;
this.factory = factory;
}
}
/**
* A NameFactoryPair for easier passing of a name and a factory.
*
* @param the table type this NFP fetches from.
*/
public static class NFP {
public final String name;
public final ExpressionFactory factory;
public NFP(String name, ExpressionFactory factory) {
this.name = name;
this.factory = factory;
}
}
public PropertyFieldRegistry(T table) {
this.table = table;
this.epMapSelect = new HashMap<>();
this.epMapAll = new HashMap<>();
this.allSelectPropertyFields = new ArrayList<>();
}
public PropertyFieldRegistry(T table, PropertyFieldRegistry copyFrom) {
this.table = table;
this.epMapSelect = copyFrom.epMapSelect;
this.epMapAll = copyFrom.epMapAll;
this.allSelectPropertyFields = copyFrom.allSelectPropertyFields;
}
/**
* Get the Fields for the given class, that are allowed to be used in the
* select clause of a query.
*
* @param The type of collection given as a target.
* @param target The list to add to. If null a new ArrayList will be created.
* @return The target list, or a new list if target was null.
*/
public >> C getSelectFields(C target) {
C result = target;
if (result == null) {
result = (C) new ArrayList();
}
result.addAll(allSelectPropertyFields);
return result;
}
/**
* Get a list of Fields for the given property and table. Add it to the
* given list, or a new list.
*
* @param property The property to get expressions for.
* @return The target list, or a new list if target was null.
*/
public PropertyFields getSelectFieldsForProperty(Property property) {
if (property instanceof EntityPropertyCustomSelect epCustomSelect) {
return table.handleEntityPropertyCustomSelect(epCustomSelect);
} else {
return epMapSelect.get(property);
}
}
/**
* Get a Map of expressions for the given property and table. Add it to the
* given Map, or a new Map.
*
* @param property The property to get expressions for.
* @param target The Map to add to. If null a new Map will be created.
* @return The target Map, or a new Map if target was null.
*/
public Map getAllFieldsForProperty(EntityPropertyMain property, Map target) {
Map> coreMap = epMapAll.get(property);
if (coreMap == null) {
throw new IllegalArgumentException("No property called " + property.toString() + " for " + table.getClass());
}
Map result = target;
if (result == null) {
result = new LinkedHashMap<>();
}
for (Map.Entry> es : coreMap.entrySet()) {
result.put(es.getKey(), es.getValue().get(table));
}
return result;
}
/**
* Get the set of expressions for the given set of selected properties.
*
* @param selectedProperties The set of properties to get the expressions
* of.
* @return The set of expressions.
*/
public Set> getFieldsForProperties(Set selectedProperties) {
Set> exprSet = new LinkedHashSet<>();
if (selectedProperties.isEmpty()) {
getSelectFields(exprSet);
} else {
for (Property property : selectedProperties) {
final PropertyFields selectFieldsForProperty = getSelectFieldsForProperty(property);
if (selectFieldsForProperty != null) {
exprSet.add(selectFieldsForProperty);
}
}
}
return exprSet;
}
public void addEntry(NavigationPropertyMain property, ExpressionFactory factory) {
if (property instanceof NavigationPropertyEntity navigationPropertyEntity) {
addEntry(navigationPropertyEntity, factory);
} else if (property instanceof NavigationPropertyEntitySet navigationPropertyEntitySet) {
addEntry(navigationPropertyEntitySet, factory);
} else {
throw new IllegalArgumentException("Unknown NavigationProperty type: " + property);
}
}
public void addEntry(NavigationPropertyEntity property, ExpressionFactory factory) {
PropertyFields pf = new PropertyFields<>(property, new ConverterEntity<>(property, factory));
pf.addField(null, factory);
epMapSelect.put(property, pf);
allSelectPropertyFields.add(pf);
addEntry(epMapAll, property, null, factory);
}
public void addEntry(NavigationPropertyEntity property, ExpressionFactory factory, ConverterRecord ps) {
PropertyFields pf = new PropertyFields<>(property, ps);
pf.addField(null, factory);
epMapSelect.put(property, pf);
allSelectPropertyFields.add(pf);
addEntry(epMapAll, property, null, factory);
}
public void addEntry(NavigationPropertyEntitySet property, ExpressionFactory factory) {
PropertyFields pf = new PropertyFields<>(property, new ConverterEntitySet<>());
pf.addField(null, factory);
epMapSelect.put(property, pf);
allSelectPropertyFields.add(pf);
addEntry(epMapAll, property, null, factory);
}
public void addEntryString(EntityProperty property, ExpressionFactory factory) {
PropertyFields pf = new PropertyFields<>(property, new ConverterString<>(property, factory));
pf.addField(null, factory);
epMapSelect.put(property, pf);
allSelectPropertyFields.add(pf);
addEntry(epMapAll, property, null, factory);
}
public void addEntryNumeric(EntityProperty property, ExpressionFactory factory) {
PropertyFields pf = new PropertyFields<>(property, new ConverterSimple<>(property, factory));
pf.addField(null, factory);
epMapSelect.put(property, pf);
allSelectPropertyFields.add(pf);
addEntry(epMapAll, property, null, factory);
}
public void addEntryId(ExpressionFactory factory) {
final EntityPropertyMain keyProperty = table.getEntityType().getPrimaryKey().getKeyProperty(0);
final ConverterSimple converterId = new ConverterSimple<>(keyProperty, factory, true, false);
addEntry(keyProperty, factory, converterId);
final ConverterSimple converterSelfLink = new ConverterSimple<>(keyProperty, factory, false, false);
addEntry(ModelRegistry.EP_SELFLINK, factory, converterSelfLink);
}
public void addEntryMap(EntityProperty
© 2015 - 2025 Weber Informatics LLC | Privacy Policy