Query API#
In order to ensure the generality of DTSQL, it operates on a canonical representation of time series (as already explained in the respective section about Time Series). This allows developers to hook up any storage system containing time series data (CSV files, InfluxDB, SQL databases, web services, …) to DTSQL. The paragraphs below explain both how canonical time series are queried and which interfaces are involved in obtaining such queryable time series.
Query Service#
The QueryService interface is very simple, providing only a single method that takes a time series and a DTSQL query and returns a query result (see also the section about Query Results).
Implementations should parse the query into an appropriate internal representation and then evaluate it based on the respective input time series.
classDiagram
class QueryService {
<<interface>>
+query(ts: TimeSeries, dtsqlQuery: String) QueryResult
}
Storage Services#
Before feeding a canonical time series to a QueryService implementation, it has to be extracted from an arbitrary data source.
This is possible via the StorageService, StorageConfig and StorageConfig interfaces.
In general, StorageService provides data access, parameterized by a StorageConfig instance consisting of several StorageProperty values.
The diagrams below visualize the members of each interface.
Underneath them, dedicated content tabs provide a more in-depth view of these three interfaces, explaining their individual methods and depicting succinct examples of how they may be utilized in practice.
classDiagram
class StorageService~T, U extends StorageConfig~ {
<<interface>>
+initialize(svcCfg: U)
+isInitialized() Boolean
+load(lookupCfg: U) T[]
+transform(loadedData: T[], transformCfg: U) TimeSeries
+store(data: TimeSeries, persistCfg: U)
}
class StorageProperty {
<<interface>>
+getIdentifier() String
+getType() Class~V~
}
classDiagram
class StorageConfig {
<<interface>>
+getSupportedProperties() StorageProperty[]
+isPropertySet(prop: StorageProperty) Boolean
+getProperty(prop: StorageProperty, [type: Class~V~]) V
+setProperty(prop: StorageProperty, value: Object) Object
+unsetProperty(prop: StorageProperty) Object
}
Represents an abstraction to be used to connect a custom storage mechanism to a Query Service instance.
Info: Interface Method Descriptions
T: The storage-specific (native) type of data retrieved byload.U: The configuration compatible with currentStorageServiceimplementation, must be a subtype ofStorageConfig.initialize: Can be used for general setup specific to the storage (e.g., connect to database, check I/O availability, …).isInitialized: Determines whether the service has been initialized; is a precondition forstore,loadandtransform.load: Reads required data from the storage with parameters specified bylookupCfginto the native data typeT.transform: Converts the data obtained fromloadinto aTimeSeriesinstance according to the parameters represented bytransformCfg.store: Is meant to store/persist aTimeSeriesinstance into the storage system. This operation basically conducts the inverse conversion oftransform. This method is not needed in the majority of cases. Therefore, generally, it is valid not to implement this method.
Example: CsvStorageService Implementation (Prose)
For this example, we assume CSV file accesses are encapsulated by an third-party library.
T:CsvRow, a data structure provided by the library that represents a line in a CSV file.U:CsvStorageConfig, a derived type ofStorageConfigthat is valid to feed toCsvStorageService(see second tab page for details).initialize: Since file streams are opened and closed at the moment of accessing CSV files, there is nothing like an underlying database connection or web session. Therefore, this method may be empty.isInitialized: For the reasons explained above, this method may always returntrue.load: TheCsvStorageConfiginstancelookupCfgcontains parameters such as file path, field delimiter, and a number of lines to skip before parsing. Using those parameters, the CSV library can be instructed to load the desiredd data asCsvRowinstance.transform: In order to convert a range ofCsvRowinstances toDataPointobjects (and subsequently aTimeSeries), thetransformCfgcontains information such as index of date and value columns and date/time format to correctly parse time components of data points.store: If one were to implement this method,persistCfgshould contain information such as destination path, field separators to use, format to serialize time components into and possibly an option to toggle create/append file modes.
Represents a container for the configuration (properties) of a concrete StorageService.
Info: Interface Method Descriptions
getSupportedProperties: Returns a range ofStoragePropertyinstances that are valid for the currentStorageServiceimplementation. All methods below throw an error if a non-supported property is passed to them.isPropertySet: Determines whether there currently is a value associated withprop.getProperty: Returns the value currently associated withprop, if available. If the optionaltypeparameter is present, the result of this method is of typeV(the type ofprop), otherwiseObject.setProperty: Associatespropwith the value `value and returns the value it previously was associated with, if available.unsetProperty: Removes the association ofpropwith a value and returns the value it previously was associated with, if available.
Example: CsvStorageConfig Implementation (Prose)
The implementation of all interface methods (except getSupportedProperties) is very similar for (almost) all storage mechanisms.
Therefore, it is recommended to provide an abstract base class that conforms to the informal descriptions above.
That way, concrete StorageConfig implementation need only be concerned with supplying the supported storage properties.
The kinds of properties conceivable for a CsvStorageConfig are enumerated on the tab concerned with the StorageProperty interface.
Represents a configuration property to be used within StorageConfig implementations.
Instances of this interface are not associated with values.
The actual values of storage configuration properties are managed solely by StorageConfig instances.
Furthermore, object equality is determined by their identifier.
A StorageConfig must not support two different properties with the same identifier.
Example: CsvStorageProperty Implementation (Prose)
Depending on the concrete programming language, the way of implementing multiple storage properties can differ widely in both manner and succinctity (lambdas, anonymous classes, constants, static final instances, parameterized enum members).
The table below summarizes some possible configuration properties of a CSV storage service.
| name | identifier | type | used by |
|---|---|---|---|
FILE_PATH |
filePath | String | load, store |
FIELD_SEPARATOR |
fieldSeparator | Character | load, store |
TIME_COLUMN |
timeColumn | Integer | transform |
TIME_FORMAT |
timeFormat | String | transform, store |
VALUE_COLUMN |
valueColumn | Integer | transform |
SKIP_HEADERS |
skipHeaders | Integer | load |
APPEND |
append | Boolean | store |
This second example demonstrates a succinct Java representation of the table above, in the form of an enum implementing the StorageProperty interface.
Example: CsvStorageProperty Implementation (Java)
public enum CsvStorageProperty implements StorageProperty {
/**
* Used by load, store.
*/
FILE_PATH("filePath", String.class),
/**
* Used by load, store.
*/
FIELD_SEPARATOR("fieldSeparator", Character.class),
/**
* Used by transform.
*/
TIME_COLUMN("timeColumn", Integer.class),
/**
* Used by transform, store.
*/
TIME_FORMAT("timeFormat", String.class),
/**
* Used by transform.
*/
VALUE_COLUMN("valueColumn", Integer.class),
/**
* Used by load.
*/
SKIP_HEADERS("skipHeaders", Integer.class),
/*
* Used by store.
*/
APPEND("append", Boolean.class),
private final String identifier;
private final Class<?> type;
CsvStorageProperty(String identifier, Class<?> type) {
this.identifier = identifier;
this.type = type;
}
@Override
public String identifier() {
return identifier;
}
@Override
public Class<?> type() {
return type;
}
}