plans.databases#
SQLite-based database classes for storing and managing hydro-environmental time series.
The base class DataBase structures a database around two table categories:
catalogue tables (variables, flags, sources, statistics) seeded from
shipped CSV files, and operational tables (specs, records) populated per project.
A new database is created from a TOML (or JSON) setup file:
[database]
path = "hydro.db"
[specs]
path = "my_specs.json" # .csv also accepted; format inferred from extension
[catalogs] # optional overrides; omitted keys fall back to defaults
variables = "my_vars.csv"
The specs table describes every dataset stored in records.
A JSON specs file is a list of objects, one per dataset:
[
{
"name": "ppt_monthly_chirps",
"abstract": "Monthly precipitation from CHIRPS v2.0",
"method": "spatial average over watershed",
"timestep": "1M",
"extent": "watershed",
"scale": 1,
"offset": 0,
"start": "1995-01-01",
"end": null,
"variable_name": "precipitation",
"statistic_name": "sum",
"source_name": "CHIRPS v2.0"
}
]
Values in records are stored as stored = actual * scale + offset.
Classes
|
Base SQLite database with a structured schema. |
- class plans.databases.DataBase(name, alias=None)[source]#
Bases:
MbaEBase SQLite database with a structured schema.
Manages catalogue and operational tables for hydro-environmental datasets. Child classes inherit and extend this via
SQL_DIRand override methods where the schema diverges.- Parameters:
name (str) – database name
alias (str, optional) – short alias
- SQL_DIR = PosixPath('/home/runner/work/plans/plans/src/plans/data/sql/base')#
- connect(file_db)[source]#
Open a connection to a SQLite database file.
Enables foreign key enforcement on the connection.
- Parameters:
file_db (str or Path) – path to the SQLite file
- Returns:
active connection
- Return type:
sqlite3.Connection
- close()[source]#
Close the active connection and release the file lock.
Sets
conntoNoneafter closing.- Returns:
None
- Return type:
None
- inspect_schema(table=None, quiet=False)[source]#
Print an overview of the database to stdout.
Without arguments, all tables are rendered three per row in a fixed display order: operational tables first (
records,specs,flags), then catalogue tables (variables,statistics,sources). Whentableis given, only that table is shown. Each block shows the table name, row count, and column names with types. Requires an active connection.- Parameters:
table (str, optional) – name of a single table to inspect; if
Noneall tables are shownquiet (bool) – if
True, suppress printing and only return the string
- Returns:
formatted schema string
- Return type:
str
- inspect_specs(quiet=False)[source]#
Print a summary of all specs defined in the database.
Each spec is shown as a compact card with its identifying fields, time range, linear transform parameters, and abstract. Requires an active connection.
- Parameters:
quiet (bool) – if
True, suppress printing and only return the string- Returns:
formatted specs string
- Return type:
str
- inspect_records(head=10, tail=None, quiet=False)[source]#
Inspect the
recordstable.Always includes the table schema. Then shows the first
headrows and/or the lasttailrows with human-readable timestamps. Set either toNoneto skip that section. Requires an active connection.- Parameters:
head (int, optional) – number of rows to show from the top;
Noneskipstail (int, optional) – number of rows to show from the bottom;
Noneskipsquiet (bool) – if
True, suppress printing and only return the string
- Returns:
formatted records string
- Return type:
str
- execute_sql(sql)[source]#
Execute SQL from a string or a
.sqlfile path.- Parameters:
sql (str or Path) – SQL text or path to a file with
.sqlextension- Returns:
None
- Return type:
None
- query_sql(sql, params=None)[source]#
Execute a SELECT query and return the result as a DataFrame.
Accepts SQL text or a path to a
.sqlfile.- Parameters:
sql (str or Path) – SQL text or path to a file with
.sqlextensionparams (list or tuple, optional) – positional parameters bound to
?placeholders
- Returns:
query result; no datetime conversion is applied — epoch columns remain as integers unless the SQL itself handles the transformation
- Return type:
pandas.DataFrame
Example — convert epoch to a readable UTC string directly in SQLite:
df = db.query_sql( sql="SELECT datetime(datetime, 'unixepoch') AS dt, value FROM records LIMIT 10" )
- static parse_setup(setup)[source]#
Parse a database setup configuration into a plain dict.
Accepts a dict, a path to a TOML file, or a path to a JSON file.
- Parameters:
setup (dict, str, or Path) – configuration source
- Returns:
configuration dict
- Return type:
dict
- Raises:
ValueError – if the file extension is not supported
- new(config, overwrite=False)[source]#
Create a new database file from a setup configuration.
Expected configuration structure (TOML example):
[database] path = "path/to/hydro.db" [specs] path = "path/to/my_specs.csv" # or .json — format detected by extension [catalogs] # optional overrides; omitted keys fall back to defaults variables = "path/to/my_variables.csv"
- Parameters:
config (dict, str, or Path) – setup dict or path to a TOML/JSON file
overwrite (bool) – delete and recreate the file if it already exists
- Returns:
path to the created database file
- Return type:
Path
- Raises:
FileExistsError – if the database file already exists and
overwriteisFalseFileNotFoundError – if the specs file does not exist
- insert_rows(dataframe, on_table, columns_map=None)[source]#
Insert DataFrame rows into a table, keeping only columns that exist in the target.
- Parameters:
dataframe (pandas.DataFrame) – source data
on_table (str) – target table name
columns_map (dict, optional) – column mapping
{db_col: csv_name_or_index}; values may be a string (source column name) or an int (source column position, 0-based)
- Returns:
None
- Return type:
None
- insert_row(row_dict, on_table, columns_map=None)[source]#
Insert a single row from a plain dict into any table.
Convenience wrapper around
insert_rows()for one-row inserts. Epoch conversion is applied automatically for date columns in tables listed in_EPOCH_COLS(e.g.startandendinspecs).- Parameters:
row_dict (dict) – row fields as a dict
on_table (str) – target table name
columns_map (dict, optional) – column mapping
{db_col: csv_name_or_index}
- Returns:
None
- Return type:
None
- insert_records(dataframe, spec_id, flag=None, columns_map=None, transform_values=True, fill_nan=None)[source]#
Insert records into the
recordstable for a given spec.spec_idis broadcast to all rows in the batch. Thedatetimecolumn is converted from text to epoch seconds automatically. The optional linear transform (stored = actual * scale + offset) is resolved from the matching row inspecs.NaN handling in
valueis controlled byfill_nan:Nonedrops rows with NaN values; any other value fills them before inserting.- Parameters:
dataframe (pandas.DataFrame) – source data; must contain at least
datetimeandvalue;flag_valueis also required unlessflagis providedspec_id (int) – foreign key referencing the
specstableflag (int, optional) – if given, overwrite or create the
flag_valuecolumn with this constantcolumns_map (dict, optional) – column mapping
{db_col: csv_name_or_index}; values may be a string (source column name) or an int (source column position, 0-based)transform_values (bool) – apply linear transform if True
fill_nan (float or None) – fill value for NaN entries in
value; ifNone, NaN rows are dropped
- Returns:
None
- Return type:
None
- insert_record(row_dict, spec_id, flag=None, columns_map=None, transform_values=True, fill_nan=None)[source]#
Insert a single record from a plain dict.
Convenience wrapper around
insert_records()for one-row inserts.- Parameters:
row_dict (dict) – record fields, e.g.
{"datetime": "2024-01-01", "value": 12.3}spec_id (int) – foreign key referencing the
specstableflag (int, optional) – if given, overwrite or create the
flag_valuecolumn with this constantcolumns_map (dict, optional) – column mapping
{db_col: csv_name_or_index}; values may be a string (source column name) or an int (source column position, 0-based)transform_values (bool) – apply linear transform if True
fill_nan (float or None) – fill value for NaN entries in
value; ifNone, NaN rows are dropped
- Returns:
None
- Return type:
None
- load_records(files, spec_id, sep=None, flag=None, columns_map=None, transform_values=True, fill_nan=None)[source]#
Load records from a list of CSV files into the
recordstable.All files are read and concatenated, then inserted via
insert_records(). See that method for column requirements and transform behaviour.- Parameters:
files (list[str or Path]) – paths to CSV files to load
spec_id (int) – foreign key referencing the
specstablesep (str, optional) – column separator;
Noneusesfile_csv_sepflag (int, optional) – if given, overwrite or create the
flag_valuecolumn with this constantcolumns_map (dict, optional) – column mapping
{db_col: csv_name_or_index}; values may be a string (source column name) or an int (source column position, 0-based)transform_values (bool) – apply linear transform if True
fill_nan (float or None) – fill value for NaN entries in
value; ifNone, NaN rows are dropped
- Returns:
None
- Return type:
None
- query_records(query_dict=None, quiet=True)[source]#
Query the
recordstable with optional filters combined with AND logic.Filters and options are passed as a single dict so the interface stays stable as new keys are added. All keys are optional; an empty or absent dict returns the full table.
Supported keys:
start(str) — lower datetime bound (inclusive); any format parseable by pandasend(str) — upper datetime bound (inclusive)flag_value(int or list[int]) — one or more flag values to includespec_id(int or list[int]) — one or more spec IDs to includetransform_values(bool, defaultTrue) — reverse the linear transform sovalueholds actual values viaactual = (stored - offset) / scale
The returned
datetimecolumn is always a timezone-aware (UTC) pandas datetime series.- Parameters:
query_dict (dict, optional) – filter and option keys (see above)
quiet (bool) – if
False, prints elapsed query time to stdout
- Returns:
matching rows with
datetimeas UTC-aware pandas Timestamps- Return type:
pandas.DataFrame