SQL Provider
This provider uses an ontology imported in SQL database. Each entity is saved in a row in the JSON format.
Use HAYSTACK_PROVIDER=shaytack.providers.db or HAYSTACK_PROVIDER=shaytack.providers.sql
to use this provider. Add the variable HAYSTACK_DB to describe the link to the root table. At this time, only
SuperSQLite, Postgresql, MySQL and Athena were supported.
$ pip install 'shaystack[graphql,lambda]'
Install the corresponding database driver:
| Database | Driver |
|---|---|
| sqlite | pip install supersqlite (apt install build-essential before, and may take several minutes) |
| postgres | pip install psycopg2 |
or pip install psycopg2-binary |
|
| mysql | pip install pymysql cryptography |
| athena | install the postgres or mysql driver |
You can use shaystack_import_db to import a Haystack files into the database, only if the entities are modified
(to respect the notion of Version with this provider). The corresponding hisURI time-series files are uploaded too.
shaystack_import_db <haystack file url> <db url>
You can use the parameters:
--customerto set the customer id for all imported records--resetto clean the oldest versions before import a new one--no-time-seriesif you don't want to import the time-series referenced inhisURItags'
To demonstrate the usage with sqlite,
$ # Demo
$ # - Install the components
$ pip install 'shaystack[flask]'
$ # - Install the sqlite driver
$ pip install supersqlite
$ # - Import haystack file in DB
$ shaystack_import_db sample/carytown.zinc sqlite3:///test.db#haystack
$ # - Expose haystack with API
$ HAYSTACK_PROVIDER=shaystack.providers.db \
HAYSTACK_DB=sqlite3:///test.db#haystack \
shaystack
in another shell
$ curl 'http://localhost:3000/haystack/read?filter=site'
air,phone,sensor,occupied,store,damper,enum,temp,tz,tariffHis,sp,area,site,weatherRef,elecCost,hisMode,kwSite,summary,
fan,siteRef,primaryFunction,kind,cmd,geoCountry,elec,lights,geoStreet,occupiedEnd,yearBuilt,siteMeter,geoCoord,
regionRef,occupiedStart,effective,equip,sitePoint,cool,ahu,hvac,costPerHour,unit,lightsGroup,discharge,zone,power,
geoCity,rooftop,navName,outside,point,dis,energy,elecMeterLoad,id,geoAddr,cur,geoState,geoPostalCode,equipRef,meter,
pressure,heat,return,storeNum,his,metro,stage,hisURI
,"804.552.2222",,,✓,,,,"New_York",,,3149.0ft²,✓,"@p:demo:r:23a44701-1af1bca9 Richmond, VA",,,,,,,"Retail Store",,,
"US",,,"3504 W Cary St",20:00:00,1996.0,,"C(37.555385,-77.486903)",@p:demo:r:23a44701-67faf4db Richmond,10:00:00,
,,,,,,,,,,,,"Richmond",,,,,"Carytown",,,@p:demo:r:23a44701-a89a6c66 Carytown,"3504 W Cary St, Richmond, VA",,
"VA","23221",,,,,,1.0,,"Richmond",,
The SQL url is in form: <dialect[+<driver>]>://[<user>[:<password>]@]<host>[:<port>]/<database name>[#<table name>]
Samples:
sqlite3:///test.db#haystacksqlite3://localhost/test.dbsqlite3+supersqlite.sqlite3:///test.db#haystackpostgres://username:password@172.17.0.2:5432/postgresmysql://username:password@172.17.0.2:5432/haystackdb
Inside the SQL url, if the password is in form '<...>', and you use AWS lambda,
the password is retrieved from the service secretManagers. The password
must be in form '<secret_id|key>'. In the secret container secret_id at the key key, the database password must be
set.
After the deployment, you can use this provider like any others providers. The haystack filter was automatically converted to SQL. Three tables were created:
- <table_name> (
haystackby default) - <table_name>_meta_datas
- <table_name>_ts
- and some index.
The column entity use a json version of haystack entity (
See here).
The time-series are saved in a table <table_name>_ts. If you prefer to use a dedicated time-series database, overload
the method hisRead() (see Timestream provider)
<table_name>
| id | customer_id | start_datetime | end_datetime | entity |
|---|---|---|---|---|
| str | str | datetime | datetime | json |
<table_name>_meta_datas
| customer_id | start_datetime | end_datetime | metatdata | cols |
|---|---|---|---|---|
| str | datetime | datetime | json | json |
<table_name>_ts
| id | customer_id | date_time | val |
|---|---|---|---|
| str | str | datetime | str |
To manage the multi-tenancy, it's possible to use different approach:
- Overload the method
get_customer_id()to return the name of the current customer, deduce by the current API caller - Use different tables (change the table name,
...#haystack_customer1,...#haystack_customer2) and publish different API, one by customer.
Limitations
- All entities used with this provider must have an
idtag - SQLite can not manage parentheses with SQL Request with
UNIONorINTERSECT. Some complexe haystack request can not generate a perfect translation to SQL.