UNPKG

signalk-parquet

Version:

Vessel data Parquet file archive with automated value and geospatial triggers. History API compliant with cloud backups and queries.

102 lines 4.93 kB
/** * Inline per-path query filters for the History API. * * A request can narrow a single path to rows whose stored column matches a * value. The first such filter is `sourceRef`: * * navigation.headingMagnetic:average|n2k-on-ve.can0.115 * * filters to the source whose `$source` (stored in the `source_label` column) * is `n2k-on-ve.can0.115`. * * ── Adding another filter ──────────────────────────────────────────────── * Add one entry to PATH_FILTER_DEFS below. Everything else in the read path is * generic over the filter list: raw-tier forcing, parquet/buffer SQL, parquet * schema probing, result keying, and the response echo all iterate the filters * and need no per-filter changes. * * Requirements for a new filter: * - `column` must be written into raw-tier parquet AND the SQLite buffer. * The `source_*` columns already are (see data-handler.ts / sqlite-buffer.ts). * - `delimiter` must be a single character that cannot appear in a SignalK * path or aggregate token (the path sanitiser in HistoryAPI must also allow * it, alongside `|`). * - `field` is the property name echoed back in each response `values` entry. */ /** A resolved filter: match `column` = `value`, echoed back under `field`. */ export interface PathFilter { field: string; column: string; value: string; } interface PathFilterDef { /** Single character that introduces the filter's value in a path expression. */ delimiter: string; /** Response property name echoed in each `values` entry. */ field: string; /** Stored parquet/buffer column the value is matched against. */ column: string; } /** * The registry of supported inline path filters — the single place to add one. */ export declare const PATH_FILTER_DEFS: readonly PathFilterDef[]; /** The set of delimiter characters, for the path sanitiser to preserve. */ export declare const FILTER_DELIMITERS: string; /** * Split inline filters off a path expression, returning the base expression * (path + aggregate + smoothing) and the parsed filters. * * Input: 'navigation.position:first|gps-1' * Output: { base: 'navigation.position:first', * filters: [{ field: 'sourceRef', column: 'source_label', value: 'gps-1' }] } */ export declare function parsePathFilters(expr: string): { base: string; filters: PathFilter[]; }; /** * Build filters from an already-parsed spec object (e.g. a server-provided * History API PathSpec) by reading each registered field off the object. Used * by the v2 provider, where the server — not this plugin — parses the request. */ export declare function filtersFromFields(spec: Record<string, unknown>): PathFilter[]; /** Distinct stored columns referenced by the given filters. */ export declare function filterColumns(filters: PathFilter[]): string[]; /** * Build the parquet-side filter fragment to append to a WHERE clause. * * For each filter: if its column exists in `availableColumns`, append * `AND column = 'value'`; otherwise append `AND 1=0` so the parquet side * contributes nothing — legacy/imported files without the column cannot match, * and the always-tagged SQLite buffer answers through its own filtered subquery. */ export declare function buildParquetFilterClause(filters: PathFilter[], availableColumns: Set<string>): string; /** * Build the buffer-side filter fragment. The buffer schema always carries the * registered filter columns, so no existence check is needed. */ export declare function buildBufferFilterClause(filters?: PathFilter[]): string; /** Response-echo properties for a set of filters, e.g. { sourceRef: '...' }. */ export declare function filterEcho(filters: PathFilter[]): Record<string, string>; /** Minimal view of a DuckDB connection needed to probe a parquet schema. */ export interface SchemaProbeConnection { runAndReadAll: (sql: string) => Promise<{ getRowObjects: () => unknown[]; }>; } /** * Returns true if any of the given parquet globs exposes `column`. Null/empty * paths, globs that match no files, and probe errors are treated as "absent", * so a query that reads from S3 isn't penalised by a local glob that matches no * files (and vice versa). */ export declare function parquetHasColumn(connection: SchemaProbeConnection, filePaths: Array<string | null | undefined>, column: string): Promise<boolean>; /** * The subset of the filters' columns that actually exist in the given parquet * globs. Pass the result to buildParquetFilterClause so absent columns become * `AND 1=0` rather than a "column not found" error. */ export declare function availableFilterColumns(connection: SchemaProbeConnection, filePaths: Array<string | null | undefined>, filters: PathFilter[]): Promise<Set<string>>; export {}; //# sourceMappingURL=path-filters.d.ts.map