Skip to content

Commit

Permalink
Added queryStatusIdentifier. fragmentId optional parameter to querySt…
Browse files Browse the repository at this point in the history
…atus and queryEvent
  • Loading branch information
retrodaredevil committed Apr 9, 2024
1 parent ccf7500 commit 01cf884
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public PacketFinder(SimpleQueryHandler simpleQueryHandler) {
}
}
private void updateWithRange(long queryStart, long queryEnd) {
List<? extends InstancePacketGroup> rawPackets = simpleQueryHandler.queryStatus(queryStart, queryEnd, null);
List<? extends InstancePacketGroup> rawPackets = simpleQueryHandler.queryStatus(queryStart, queryEnd, null, null);
synchronized (cacheMap) {
for (InstancePacketGroup instancePacketGroup : rawPackets) {
int fragmentId = instancePacketGroup.getFragmentId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import me.retrodaredevil.couchdbjava.CouchDbInstance;
import me.retrodaredevil.solarthing.SolarThingConstants;
import me.retrodaredevil.solarthing.annotations.NotNull;
import me.retrodaredevil.solarthing.annotations.Nullable;
import me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings;
import me.retrodaredevil.solarthing.database.MillisDatabase;
import me.retrodaredevil.solarthing.database.MillisQuery;
Expand All @@ -15,13 +16,17 @@
import me.retrodaredevil.solarthing.database.couchdb.CouchDbSolarThingDatabase;
import me.retrodaredevil.solarthing.database.exception.NotFoundSolarThingDatabaseException;
import me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException;
import me.retrodaredevil.solarthing.packets.collection.DefaultInstanceOptions;
import me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup;
import me.retrodaredevil.solarthing.packets.collection.InstancePacketGroup;
import me.retrodaredevil.solarthing.packets.collection.PacketGroup;
import me.retrodaredevil.solarthing.packets.collection.PacketGroups;
import me.retrodaredevil.solarthing.packets.collection.parsing.PacketParsingErrorHandler;
import me.retrodaredevil.solarthing.rest.exceptions.DatabaseException;
import me.retrodaredevil.solarthing.type.alter.StoredAlterPacket;
import me.retrodaredevil.solarthing.type.closed.meta.DefaultMetaDatabase;
import me.retrodaredevil.solarthing.type.closed.meta.EmptyMetaDatabase;
import me.retrodaredevil.solarthing.type.closed.meta.MetaDatabase;
import me.retrodaredevil.solarthing.packets.collection.*;
import me.retrodaredevil.solarthing.packets.collection.parsing.PacketParsingErrorHandler;
import me.retrodaredevil.solarthing.rest.exceptions.DatabaseException;
import me.retrodaredevil.solarthing.type.closed.meta.RootMetaPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -31,7 +36,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -89,7 +93,7 @@ public List<? extends FragmentedPacketGroup> sortPackets(List<? extends Instance
* @param sourceId The source ID or null. If null, the returned List may contain packet groups from multiple sources
* @return The resulting packets
*/
private List<? extends InstancePacketGroup> queryPackets(MillisDatabase database, long from, long to, String sourceId) {
private List<? extends InstancePacketGroup> queryPackets(MillisDatabase database, long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) {

MillisQuery millisQuery = new MillisQueryBuilder()
.startKey(from)
Expand Down Expand Up @@ -148,21 +152,21 @@ private List<? extends InstancePacketGroup> queryPackets(MillisDatabase database
}
return Collections.emptyList();
}
if (sourceId == null) {
return PacketGroups.parseToInstancePacketGroups(rawPacketGroups, defaultInstanceOptions);
}
Map<String, List<InstancePacketGroup>> map = PacketGroups.parsePackets(rawPacketGroups, defaultInstanceOptions);
if(map.containsKey(sourceId)){
List<InstancePacketGroup> instancePacketGroupList = map.get(sourceId);
return PacketGroups.orderByFragment(instancePacketGroupList);
}
throw new NoSuchElementException("No element with sourceId: '" + sourceId + "' available keys are: " + map.keySet());
// Note: Before 2024-04-05 this method would throw a NoSuchElementException if no packets were found under a given Source ID
// Additionally PacketGroups.orderByFragment() was used to order the result ONLY IF a Source ID was provided.
// This behavior of this method has changed since then, which may have unintended effects.
// I really don't know if the ordering by Fragment ID was necessary, and I also don't think we really need that exception to be thrown.
return rawPacketGroups.stream()
.map(packetGroup -> PacketGroups.parseToInstancePacketGroup(packetGroup, defaultInstanceOptions))
.filter(instancePacketGroup -> sourceId == null || instancePacketGroup.getSourceId().equals(sourceId))
.filter(instancePacketGroup -> fragmentId == null || instancePacketGroup.getFragmentId() == fragmentId)
.toList();
}
public List<? extends InstancePacketGroup> queryStatus(long from, long to, String sourceId) {
return queryPackets(database.getStatusDatabase(), from, to, sourceId);
public List<? extends InstancePacketGroup> queryStatus(long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) {
return queryPackets(database.getStatusDatabase(), from, to, sourceId, fragmentId);
}
public List<? extends InstancePacketGroup> queryEvent(long from, long to, String sourceId) {
return queryPackets(database.getEventDatabase(), from, to, sourceId);
public List<? extends InstancePacketGroup> queryEvent(long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) {
return queryPackets(database.getEventDatabase(), from, to, sourceId, fragmentId);
}

public MetaDatabase queryMeta() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import me.retrodaredevil.solarthing.rest.graphql.packets.nodes.PacketNode;

/**
* @deprecated Should not be needed anymore as {@link me.retrodaredevil.solarthing.rest.graphql.SimpleQueryHandler} accepts fragmentIds for most of its methods now.
*/
@Deprecated
public class FragmentFilter implements PacketFilter {
private final int fragmentId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public final class SchemaConstants {
public static final String DESCRIPTION_TO = "The maximum time in milliseconds since the epoch to get data from.";
public static final String DESCRIPTION_OPTIONAL_SOURCE = "The Source ID to include packets from, or null to include packets from multiple sources.";
public static final String DESCRIPTION_REQUIRED_SOURCE = "The Source ID to include packets from.";
public static final String DESCRIPTION_FRAGMENT_ID = "The fragment ID to include data from.";
public static final String DESCRIPTION_OPTIONAL_FRAGMENT_ID = "The fragment ID to include data from.";
public static final String DESCRIPTION_REQUIRED_FRAGMENT_ID = "The fragment ID to include data from.";

}
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ public SolarThingFullDayStatusQuery queryFullDay(
@GraphQLArgument(name = "from", description = "The epoch millis value that will be used to determine the starting day. Set to null to guarantee a query of a single day.") @Nullable Long from,
@GraphQLArgument(name = "to", description = "The epoch millis value that will be used to determine the ending day.") long to,
@GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId,
@GraphQLArgument(name = "useCache", defaultValue = "false") boolean useCache){

LocalDate fromDate = Instant.ofEpochMilli(from == null ? to : from).atZone(zoneId).toLocalDate();
Expand All @@ -292,7 +293,8 @@ public SolarThingFullDayStatusQuery queryFullDay(
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(
queryStart,
queryEnd,
sourceId
sourceId,
fragmentId
);
return new SimpleSolarThingFullDayStatusQuery(new BasicPacketGetter(packets, PacketFilter.KEEP_ALL), simpleQueryHandler.sortPackets(packets, sourceId));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public List<DataNode<FXChargingPacket>> queryFXCharging(
}

long startTime = from - 3 * 60 * 60 * 1000; // 3 hours back
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(startTime, to, null);
// Don't filter on fragmentId here. Even though we are provided with one, we still want data from other fragments as those might have temperature sensor data
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(startTime, to, null, null);

// We make masterIdIgnoreDistance null because we will only be using fragmentId as the master fragment ID
Map<String, List<FragmentedPacketGroup>> map = PacketGroups.sortPackets( // separate based on source ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,34 @@ public SolarThingGraphQLService(SimpleQueryHandler simpleQueryHandler) {
@GraphQLQuery(description = "Query status packets in the specified time range.")
public @NotNull SolarThingStatusQuery queryStatus(
@GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId){
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(from, to, sourceId);
@GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId
){
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(from, to, sourceId, fragmentId);
return new SolarThingStatusQuery(new BasicPacketGetter(packets, PacketFilter.KEEP_ALL), simpleQueryHandler.sortPackets(packets, sourceId), simpleQueryHandler);
}
@GraphQLQuery(description = "Queries status packets in the specified time range while only including the specified identifier in the specified fragment")
public @NotNull SolarThingStatusQuery queryStatusIdentifier(
@GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId,
@GraphQLArgument(name = "identifier") @NotNull String identifierRepresentation,
@GraphQLArgument(name = "acceptSupplementary", defaultValue = "true") boolean acceptSupplementary
) {
// null source ID because each fragment ID is unique, even over multiple sources
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(from, to, null, fragmentId);
return new SolarThingStatusQuery(
new BasicPacketGetter(packets, new IdentifierFilter(identifierRepresentation, acceptSupplementary)),
simpleQueryHandler.sortPackets(packets, null),
simpleQueryHandler
);
}
@GraphQLQuery(description = "Query the latest collection of status packets on or before the 'to' timestamp.")
public @NotNull SolarThingStatusQuery queryStatusLast(
@GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId,
@GraphQLArgument(name = "reversed", defaultValue = "false", description = "If set to true, the returned list will be reversed. Useful to set to true if you want the very latest packet to be first.") boolean reversed){
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(to - SolarThingConstants.LATEST_PACKETS_DURATION.toMillis(), to, sourceId);
List<? extends InstancePacketGroup> packets = simpleQueryHandler.queryStatus(to - SolarThingConstants.LATEST_PACKETS_DURATION.toMillis(), to, sourceId, fragmentId);
List<InstancePacketGroup> lastPackets = new ArrayList<>();
for(List<InstancePacketGroup> packetGroups : PacketGroups.mapFragments(packets).values()) {
lastPackets.add(packetGroups.get(packetGroups.size() - 1));
Expand All @@ -98,31 +116,33 @@ public SolarThingGraphQLService(SimpleQueryHandler simpleQueryHandler) {
public @NotNull SolarThingEventQuery queryEvent(
@GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId,
@GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets
) {
return new SolarThingEventQuery(new BasicPacketGetter(simpleQueryHandler.queryEvent(from, to, sourceId), new UnknownChangePacketsFilter(includeUnknownChangePackets)));
return new SolarThingEventQuery(new BasicPacketGetter(simpleQueryHandler.queryEvent(from, to, sourceId, fragmentId), new UnknownChangePacketsFilter(includeUnknownChangePackets)));
}
@GraphQLQuery(description = "Queries events in the specified time range while only including the specified identifier in the specified fragment")
public @NotNull SolarThingEventQuery queryEventIdentifier(
@GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_FRAGMENT_ID) int fragmentId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId,
@GraphQLArgument(name = "identifier") @NotNull String identifierRepresentation,
@GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets,
@GraphQLArgument(name = "acceptSupplementary", defaultValue = "true") boolean acceptSupplementary
) {
return new SolarThingEventQuery(new BasicPacketGetter(
simpleQueryHandler.queryEvent(from, to, null), // null source ID because each fragment ID is unique, even over multiple sources
new PacketFilterMultiplexer(Arrays.asList(new FragmentFilter(fragmentId), new IdentifierFilter(identifierRepresentation, acceptSupplementary), new UnknownChangePacketsFilter(includeUnknownChangePackets)))
simpleQueryHandler.queryEvent(from, to, null, fragmentId), // null source ID because each fragment ID is unique, even over multiple sources
new PacketFilterMultiplexer(Arrays.asList(new IdentifierFilter(identifierRepresentation, acceptSupplementary), new UnknownChangePacketsFilter(includeUnknownChangePackets)))
));
}
@GraphQLQuery(description = "Queries events in the specified time range while only including the specified fragment")
@Deprecated(forRemoval = true)
@GraphQLQuery(description = "Queries events in the specified time range while only including the specified fragment. Deprecated: Use queryEvent instead")
public @NotNull SolarThingEventQuery queryEventFragment(
@GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_FRAGMENT_ID) int fragmentId,
@GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId,
@GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets
) {
return new SolarThingEventQuery(new BasicPacketGetter(
simpleQueryHandler.queryEvent(from, to, null),
simpleQueryHandler.queryEvent(from, to, null, null), // pass null as a fragmentId here because this is deprecated and might as well not change anything until this is removed
new PacketFilterMultiplexer(Arrays.asList(new FragmentFilter(fragmentId), new UnknownChangePacketsFilter(includeUnknownChangePackets)))
));
}
Expand Down

0 comments on commit 01cf884

Please sign in to comment.