parent
9bc75b9627
commit
b742f0f8d6
127 changed files with 38 additions and 5722 deletions
.cargo
.env.example.sqlx
query-03bfe5bd71d673a621b6ad6af5f71bf18ede519e6b950933f6751ef9cf7521c9.jsonquery-0874e71c6206efc82528cc450bc86549c43e9be2f4ac3b257e836187fa9ed080.jsonquery-08c517120fcfb4534a3ff540910417afca55278e269f12203f4fc83096944810.jsonquery-1348af1c13719ffcd72c2a4c6712b2bab2a9923c715295d8b1d937d33844d1a4.jsonquery-1cb4cc57ff361d6d84a0c8e8f5df1ff46abbb21dfc3eb3f4f38b251f99d10abd.jsonquery-1eda8cf54e553e8e892ac63a31cb94e91e7851a53ebae17a26b19300b83d7dac.jsonquery-20e99a281e5e3e9c9d7375425d93d15ccf840e9f469007d37b6eb47f96f31dc7.jsonquery-2551c285e3e223311cff8e32022d8b11e95d56b2f166326301a0b6722fc1fd44.jsonquery-2e3528a386066c3fc11be1259298f281279353d0b92625c46ef5cd09a672c031.jsonquery-3adb7ab9cacd5a84d882e4c9860be83d32bb0380b1fb76f90bf4e200636c7f6a.jsonquery-3b5a701d0ace12125c573680bcd5d9768b3709b347afb04c329b8fb1d3972111.jsonquery-3fe383ea9ed4965e25d54eea08fb5abbab1b0c8eec7cf11597267de780299d0d.jsonquery-457e9d4808332255ed7354a28e6ebc2015558f66dbcd00cb4ce559d80f2bd023.jsonquery-486ed307f718754a3d4ea2c6fe944f9571c88fad3316593edf0c72ddef24c73e.jsonquery-49afbeaa1d32f8c2e6fea7a2d57a11ec04dd0aab26139c19583af00e5baaba56.jsonquery-4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111.jsonquery-52958684fa52b7a4753cd4356482dc6c655102a501d8aa48e03b1fb3dbbad02d.jsonquery-5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465.jsonquery-66a141b71041a7827f1932e6e288fdab37cc699720e5484c30697b5566b8d513.jsonquery-711398eb64710a25cc818167be8f3b2d03cab39116c2732c06e3c74a02fb0367.jsonquery-7519da166e2e0b6de4c02559fc173396e85db762d482607e4662e788c5542fea.jsonquery-772c710d542c7f5aaa49069fe12a7a37ef509f50954509557ec985c996960da2.jsonquery-7b3ee1cad84a146699b9010be6d31665a416687772b95d159e5d3e98cde3511c.jsonquery-7bbe1a982c77194feba2ff610b01e824b99a3888adf5365619ecfed7ae6544a9.jsonquery-7cd5b42013b4e6a37a670e55cd3ceb0911001eee41256f7b324edc72f5cadcba.jsonquery-7e7cdf2650c08feb10a35275e693d0d3c690b4e9bccc6f0f5fed2bfd2826b480.jsonquery-87b7396fb761030e25836cb90ed07a1bdaa1d82ae3d43d107cf8bac3e9ba4c25.jsonquery-8bdd41a11fd2ca0440b2d6c0dc752a342012048741bdcd1ff9461bc46e1cf701.jsonquery-90ed2cd2f8161552dae06ab2d9cfee8914e253db00e6a648a78e99ade6a4de60.jsonquery-921a0775f75d9e2f67f604265872bf715af1e1ed4d420ac6fa132a94ff352e56.jsonquery-96a0b9960daa8a10e04e22cba592870941545b095193612956c29d37a5a1b774.jsonquery-96f34b8654265ea5ab5210ab5dcad8c0bacd8d9e73e375dc35e759bdb82369a1.jsonquery-a0c9c1a108c6560b4f073c866415a94af2e823a8d88ab2aa5ace8c2b56023004.jsonquery-a1f5699889cfabb3f681e6bb71a8d7c739d0cb82eea1f8289d012c37bd30c776.jsonquery-a64694ec1a81472a05a68b1caf64c32a261bb7d1f34577c0f4dc52e318124ecd.jsonquery-a69f0bf9b3fefd7914502aa15fa120ecf4e5542011b781d8023bdb422580d97a.jsonquery-a6dc153657cb3fefb5ba5b763dc5b7b4da78ab8acec79c7e7ea51ce5c9414bcb.jsonquery-a8b2d9cfd386b5f9ad5b76ef08711691dae057a431fffc27417e4f5504dcfb30.jsonquery-a94cb95af7e6c13e0e155c74de2febe44c1250f25989034a3f9e4e8bcb39dece.jsonquery-ab8dafa95af67dc06074e83e1ec61be2fe713637f883d175f9b279f0f2f8fd87.jsonquery-b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153.jsonquery-b6f6fd898dc3f1dbe2c39bf0445bac76c8233c0feee15f4504bf74ea864716ce.jsonquery-b91f6aab0bdb316633b3a0d75303086dd6e4e204e9e063535b19db666476fe88.jsonquery-bcd9d4dd3641e6c84262ed5f6c5646f825be186da276b113c0150aaad26b057c.jsonquery-c138a9c659a7410e9935ad3f6a56c2bc73174fb1921fe1260702f1eab87d979c.jsonquery-c30156fb112fcc28f08fbbec04197c41c9f71f6a4a3f44221f5ec012c99ebf54.jsonquery-c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2.jsonquery-cb0d76a3a1cfa439d48056c865cd5bfbfbc785fa795254120822b843ce63ff07.jsonquery-cbda6fd5137f3698537262772df22a0a66064e3416e4f5c89d8d83fa6c0536ad.jsonquery-cdcae4768f7b62390e5e5da850e301b502ffd56dd88485cd73b694f6559ccd4e.jsonquery-db48fb93e9f22ee7da0786ae913d962b1da35b5b2b663f759f6af106650951b8.jsonquery-e9386ab7ecbe4ce13f8ee5ee5852697741fb210ea8bfc3d61f1508106c0b076e.jsonquery-e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f.jsonquery-ea4b06aaad9436096e20a53d81fd36ed21da18ceed5b71e51a1e749bab466422.jsonquery-ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d.jsonquery-eee8820f59927c1560a5fd461b9f4a2d40abdf3843d0c815399ea9d267cade5a.jsonquery-f75318134ec1facc3de6b04232cb28a92524b8f556840b76f76c8f317059e668.jsonquery-f7b90a6a0af3f7d7c96158f96f1ada06827a0e5a2d2dbd48bfb8e04f973a6131.jsonquery-fde0dca1aba5b490a9f5f6006677be750a7bcf5d1185935e8386671c69dc7270.json
Cargo.tomlMakefilebuild.rsconfig
core.pklemgauwa-common
|
@ -1,3 +0,0 @@
|
|||
[alias]
|
||||
format = "+nightly fmt"
|
||||
lint = "clippy --all-targets --all-features -- -D warnings"
|
|
@ -1,3 +0,0 @@
|
|||
#EMGAUWA_CONTROLLER__LOGGING__LEVEL=DEBUG
|
||||
|
||||
#EMGAUWA_CORE__LOGGING__LEVEL=DEBUG
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macros WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "03bfe5bd71d673a621b6ad6af5f71bf18ede519e6b950933f6751ef9cf7521c9"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM junction_relay_schedule WHERE relay_id = ? AND weekday = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "0874e71c6206efc82528cc450bc86549c43e9be2f4ac3b257e836187fa9ed080"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "08c517120fcfb4534a3ff540910417afca55278e269f12203f4fc83096944810"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT 1 FROM macros WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "1",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1348af1c13719ffcd72c2a4c6712b2bab2a9923c715295d8b1d937d33844d1a4"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM controllers WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "relay_count",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1cb4cc57ff361d6d84a0c8e8f5df1ff46abbb21dfc3eb3f4f38b251f99d10abd"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE schedules SET name = ?, periods = ? WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "1eda8cf54e553e8e892ac63a31cb94e91e7851a53ebae17a26b19300b83d7dac"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.relay_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "20e99a281e5e3e9c9d7375425d93d15ccf840e9f469007d37b6eb47f96f31dc7"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT relays.* FROM relays INNER JOIN junction_relay_schedule\n\t\t\tON junction_relay_schedule.relay_id = relays.id\n\t\t\tWHERE junction_relay_schedule.schedule_id = ?\n\t\t\tORDER BY junction_relay_schedule.weekday",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "2551c285e3e223311cff8e32022d8b11e95d56b2f166326301a0b6722fc1fd44"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM macro_actions WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2e3528a386066c3fc11be1259298f281279353d0b92625c46ef5cd09a672c031"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM macros WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3adb7ab9cacd5a84d882e4c9860be83d32bb0380b1fb76f90bf4e200636c7f6a"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE relays SET name = ? WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3b5a701d0ace12125c573680bcd5d9768b3709b347afb04c329b8fb1d3972111"
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM tags WHERE tag = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "3fe383ea9ed4965e25d54eea08fb5abbab1b0c8eec7cf11597267de780299d0d"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM schedules WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "457e9d4808332255ed7354a28e6ebc2015558f66dbcd00cb4ce559d80f2bd023"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM macro_actions WHERE macro_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "486ed307f718754a3d4ea2c6fe944f9571c88fad3316593edf0c72ddef24c73e"
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO macros (uid, name) VALUES (?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "49afbeaa1d32f8c2e6fea7a2d57a11ec04dd0aab26139c19583af00e5baaba56"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM relays WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111"
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM tags",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "52958684fa52b7a4753cd4356482dc6c655102a501d8aa48e03b1fb3dbbad02d"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM schedules",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "66a141b71041a7827f1932e6e288fdab37cc699720e5484c30697b5566b8d513"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE controllers SET active = ? WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "711398eb64710a25cc818167be8f3b2d03cab39116c2732c06e3c74a02fb0367"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM controllers",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "relay_count",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7519da166e2e0b6de4c02559fc173396e85db762d482607e4662e788c5542fea"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macro_actions WHERE macro_id = ? AND weekday = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "macro_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "772c710d542c7f5aaa49069fe12a7a37ef509f50954509557ec985c996960da2"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7b3ee1cad84a146699b9010be6d31665a416687772b95d159e5d3e98cde3511c"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule\n\t\t\tON junction_relay_schedule.schedule_id = schedules.id\n\t\t\tWHERE junction_relay_schedule.relay_id = ? AND junction_relay_schedule.weekday = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7bbe1a982c77194feba2ff610b01e824b99a3888adf5365619ecfed7ae6544a9"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO junction_relay_schedule (weekday, relay_id, schedule_id) VALUES (?, ?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7cd5b42013b4e6a37a670e55cd3ceb0911001eee41256f7b324edc72f5cadcba"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM junction_tag WHERE relay_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7e7cdf2650c08feb10a35275e693d0d3c690b4e9bccc6f0f5fed2bfd2826b480"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM junction_tag WHERE schedule_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "87b7396fb761030e25836cb90ed07a1bdaa1d82ae3d43d107cf8bac3e9ba4c25"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macro_actions",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "macro_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "8bdd41a11fd2ca0440b2d6c0dc752a342012048741bdcd1ff9461bc46e1cf701"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM relays WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "90ed2cd2f8161552dae06ab2d9cfee8914e253db00e6a648a78e99ade6a4de60"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT 1 FROM controllers WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "1",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "921a0775f75d9e2f67f604265872bf715af1e1ed4d420ac6fa132a94ff352e56"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT 1 FROM tags WHERE tag = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "1",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "96a0b9960daa8a10e04e22cba592870941545b095193612956c29d37a5a1b774"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "96f34b8654265ea5ab5210ab5dcad8c0bacd8d9e73e375dc35e759bdb82369a1"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macro_actions WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "macro_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a0c9c1a108c6560b4f073c866415a94af2e823a8d88ab2aa5ace8c2b56023004"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE controllers SET active = 0",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a1f5699889cfabb3f681e6bb71a8d7c739d0cb82eea1f8289d012c37bd30c776"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule\n\t\t\tON junction_relay_schedule.schedule_id = schedules.id\n\t\t\tWHERE junction_relay_schedule.relay_id = ?\n\t\t\tORDER BY junction_relay_schedule.weekday",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a64694ec1a81472a05a68b1caf64c32a261bb7d1f34577c0f4dc52e318124ecd"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "a69f0bf9b3fefd7914502aa15fa120ecf4e5542011b781d8023bdb422580d97a"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.schedule_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a6dc153657cb3fefb5ba5b763dc5b7b4da78ab8acec79c7e7ea51ce5c9414bcb"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM schedules WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a8b2d9cfd386b5f9ad5b76ef08711691dae057a431fffc27417e4f5504dcfb30"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM controllers WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a94cb95af7e6c13e0e155c74de2febe44c1250f25989034a3f9e4e8bcb39dece"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM junction_relay_schedule WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ab8dafa95af67dc06074e83e1ec61be2fe713637f883d175f9b279f0f2f8fd87"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM relays WHERE controller_id = ? AND number = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macro_actions WHERE macro_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "macro_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b6f6fd898dc3f1dbe2c39bf0445bac76c8233c0feee15f4504bf74ea864716ce"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "relay_count",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b91f6aab0bdb316633b3a0d75303086dd6e4e204e9e063535b19db666476fe88"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO macro_actions (macro_id, relay_id, schedule_id, weekday) VALUES (?, ?, ?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "macro_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "relay_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "schedule_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "weekday",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "bcd9d4dd3641e6c84262ed5f6c5646f825be186da276b113c0150aaad26b057c"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM macros WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c138a9c659a7410e9935ad3f6a56c2bc73174fb1921fe1260702f1eab87d979c"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM controllers WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "relay_count",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c30156fb112fcc28f08fbbec04197c41c9f71f6a4a3f44221f5ec012c99ebf54"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM relays WHERE controller_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM tags WHERE tag = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cb0d76a3a1cfa439d48056c865cd5bfbfbc785fa795254120822b843ce63ff07"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT 1 FROM schedules WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "1",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "cbda6fd5137f3698537262772df22a0a66064e3416e4f5c89d8d83fa6c0536ad"
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO controllers (uid, name, relay_count) VALUES (?, ?, ?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "relay_count",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"ordinal": 4,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "cdcae4768f7b62390e5e5da850e301b502ffd56dd88485cd73b694f6559ccd4e"
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM tags WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "db48fb93e9f22ee7da0786ae913d962b1da35b5b2b663f759f6af106650951b8"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM schedules WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "periods",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e9386ab7ecbe4ce13f8ee5ee5852697741fb210ea8bfc3d61f1508106c0b076e"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT relay.* FROM relays AS relay INNER JOIN junction_tag ON junction_tag.relay_id = relay.id WHERE junction_tag.tag_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f"
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO tags (tag) VALUES (?) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "tag",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ea4b06aaad9436096e20a53d81fd36ed21da18ceed5b71e51a1e749bab466422"
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM relays",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "controller_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d"
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macros WHERE uid = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "eee8820f59927c1560a5fd461b9f4a2d40abdf3843d0c815399ea9d267cade5a"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE junction_relay_schedule SET weekday = ?, relay_id = ?, schedule_id= ? WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f75318134ec1facc3de6b04232cb28a92524b8f556840b76f76c8f317059e668"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE controllers SET name = ?, relay_count = ? WHERE id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f7b90a6a0af3f7d7c96158f96f1ada06827a0e5a2d2dbd48bfb8e04f973a6131"
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM macros",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "uid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "fde0dca1aba5b490a9f5f6006677be750a7bcf5d1185935e8386671c69dc7270"
|
||||
}
|
38
Cargo.toml
38
Cargo.toml
|
@ -1,7 +1,31 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"emgauwa-core",
|
||||
"emgauwa-controller",
|
||||
"emgauwa-common",
|
||||
]
|
||||
[package]
|
||||
name = "emgauwa-core"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
authors = ["Tobias Reisinger <tobias@msrg.cc>"]
|
||||
|
||||
[dependencies]
|
||||
emgauwa-common = { git = "https://git.serguzim.me/emgauwa/common.git" }
|
||||
|
||||
actix = "0.13"
|
||||
actix-web = "4.4"
|
||||
actix-web-actors = "4.2"
|
||||
actix-cors = "0.7"
|
||||
|
||||
utoipa = "4.2"
|
||||
utoipa-swagger-ui = { version = "6.0", features = ["actix-web", "debug-embed"] }
|
||||
|
||||
log = "0.4"
|
||||
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
uuid = { version = "1.5", features = ["serde", "v4"] }
|
||||
itertools = "0.12"
|
||||
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] }
|
||||
|
||||
futures = "0.3"
|
||||
tokio = { version = "1.36", features = ["rt", "rt-multi-thread"] }
|
||||
|
|
29
Makefile
29
Makefile
|
@ -1,42 +1,23 @@
|
|||
sqlx:
|
||||
cargo sqlx database drop -y
|
||||
cargo sqlx database create
|
||||
cargo sqlx migrate run
|
||||
cargo sqlx prepare --workspace
|
||||
|
||||
build-rpi:
|
||||
cross build --target arm-unknown-linux-gnueabihf
|
||||
|
||||
emgauwa-%.json: config/%.pkl
|
||||
emgauwa-core.json: core.pkl
|
||||
pkl eval -f json -o $@ $<
|
||||
|
||||
configs:
|
||||
config:
|
||||
$(MAKE) emgauwa-core.json
|
||||
$(MAKE) emgauwa-controller.json
|
||||
|
||||
clean:
|
||||
rm -f emgauwa-controller.json
|
||||
rm -f emgauwa-controller.sqlite
|
||||
rm -f emgauwa-core.json
|
||||
rm -f emgauwa-core.sqlite
|
||||
rm -f emgauwa-dev.sqlite
|
||||
|
||||
emgauwa-controller_%:
|
||||
$(TOOL) build --target $* --release --bin emgauwa-controller
|
||||
mkdir -p out/releases
|
||||
cp target/$*/release/emgauwa-controller out/releases/emgauwa-controller_$*
|
||||
|
||||
emgauwa-core_%:
|
||||
$(TOOL) build --target $* --release --bin emgauwa-core
|
||||
mkdir -p out/releases
|
||||
cp target/$*/release/emgauwa-core out/releases/emgauwa-core_$*
|
||||
|
||||
emgauwa_%:
|
||||
$(MAKE) emgauwa-controller_$*
|
||||
$(MAKE) emgauwa-core_$*
|
||||
|
||||
releases:
|
||||
$(MAKE) TOOL=cross emgauwa_arm-unknown-linux-gnueabihf
|
||||
$(MAKE) TOOL=cargo emgauwa_x86_64-unknown-linux-gnu
|
||||
$(MAKE) TOOL=cross emgauwa_x86_64-unknown-linux-musl
|
||||
$(MAKE) TOOL=cross emgauwa-core_arm-unknown-linux-gnueabihf
|
||||
$(MAKE) TOOL=cargo emgauwa-core_x86_64-unknown-linux-gnu
|
||||
$(MAKE) TOOL=cross emgauwa-core_x86_64-unknown-linux-musl
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::process::{exit, Command};
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=../api.v1.yaml");
|
||||
println!("cargo:rerun-if-changed=./api.v1.yaml");
|
||||
let output = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("yq . < ../api.v1.yaml > $OUT_DIR/api.v1.json")
|
||||
.arg("yq . < ./api.v1.yaml > $OUT_DIR/api.v1.json")
|
||||
.output()
|
||||
.expect("Failed to convert api documentation to json");
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
amends "package://emgauwa.app/pkl/emgauwa@0.1.0#/controller.pkl"
|
||||
|
||||
relays {
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 0
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 1
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 2
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 3
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 4
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 5
|
||||
inverted = true
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 10
|
||||
inverted = true
|
||||
pulse = 10
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 11
|
||||
inverted = true
|
||||
pulse = 10
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 20
|
||||
inverted = false
|
||||
}
|
||||
new {
|
||||
driver = "null"
|
||||
pin = 21
|
||||
inverted = false
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
[package]
|
||||
name = "emgauwa-common"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
authors = ["Tobias Reisinger <tobias@msrg.cc>"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
actix = "0.13"
|
||||
actix-web = "4.4"
|
||||
actix-web-actors = "4.2"
|
||||
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
||||
simple_logger = "4.2"
|
||||
log = "0.4"
|
||||
|
||||
config = "0.13"
|
||||
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] }
|
||||
libsqlite3-sys = { version = "*", features = ["bundled"] }
|
||||
uuid = "1.6"
|
||||
futures = "0.3"
|
||||
libc = "0.2"
|
||||
|
||||
rppal = "0.17"
|
||||
rppal-pfd = "0.0.5"
|
||||
rppal-mcp23s17 = "0.0.3"
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("cargo:rerun-if-changed=migrations");
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
use std::time::Duration;
|
||||
|
||||
pub const DEFAULT_PORT: u16 = 4419;
|
||||
pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
|
||||
pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(15);
|
||||
|
||||
pub const WEBSOCKET_RETRY_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
pub const RELAYS_RETRY_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
pub const RELAY_PULSE_DURATION: u64 = 3;
|
|
@ -1,184 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbRelay, DbTag};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::EmgauwaUid;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbController {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
#[serde(rename = "id")]
|
||||
pub uid: EmgauwaUid,
|
||||
pub name: String,
|
||||
pub relay_count: i64,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl DbController {
|
||||
pub async fn get_all(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<DbController>, DatabaseError> {
|
||||
sqlx::query_as!(DbController, "SELECT * FROM controllers")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbController>, DatabaseError> {
|
||||
sqlx::query_as!(DbController, "SELECT * FROM controllers WHERE id = ?", id)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: &EmgauwaUid,
|
||||
) -> Result<Option<DbController>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbController,
|
||||
"SELECT * FROM controllers WHERE uid = ?",
|
||||
filter_uid
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
uid: &EmgauwaUid,
|
||||
new_name: &str,
|
||||
new_relay_count: i64,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
match DbController::get_by_uid(conn, uid).await? {
|
||||
Some(tag) => Ok(tag),
|
||||
None => DbController::create(conn, uid, new_name, new_relay_count).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
) -> Result<Vec<DbController>, DatabaseError> {
|
||||
sqlx::query_as!(DbController, "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn delete_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: EmgauwaUid,
|
||||
) -> Result<(), DatabaseError> {
|
||||
if sqlx::query_scalar!("SELECT 1 FROM controllers WHERE uid = ?", filter_uid)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
return Err(DatabaseError::NotFound);
|
||||
}
|
||||
|
||||
sqlx::query!("DELETE FROM controllers WHERE uid = ?", filter_uid)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_uid: &EmgauwaUid,
|
||||
new_name: &str,
|
||||
new_relay_count: i64,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbController,
|
||||
"INSERT INTO controllers (uid, name, relay_count) VALUES (?, ?, ?) RETURNING *",
|
||||
new_uid,
|
||||
new_name,
|
||||
new_relay_count,
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_name: &str,
|
||||
new_relay_count: i64,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
sqlx::query!(
|
||||
"UPDATE controllers SET name = ?, relay_count = ? WHERE id = ?",
|
||||
new_name,
|
||||
new_relay_count,
|
||||
self.id,
|
||||
)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
Self::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
|
||||
pub async fn update_active(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_active: bool,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
sqlx::query!(
|
||||
"UPDATE controllers SET active = ? WHERE id = ?",
|
||||
new_active,
|
||||
self.id,
|
||||
)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
Self::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
|
||||
pub async fn get_relays(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbRelay,
|
||||
"SELECT * FROM relays WHERE controller_id = ?",
|
||||
self.id
|
||||
)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn all_inactive(conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("UPDATE controllers SET active = 0")
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
Self::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbRelay, DbSchedule};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::Weekday;
|
||||
|
||||
pub struct DbJunctionRelaySchedule {
|
||||
pub id: i64,
|
||||
pub weekday: Weekday,
|
||||
pub relay_id: i64,
|
||||
pub schedule_id: i64,
|
||||
}
|
||||
|
||||
impl DbJunctionRelaySchedule {
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbJunctionRelaySchedule>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbJunctionRelaySchedule,
|
||||
"SELECT * FROM junction_relay_schedule WHERE id = ?",
|
||||
id
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_junction_by_relay_and_weekday(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
relay: &DbRelay,
|
||||
weekday: Weekday,
|
||||
) -> Result<Option<DbJunctionRelaySchedule>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbJunctionRelaySchedule,
|
||||
"SELECT * FROM junction_relay_schedule WHERE relay_id = ? AND weekday = ?",
|
||||
relay.id,
|
||||
weekday
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_relays(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
schedule: &DbSchedule,
|
||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbRelay,
|
||||
r#"SELECT relays.* FROM relays INNER JOIN junction_relay_schedule
|
||||
ON junction_relay_schedule.relay_id = relays.id
|
||||
WHERE junction_relay_schedule.schedule_id = ?
|
||||
ORDER BY junction_relay_schedule.weekday"#,
|
||||
schedule.id
|
||||
)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_schedule(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
relay: &DbRelay,
|
||||
weekday: Weekday,
|
||||
) -> Result<Option<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbSchedule,
|
||||
r#"SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule
|
||||
ON junction_relay_schedule.schedule_id = schedules.id
|
||||
WHERE junction_relay_schedule.relay_id = ? AND junction_relay_schedule.weekday = ?"#,
|
||||
relay.id,
|
||||
weekday
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_schedules(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
relay: &DbRelay,
|
||||
) -> Result<Vec<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbSchedule,
|
||||
r#"SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule
|
||||
ON junction_relay_schedule.schedule_id = schedules.id
|
||||
WHERE junction_relay_schedule.relay_id = ?
|
||||
ORDER BY junction_relay_schedule.weekday"#,
|
||||
relay.id
|
||||
)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn set_schedule(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
relay: &DbRelay,
|
||||
schedule: &DbSchedule,
|
||||
weekday: Weekday,
|
||||
) -> Result<DbJunctionRelaySchedule, DatabaseError> {
|
||||
match Self::get_junction_by_relay_and_weekday(conn, relay, weekday).await? {
|
||||
None => sqlx::query_as!(
|
||||
DbJunctionRelaySchedule,
|
||||
"INSERT INTO junction_relay_schedule (weekday, relay_id, schedule_id) VALUES (?, ?, ?) RETURNING *",
|
||||
weekday,
|
||||
relay.id,
|
||||
schedule.id
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError),
|
||||
|
||||
Some(junction) => {
|
||||
sqlx::query!(
|
||||
"UPDATE junction_relay_schedule SET weekday = ?, relay_id = ?, schedule_id= ? WHERE id = ?",
|
||||
weekday,
|
||||
relay.id,
|
||||
schedule.id,
|
||||
junction.id
|
||||
)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
Self::get(conn, junction.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_schedules(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
relay: &DbRelay,
|
||||
schedules: Vec<&DbSchedule>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
for (weekday, schedule) in schedules.iter().enumerate() {
|
||||
Self::set_schedule(conn, relay, schedule, weekday as Weekday).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbRelay, DbSchedule, DbTag};
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
pub struct DbJunctionTag {
|
||||
pub id: i64,
|
||||
pub tag_id: i64,
|
||||
pub relay_id: Option<i64>,
|
||||
pub schedule_id: Option<i64>,
|
||||
}
|
||||
|
||||
impl DbJunctionTag {
|
||||
pub async fn link_relay(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
relay: &DbRelay,
|
||||
) -> Result<DbJunctionTag, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbJunctionTag,
|
||||
"INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *",
|
||||
tag.id,
|
||||
relay.id
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn link_schedule(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
schedule: &DbSchedule,
|
||||
) -> Result<DbJunctionTag, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbJunctionTag,
|
||||
"INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *",
|
||||
tag.id,
|
||||
schedule.id
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbController, DbMacroAction, DbRelay, DbSchedule};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::{EmgauwaUid, RequestMacroAction};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbMacro {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
#[serde(rename = "id")]
|
||||
pub uid: EmgauwaUid,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
|
||||
impl DbMacro {
|
||||
pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbMacro>, DatabaseError> {
|
||||
sqlx::query_as!(DbMacro, "SELECT * FROM macros")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbMacro>, DatabaseError> {
|
||||
sqlx::query_as!(DbMacro, "SELECT * FROM macros WHERE id = ?", id)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: &EmgauwaUid,
|
||||
) -> Result<Option<DbMacro>, DatabaseError> {
|
||||
sqlx::query_as!(DbMacro, "SELECT * FROM macros WHERE uid = ?", filter_uid)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_uid: EmgauwaUid,
|
||||
new_name: &str,
|
||||
) -> Result<DbMacro, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbMacro,
|
||||
"INSERT INTO macros (uid, name) VALUES (?, ?) RETURNING *",
|
||||
new_uid,
|
||||
new_name
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM macros WHERE id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn delete_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: EmgauwaUid,
|
||||
) -> Result<(), DatabaseError> {
|
||||
if sqlx::query_scalar!("SELECT 1 FROM macros WHERE uid = ?", filter_uid)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
return Err(DatabaseError::NotFound);
|
||||
}
|
||||
|
||||
sqlx::query!("DELETE FROM macros WHERE uid = ?", filter_uid)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_name: &str,
|
||||
) -> Result<DbMacro, DatabaseError> {
|
||||
sqlx::query!("UPDATE relays SET name = ? WHERE id = ?", new_name, self.id,)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
DbMacro::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
|
||||
pub async fn set_actions(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_actions: &[RequestMacroAction],
|
||||
) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM macro_actions WHERE macro_id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
for new_action in new_actions {
|
||||
let controller = DbController::get_by_uid(conn, &new_action.relay.controller_id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)?;
|
||||
let relay =
|
||||
DbRelay::get_by_controller_and_num(conn, &controller, new_action.relay.number)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)?;
|
||||
|
||||
let schedule = DbSchedule::get_by_uid(conn, &new_action.schedule.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)?;
|
||||
|
||||
DbMacroAction::create(conn, self, &relay, &schedule, new_action.weekday).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_actions(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<DbMacroAction>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbMacroAction,
|
||||
"SELECT * FROM macro_actions WHERE macro_id = ?",
|
||||
self.id
|
||||
)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_actions_weekday(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
weekday: i64,
|
||||
) -> Result<Vec<DbMacroAction>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbMacroAction,
|
||||
"SELECT * FROM macro_actions WHERE macro_id = ? AND weekday = ?",
|
||||
self.id,
|
||||
weekday
|
||||
)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbMacro, DbRelay, DbSchedule};
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DbMacroAction {
|
||||
pub id: i64,
|
||||
pub macro_id: i64,
|
||||
pub relay_id: i64,
|
||||
pub schedule_id: i64,
|
||||
pub weekday: i64, // should be u8, but sqlite will store it as i64
|
||||
}
|
||||
|
||||
|
||||
impl DbMacroAction {
|
||||
pub async fn get_all(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<DbMacroAction>, DatabaseError> {
|
||||
sqlx::query_as!(DbMacroAction, "SELECT * FROM macro_actions")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbMacroAction>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbMacroAction,
|
||||
"SELECT * FROM macro_actions WHERE id = ?",
|
||||
id
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_macro: &DbMacro,
|
||||
new_relay: &DbRelay,
|
||||
new_schedule: &DbSchedule,
|
||||
new_weekday: i64,
|
||||
) -> Result<DbMacroAction, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbMacroAction,
|
||||
"INSERT INTO macro_actions (macro_id, relay_id, schedule_id, weekday) VALUES (?, ?, ?, ?) RETURNING *",
|
||||
new_macro.id,
|
||||
new_relay.id,
|
||||
new_schedule.id,
|
||||
new_weekday
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM macro_actions WHERE id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn get_relay(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbRelay, DatabaseError> {
|
||||
DbRelay::get(conn, self.relay_id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn get_schedule(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbSchedule, DatabaseError> {
|
||||
DbSchedule::get(conn, self.schedule_id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn get_macro(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbMacro, DatabaseError> {
|
||||
DbMacro::get(conn, self.macro_id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||
use sqlx::{ConnectOptions, Pool, Sqlite};
|
||||
|
||||
mod controllers;
|
||||
mod junction_relay_schedule;
|
||||
mod junction_tag;
|
||||
mod r#macro;
|
||||
mod macro_action;
|
||||
mod model_utils;
|
||||
mod relays;
|
||||
mod schedules;
|
||||
mod tag;
|
||||
|
||||
pub use controllers::DbController;
|
||||
pub use junction_relay_schedule::DbJunctionRelaySchedule;
|
||||
pub use junction_tag::DbJunctionTag;
|
||||
pub use macro_action::DbMacroAction;
|
||||
pub use r#macro::DbMacro;
|
||||
pub use relays::DbRelay;
|
||||
pub use schedules::{DbPeriods, DbSchedule};
|
||||
pub use tag::DbTag;
|
||||
|
||||
use crate::errors::{DatabaseError, EmgauwaError};
|
||||
|
||||
static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
|
||||
|
||||
pub async fn run_migrations(pool: &Pool<Sqlite>) -> Result<(), EmgauwaError> {
|
||||
log::info!("Running migrations");
|
||||
MIGRATOR.run(pool).await.map_err(DatabaseError::from)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn init(db: &str) -> Result<Pool<Sqlite>, EmgauwaError> {
|
||||
let options = SqliteConnectOptions::from_str(db)?
|
||||
.create_if_missing(true)
|
||||
.log_statements(log::LevelFilter::Trace);
|
||||
|
||||
let pool: Pool<Sqlite> = SqlitePoolOptions::new()
|
||||
.acquire_timeout(std::time::Duration::from_secs(1))
|
||||
.max_connections(5)
|
||||
.connect_with(options)
|
||||
.await?;
|
||||
|
||||
run_migrations(&pool).await?;
|
||||
|
||||
let mut pool_conn = pool.acquire().await?;
|
||||
|
||||
DbSchedule::get_on(&mut pool_conn).await?;
|
||||
DbSchedule::get_off(&mut pool_conn).await?;
|
||||
|
||||
Ok(pool)
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
use chrono::{NaiveTime, Timelike};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::database::HasArguments;
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
||||
use sqlx::{Decode, Encode, Sqlite, Type};
|
||||
|
||||
use crate::db::DbPeriods;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
pub struct Period {
|
||||
#[serde(with = "period_format")]
|
||||
pub start: NaiveTime,
|
||||
#[serde(with = "period_format")]
|
||||
pub end: NaiveTime,
|
||||
}
|
||||
|
||||
mod period_format {
|
||||
use chrono::NaiveTime;
|
||||
use serde::{self, Deserialize, Deserializer, Serializer};
|
||||
|
||||
const FORMAT: &str = "%H:%M";
|
||||
|
||||
pub fn serialize<S>(time: &NaiveTime, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let s = format!("{}", time.format(FORMAT));
|
||||
serializer.serialize_str(&s)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<NaiveTime, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
NaiveTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
impl Period {
|
||||
pub fn new(start: NaiveTime, end: NaiveTime) -> Self {
|
||||
Period { start, end }
|
||||
}
|
||||
|
||||
pub fn new_on() -> Self {
|
||||
Period {
|
||||
start: NaiveTime::MIN,
|
||||
end: NaiveTime::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
||||
self.start.eq(&self.end) || (self.start.le(now) && self.end.gt(now))
|
||||
}
|
||||
|
||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||
if self.start.eq(&self.end) {
|
||||
// this period is always on
|
||||
return None;
|
||||
}
|
||||
|
||||
let start_after_now = self.start.gt(now);
|
||||
let end_after_now = self.end.gt(now);
|
||||
let start_before_end = self.start.lt(&self.end);
|
||||
|
||||
match (start_after_now, end_after_now, start_before_end) {
|
||||
(false, false, _) => None, // both before now
|
||||
(true, false, _) => Some(self.start), // only start after now
|
||||
(false, true, _) => Some(self.end), // only end after now
|
||||
(true, true, true) => Some(self.start), // both after now but start first
|
||||
(true, true, false) => Some(self.end), // both after now but end first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type<Sqlite> for DbPeriods {
|
||||
fn type_info() -> SqliteTypeInfo {
|
||||
<&[u8] as Type<Sqlite>>::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &SqliteTypeInfo) -> bool {
|
||||
<&[u8] as Type<Sqlite>>::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'q> Encode<'q, Sqlite> for DbPeriods {
|
||||
//noinspection DuplicatedCode
|
||||
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
|
||||
<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> Decode<'r, Sqlite> for DbPeriods {
|
||||
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
|
||||
let blob = <&[u8] as Decode<Sqlite>>::decode(value)?;
|
||||
Ok(DbPeriods::from(Vec::from(blob)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&DbPeriods> for Vec<u8> {
|
||||
fn from(periods: &DbPeriods) -> Vec<u8> {
|
||||
periods
|
||||
.0
|
||||
.iter()
|
||||
.flat_map(|period| {
|
||||
let vec = vec![
|
||||
period.start.hour() as u8,
|
||||
period.start.minute() as u8,
|
||||
period.end.hour() as u8,
|
||||
period.end.minute() as u8,
|
||||
];
|
||||
vec
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for DbPeriods {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
let mut vec = Vec::new();
|
||||
for i in (3..value.len()).step_by(4) {
|
||||
let start_val_h: u32 = value[i - 3] as u32;
|
||||
let start_val_m: u32 = value[i - 2] as u32;
|
||||
let end_val_h: u32 = value[i - 1] as u32;
|
||||
let end_val_m: u32 = value[i] as u32;
|
||||
vec.push(Period {
|
||||
start: NaiveTime::from_hms_opt(start_val_h, start_val_m, 0)
|
||||
.expect("Failed to parse period start time from database"),
|
||||
end: NaiveTime::from_hms_opt(end_val_h, end_val_m, 0)
|
||||
.expect("Failed to parse period end time from database"),
|
||||
});
|
||||
}
|
||||
DbPeriods(vec)
|
||||
}
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbController, DbJunctionRelaySchedule, DbJunctionTag, DbSchedule, DbTag};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::Weekday;
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbRelay {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub number: i64,
|
||||
#[serde(skip)]
|
||||
pub controller_id: i64,
|
||||
}
|
||||
|
||||
|
||||
impl DbRelay {
|
||||
pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(DbRelay, "SELECT * FROM relays")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_controller_and_num(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
controller: &DbController,
|
||||
number: i64,
|
||||
) -> Result<Option<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbRelay,
|
||||
"SELECT * FROM relays WHERE controller_id = ? AND number = ?",
|
||||
controller.id,
|
||||
number
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_controller_and_num_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
controller: &DbController,
|
||||
number: i64,
|
||||
new_name: &str,
|
||||
) -> Result<(DbRelay, bool), DatabaseError> {
|
||||
match DbRelay::get_by_controller_and_num(conn, controller, number).await? {
|
||||
Some(relay) => Ok((relay, false)),
|
||||
None => {
|
||||
let relay = DbRelay::create(conn, new_name, number, controller).await?;
|
||||
Ok((relay, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||
sqlx::query_as!(DbRelay, "SELECT relay.* FROM relays AS relay INNER JOIN junction_tag ON junction_tag.relay_id = relay.id WHERE junction_tag.tag_id = ?", tag.id)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_name: &str,
|
||||
new_number: i64,
|
||||
new_controller: &DbController,
|
||||
) -> Result<DbRelay, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbRelay,
|
||||
"INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?) RETURNING *",
|
||||
new_name,
|
||||
new_number,
|
||||
new_controller.id,
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM relays WHERE id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_name: &str,
|
||||
) -> Result<DbRelay, DatabaseError> {
|
||||
sqlx::query!("UPDATE relays SET name = ? WHERE id = ?", new_name, self.id,)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
DbRelay::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
|
||||
pub async fn get_controller(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbController, DatabaseError> {
|
||||
DbController::get(conn, self.controller_id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn get_tags(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<String>, DatabaseError> {
|
||||
sqlx::query_scalar!("SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.relay_id = ?", self.id)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn set_tags(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_tags: &[String],
|
||||
) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM junction_tag WHERE relay_id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
for new_tag in new_tags {
|
||||
let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?;
|
||||
DbJunctionTag::link_relay(conn, &tag, self).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbRelay, DatabaseError> {
|
||||
Self::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn get_active_schedule(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbSchedule, DatabaseError> {
|
||||
let weekday = utils::get_weekday();
|
||||
DbJunctionRelaySchedule::get_schedule(conn, self, weekday as Weekday)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use chrono::NaiveTime;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::model_utils::Period;
|
||||
use crate::db::{DbJunctionTag, DbTag};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::ScheduleUid;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DbSchedule {
|
||||
#[serde(skip)]
|
||||
pub id: i64,
|
||||
#[serde(rename = "id")]
|
||||
pub uid: ScheduleUid,
|
||||
pub name: String,
|
||||
pub periods: DbPeriods,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
pub struct DbPeriods(pub Vec<Period>);
|
||||
|
||||
impl DbSchedule {
|
||||
pub async fn get_all(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(DbSchedule, "SELECT * FROM schedules")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(DbSchedule, "SELECT * FROM schedules WHERE id = ?", id)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: &ScheduleUid,
|
||||
) -> Result<Option<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbSchedule,
|
||||
"SELECT * FROM schedules WHERE uid = ?",
|
||||
filter_uid
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
tag: &DbTag,
|
||||
) -> Result<Vec<DbSchedule>, DatabaseError> {
|
||||
sqlx::query_as!(DbSchedule, "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn delete_by_uid(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_uid: ScheduleUid,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let filter_uid = match filter_uid {
|
||||
ScheduleUid::Off => Err(DatabaseError::Protected),
|
||||
ScheduleUid::On => Err(DatabaseError::Protected),
|
||||
ScheduleUid::Any(_) => Ok(filter_uid),
|
||||
}?;
|
||||
|
||||
if sqlx::query_scalar!("SELECT 1 FROM schedules WHERE uid = ?", filter_uid)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
return Err(DatabaseError::NotFound);
|
||||
}
|
||||
|
||||
sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_uid: ScheduleUid,
|
||||
new_name: &str,
|
||||
new_periods: &DbPeriods,
|
||||
) -> Result<DbSchedule, DatabaseError> {
|
||||
sqlx::query_as!(
|
||||
DbSchedule,
|
||||
"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
|
||||
new_uid,
|
||||
new_name,
|
||||
new_periods,
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn get_by_uid_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
uid: ScheduleUid,
|
||||
name: &str,
|
||||
periods: &DbPeriods,
|
||||
) -> Result<(DbSchedule, bool), DatabaseError> {
|
||||
match DbSchedule::get_by_uid(conn, &uid).await? {
|
||||
Some(schedule) => Ok((schedule, false)),
|
||||
None => {
|
||||
let schedule = DbSchedule::create(conn, uid, name, periods).await?;
|
||||
Ok((schedule, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_on(conn: &mut PoolConnection<Sqlite>) -> Result<DbSchedule, DatabaseError> {
|
||||
if let Some(schedule) = DbSchedule::get_by_uid(conn, &ScheduleUid::On).await? {
|
||||
return Ok(schedule);
|
||||
}
|
||||
let periods = DbPeriods(vec![Period::new_on()]);
|
||||
Self::create(conn, ScheduleUid::On, "On", &periods).await
|
||||
}
|
||||
|
||||
pub async fn get_off(conn: &mut PoolConnection<Sqlite>) -> Result<DbSchedule, DatabaseError> {
|
||||
if let Some(schedule) = DbSchedule::get_by_uid(conn, &ScheduleUid::Off).await? {
|
||||
return Ok(schedule);
|
||||
}
|
||||
let periods = DbPeriods(vec![]);
|
||||
Self::create(conn, ScheduleUid::Off, "Off", &periods).await
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_name: &str,
|
||||
new_periods: &DbPeriods,
|
||||
) -> Result<DbSchedule, DatabaseError> {
|
||||
// overwrite periods on protected schedules
|
||||
let new_periods = match self.uid {
|
||||
ScheduleUid::Off | ScheduleUid::On => self.periods.borrow(),
|
||||
ScheduleUid::Any(_) => new_periods,
|
||||
};
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE schedules SET name = ?, periods = ? WHERE id = ?",
|
||||
new_name,
|
||||
new_periods,
|
||||
self.id,
|
||||
)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
DbSchedule::get(conn, self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::UpdateGetError)
|
||||
}
|
||||
|
||||
pub async fn get_tags(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Vec<String>, DatabaseError> {
|
||||
Ok(sqlx::query_scalar!("SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.schedule_id = ?", self.id)
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn set_tags(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_tags: &[String],
|
||||
) -> Result<(), DatabaseError> {
|
||||
sqlx::query!("DELETE FROM junction_tag WHERE schedule_id = ?", self.id)
|
||||
.execute(conn.deref_mut())
|
||||
.await?;
|
||||
|
||||
for new_tag in new_tags {
|
||||
let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?;
|
||||
DbJunctionTag::link_schedule(conn, &tag, self).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
||||
self.periods.0.iter().any(|period| period.is_on(now))
|
||||
}
|
||||
|
||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||
self.periods
|
||||
.0
|
||||
.iter()
|
||||
.filter_map(|period| period.get_next_time(now))
|
||||
.min()
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use serde_derive::Serialize;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct DbTag {
|
||||
pub id: i64,
|
||||
pub tag: String,
|
||||
}
|
||||
|
||||
impl DbTag {
|
||||
pub async fn create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
new_tag: &str,
|
||||
) -> Result<DbTag, DatabaseError> {
|
||||
if new_tag.is_empty() {
|
||||
return Err(DatabaseError::EmptyDataInsert);
|
||||
}
|
||||
|
||||
sqlx::query_as!(
|
||||
DbTag,
|
||||
"INSERT INTO tags (tag) VALUES (?) RETURNING *",
|
||||
new_tag
|
||||
)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.ok_or(DatabaseError::InsertGetError)
|
||||
}
|
||||
|
||||
pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbTag>, DatabaseError> {
|
||||
sqlx::query_as!(DbTag, "SELECT * FROM tags")
|
||||
.fetch_all(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
id: i64,
|
||||
) -> Result<Option<DbTag>, DatabaseError> {
|
||||
sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE id = ?", id)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn get_by_tag_or_create(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
target_tag: &str,
|
||||
) -> Result<DbTag, DatabaseError> {
|
||||
match DbTag::get_by_tag(conn, target_tag).await? {
|
||||
Some(tag) => Ok(tag),
|
||||
None => DbTag::create(conn, target_tag).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
target_tag: &str,
|
||||
) -> Result<Option<DbTag>, DatabaseError> {
|
||||
sqlx::query_as!(DbTag, "SELECT * FROM tags WHERE tag = ?", target_tag)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await
|
||||
.map_err(DatabaseError::from)
|
||||
}
|
||||
|
||||
pub async fn delete_by_tag(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
filter_tag: &str,
|
||||
) -> Result<(), DatabaseError> {
|
||||
if sqlx::query_scalar!("SELECT 1 FROM tags WHERE tag = ?", filter_tag)
|
||||
.fetch_optional(conn.deref_mut())
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
return Err(DatabaseError::NotFound);
|
||||
}
|
||||
|
||||
sqlx::query!("DELETE FROM tags WHERE tag = ?", filter_tag)
|
||||
.execute(conn.deref_mut())
|
||||
.await
|
||||
.map(|res| match res.rows_affected() {
|
||||
0 => Err(DatabaseError::DeleteError),
|
||||
_ => Ok(()),
|
||||
})?
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
use rppal::gpio::{Gpio, OutputPin};
|
||||
|
||||
use crate::drivers::RelayDriver;
|
||||
use crate::errors::EmgauwaError;
|
||||
|
||||
pub struct GpioDriver {
|
||||
pub gpio: OutputPin,
|
||||
pub inverted: bool,
|
||||
}
|
||||
|
||||
impl GpioDriver {
|
||||
pub fn new(pin: u8, inverted: bool) -> Result<Self, EmgauwaError> {
|
||||
let gpio = Gpio::new()?.get(pin)?.into_output();
|
||||
Ok(Self { gpio, inverted })
|
||||
}
|
||||
}
|
||||
|
||||
impl RelayDriver for GpioDriver {
|
||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError> {
|
||||
if self.get_high(value) {
|
||||
self.gpio.set_high();
|
||||
} else {
|
||||
self.gpio.set_low();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pin(&self) -> u8 {
|
||||
self.gpio.pin()
|
||||
}
|
||||
|
||||
fn get_inverted(&self) -> bool {
|
||||
self.inverted
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
mod gpio;
|
||||
mod null;
|
||||
mod piface;
|
||||
|
||||
pub use gpio::GpioDriver;
|
||||
pub use null::NullDriver;
|
||||
pub use piface::PiFaceDriver;
|
||||
|
||||
use crate::errors::EmgauwaError;
|
||||
|
||||
pub trait RelayDriver {
|
||||
fn get_high(&self, value: bool) -> bool {
|
||||
value ^ self.get_inverted()
|
||||
}
|
||||
|
||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError>;
|
||||
fn get_pin(&self) -> u8;
|
||||
fn get_inverted(&self) -> bool;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
use crate::drivers::RelayDriver;
|
||||
use crate::errors::EmgauwaError;
|
||||
|
||||
pub struct NullDriver {
|
||||
pub pin: u8,
|
||||
}
|
||||
|
||||
impl NullDriver {
|
||||
pub fn new(pin: u8) -> Self {
|
||||
Self { pin }
|
||||
}
|
||||
}
|
||||
|
||||
impl RelayDriver for NullDriver {
|
||||
fn set(&mut self, _value: bool) -> Result<(), EmgauwaError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pin(&self) -> u8 {
|
||||
self.pin
|
||||
}
|
||||
|
||||
fn get_inverted(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
use rppal_pfd::{
|
||||
ChipSelect, HardwareAddress, OutputPin, PiFaceDigital, PiFaceDigitalError, SpiBus, SpiMode,
|
||||
};
|
||||
|
||||
use crate::drivers::RelayDriver;
|
||||
use crate::errors::EmgauwaError;
|
||||
|
||||
pub struct PiFaceDriver {
|
||||
pub pfd_pin: OutputPin,
|
||||
}
|
||||
|
||||
impl PiFaceDriver {
|
||||
pub fn new(pin: u8, pfd: &Option<PiFaceDigital>) -> Result<Self, EmgauwaError> {
|
||||
let pfd = pfd.as_ref().ok_or(EmgauwaError::Hardware(String::from(
|
||||
"PiFaceDigital not initialized",
|
||||
)))?;
|
||||
let pfd_pin = pfd.get_output_pin(pin)?;
|
||||
Ok(Self { pfd_pin })
|
||||
}
|
||||
|
||||
pub fn init_piface() -> Result<PiFaceDigital, EmgauwaError> {
|
||||
let mut pfd = PiFaceDigital::new(
|
||||
HardwareAddress::new(0)?,
|
||||
SpiBus::Spi0,
|
||||
ChipSelect::Cs0,
|
||||
100_000,
|
||||
SpiMode::Mode0,
|
||||
)?;
|
||||
pfd.init()?;
|
||||
|
||||
Ok(pfd)
|
||||
}
|
||||
}
|
||||
|
||||
impl RelayDriver for PiFaceDriver {
|
||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError> {
|
||||
if self.get_high(value) {
|
||||
self.pfd_pin.set_high().map_err(PiFaceDigitalError::from)?;
|
||||
} else {
|
||||
self.pfd_pin.set_low().map_err(PiFaceDigitalError::from)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pin(&self) -> u8 {
|
||||
self.pfd_pin.get_pin_number()
|
||||
}
|
||||
|
||||
fn get_inverted(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use actix_web::http::StatusCode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApiError {
|
||||
ProtectedSchedule,
|
||||
}
|
||||
|
||||
impl ApiError {
|
||||
pub fn get_code(&self) -> StatusCode {
|
||||
match self {
|
||||
ApiError::ProtectedSchedule => StatusCode::FORBIDDEN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ApiError> for String {
|
||||
fn from(err: &ApiError) -> Self {
|
||||
match err {
|
||||
ApiError::ProtectedSchedule => String::from("the targeted schedule is protected"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
use actix_web::http::StatusCode;
|
||||
use actix_web::HttpResponse;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Serialize, Serializer};
|
||||
use sqlx::migrate::MigrateError;
|
||||
use sqlx::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DatabaseError {
|
||||
DeleteError,
|
||||
InsertError,
|
||||
InsertGetError,
|
||||
NotFound,
|
||||
Protected,
|
||||
EmptyDataInsert,
|
||||
UpdateError,
|
||||
UpdateGetError,
|
||||
MigrationError(MigrateError),
|
||||
Unknown(Error),
|
||||
}
|
||||
|
||||
impl DatabaseError {
|
||||
pub fn get_code(&self) -> StatusCode {
|
||||
match self {
|
||||
DatabaseError::NotFound => StatusCode::NOT_FOUND,
|
||||
DatabaseError::Protected => StatusCode::FORBIDDEN,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for DatabaseError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut s = serializer.serialize_struct("error", 3)?;
|
||||
s.serialize_field("type", "database-error")?;
|
||||
s.serialize_field("code", &self.get_code().as_u16())?;
|
||||
s.serialize_field("description", &String::from(self))?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&DatabaseError> for String {
|
||||
fn from(err: &DatabaseError) -> Self {
|
||||
String::from(match err {
|
||||
DatabaseError::InsertError => "error on inserting into database",
|
||||
DatabaseError::InsertGetError => {
|
||||
"error on retrieving new entry from database (your entry was saved)"
|
||||
}
|
||||
DatabaseError::NotFound => "model was not found in database",
|
||||
DatabaseError::DeleteError => "error on deleting from database",
|
||||
DatabaseError::Protected => "model is protected",
|
||||
DatabaseError::UpdateError => "error on updating the model",
|
||||
DatabaseError::UpdateGetError => {
|
||||
"error on retrieving updated model from database (your entry was saved)"
|
||||
}
|
||||
DatabaseError::MigrationError(_) => "error on running migrations",
|
||||
DatabaseError::Unknown(_) => "unknown error",
|
||||
DatabaseError::EmptyDataInsert => "tried to insert empty data",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DatabaseError> for HttpResponse {
|
||||
fn from(err: DatabaseError) -> Self {
|
||||
HttpResponse::build(err.get_code()).json(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for DatabaseError {
|
||||
fn from(value: Error) -> Self {
|
||||
match value {
|
||||
Error::RowNotFound => DatabaseError::NotFound,
|
||||
_ => DatabaseError::Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MigrateError> for DatabaseError {
|
||||
fn from(value: MigrateError) -> Self {
|
||||
Self::MigrationError(value)
|
||||
}
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::io::ErrorKind;
|
||||
|
||||
use actix::MailboxError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::HttpResponse;
|
||||
use config::ConfigError;
|
||||
use rppal::gpio;
|
||||
use rppal_mcp23s17::Mcp23s17Error;
|
||||
use rppal_pfd::PiFaceDigitalError;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::errors::{ApiError, DatabaseError};
|
||||
use crate::types::EmgauwaUid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EmgauwaError {
|
||||
Api(ApiError),
|
||||
Uid(uuid::Error),
|
||||
Serialization(serde_json::Error),
|
||||
Database(DatabaseError),
|
||||
Other(String),
|
||||
Internal(String),
|
||||
Connection(EmgauwaUid),
|
||||
Hardware(String),
|
||||
}
|
||||
|
||||
impl EmgauwaError {
|
||||
fn get_code(&self) -> StatusCode {
|
||||
match self {
|
||||
EmgauwaError::Api(err) => err.get_code(),
|
||||
EmgauwaError::Serialization(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EmgauwaError::Database(err) => err.get_code(),
|
||||
EmgauwaError::Uid(_) => StatusCode::BAD_REQUEST,
|
||||
EmgauwaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EmgauwaError::Connection(_) => StatusCode::GATEWAY_TIMEOUT,
|
||||
EmgauwaError::Other(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EmgauwaError::Hardware(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EmgauwaError> for String {
|
||||
fn from(err: &EmgauwaError) -> Self {
|
||||
match err {
|
||||
EmgauwaError::Api(err) => String::from(err),
|
||||
EmgauwaError::Serialization(_) => String::from("error during (de-)serialization"),
|
||||
EmgauwaError::Database(err) => String::from(err),
|
||||
EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
|
||||
EmgauwaError::Internal(_) => String::from("internal error"),
|
||||
EmgauwaError::Connection(_) => String::from("the target controller is not connected"),
|
||||
EmgauwaError::Other(err) => format!("other error: {}", err),
|
||||
EmgauwaError::Hardware(err) => format!("hardware error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ApiError> for EmgauwaError {
|
||||
fn from(value: ApiError) -> Self {
|
||||
EmgauwaError::Api(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DatabaseError> for EmgauwaError {
|
||||
fn from(value: DatabaseError) -> Self {
|
||||
EmgauwaError::Database(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for EmgauwaError {
|
||||
fn from(value: serde_json::Error) -> Self {
|
||||
EmgauwaError::Serialization(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for EmgauwaError {
|
||||
fn from(value: sqlx::Error) -> Self {
|
||||
EmgauwaError::Database(DatabaseError::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<uuid::Error> for EmgauwaError {
|
||||
fn from(value: uuid::Error) -> Self {
|
||||
EmgauwaError::Uid(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MailboxError> for EmgauwaError {
|
||||
fn from(value: MailboxError) -> Self {
|
||||
EmgauwaError::Internal(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigError> for EmgauwaError {
|
||||
fn from(value: ConfigError) -> Self {
|
||||
Self::Other(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gpio::Error> for EmgauwaError {
|
||||
fn from(value: gpio::Error) -> Self {
|
||||
Self::Hardware(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PiFaceDigitalError> for EmgauwaError {
|
||||
fn from(value: PiFaceDigitalError) -> Self {
|
||||
match value {
|
||||
PiFaceDigitalError::Mcp23s17Error { source } => match source {
|
||||
Mcp23s17Error::SpiError { source } => Self::Hardware(source.to_string()),
|
||||
_ => Self::Hardware(source.to_string()),
|
||||
},
|
||||
PiFaceDigitalError::GpioError { source } => Self::Hardware(source.to_string()),
|
||||
_ => Self::Hardware(value.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EmgauwaError> for HttpResponse {
|
||||
fn from(err: &EmgauwaError) -> Self {
|
||||
HttpResponse::build(err.get_code()).json(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for EmgauwaError {}
|
||||
|
||||
impl From<EmgauwaError> for std::io::Error {
|
||||
fn from(value: EmgauwaError) -> Self {
|
||||
std::io::Error::new(ErrorKind::Other, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for EmgauwaError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut s = serializer.serialize_struct("error", 2)?;
|
||||
s.serialize_field("code", &self.get_code().as_u16())?;
|
||||
s.serialize_field("description", &String::from(self))?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EmgauwaError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}: {}", self.get_code(), String::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl actix_web::error::ResponseError for EmgauwaError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
self.get_code()
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::from(self)
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
mod api_error;
|
||||
mod database_error;
|
||||
mod emgauwa_error;
|
||||
|
||||
pub use api_error::ApiError;
|
||||
pub use database_error::DatabaseError;
|
||||
pub use emgauwa_error::EmgauwaError;
|
|
@ -1,8 +0,0 @@
|
|||
pub mod constants;
|
||||
pub mod db;
|
||||
pub mod drivers;
|
||||
pub mod errors;
|
||||
pub mod models;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
pub mod utils;
|
|
@ -1,86 +0,0 @@
|
|||
use std::time::Instant;
|
||||
|
||||
use actix::MessageResponse;
|
||||
use chrono::NaiveTime;
|
||||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::DbController;
|
||||
use crate::errors::{DatabaseError, EmgauwaError};
|
||||
use crate::models::{convert_db_list_cache, FromDbModel, Relay};
|
||||
use crate::types::RelayStates;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
||||
pub struct Controller {
|
||||
#[serde(flatten)]
|
||||
pub c: DbController,
|
||||
pub relays: Vec<Relay>,
|
||||
}
|
||||
|
||||
impl FromDbModel for Controller {
|
||||
type DbModel = DbController;
|
||||
type DbModelCache = Vec<Relay>;
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let relays_db = block_on(db_model.get_relays(conn))?;
|
||||
let cache = convert_db_list_cache(conn, relays_db, db_model.clone())?;
|
||||
Self::from_db_model_cache(conn, db_model, cache)
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
_conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
Ok(Controller {
|
||||
c: db_model,
|
||||
relays: cache,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
||||
self.c = block_on(self.c.reload(conn))?;
|
||||
for relay in &mut self.relays {
|
||||
relay.reload(conn)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_relay_states(&mut self, relay_states: &RelayStates) {
|
||||
self.relays
|
||||
.iter_mut()
|
||||
.zip(relay_states.iter())
|
||||
.for_each(|(relay, is_on)| {
|
||||
relay.is_on = *is_on;
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_relay_states(&self) -> RelayStates {
|
||||
self.relays.iter().map(|r| r.is_on).collect()
|
||||
}
|
||||
|
||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||
self.relays
|
||||
.iter()
|
||||
.filter_map(|r| r.active_schedule.get_next_time(now))
|
||||
.min()
|
||||
}
|
||||
|
||||
pub fn relay_pulse(&mut self, relay_num: i64, until: Instant) -> Result<(), EmgauwaError> {
|
||||
let relay = self
|
||||
.relays
|
||||
.iter_mut()
|
||||
.find(|r| r.r.number == relay_num)
|
||||
.ok_or(EmgauwaError::Other(String::from("Relay not found")))?;
|
||||
|
||||
relay.pulsing = Some(until);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::DbMacro;
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::models::{convert_db_list, FromDbModel, MacroAction};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Macro {
|
||||
#[serde(flatten)]
|
||||
pub m: DbMacro,
|
||||
pub actions: Vec<MacroAction>,
|
||||
}
|
||||
|
||||
|
||||
impl FromDbModel for Macro {
|
||||
type DbModel = DbMacro;
|
||||
type DbModelCache = ();
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
Self::from_db_model_cache(conn, db_model, ())
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
_cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let actions_db = block_on(db_model.get_actions(conn))?;
|
||||
let actions: Vec<MacroAction> = convert_db_list(conn, actions_db)?;
|
||||
|
||||
Ok(Macro {
|
||||
m: db_model,
|
||||
actions,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbJunctionRelaySchedule, DbMacroAction};
|
||||
use crate::errors::{DatabaseError, EmgauwaError};
|
||||
use crate::models::{FromDbModel, Relay, Schedule};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct MacroAction {
|
||||
pub schedule: Schedule,
|
||||
pub relay: Relay,
|
||||
pub weekday: i64,
|
||||
}
|
||||
|
||||
|
||||
impl FromDbModel for MacroAction {
|
||||
type DbModel = DbMacroAction;
|
||||
type DbModelCache = ();
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
Self::from_db_model_cache(conn, db_model, ())
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
_cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let schedule_db = block_on(db_model.get_schedule(conn))?;
|
||||
let schedule = Schedule::from_db_model(conn, schedule_db)?;
|
||||
|
||||
let relay_db = block_on(db_model.get_relay(conn))?;
|
||||
let relay = Relay::from_db_model(conn, relay_db)?;
|
||||
|
||||
let weekday = db_model.weekday;
|
||||
|
||||
Ok(MacroAction {
|
||||
schedule,
|
||||
relay,
|
||||
weekday,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MacroAction {
|
||||
pub async fn execute(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
||||
DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule.s, self.weekday)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
mod controller;
|
||||
mod r#macro;
|
||||
mod macro_action;
|
||||
mod relay;
|
||||
mod schedule;
|
||||
mod tag;
|
||||
|
||||
pub use controller::Controller;
|
||||
pub use macro_action::MacroAction;
|
||||
pub use r#macro::Macro;
|
||||
pub use relay::Relay;
|
||||
pub use schedule::Schedule;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
pub use tag::Tag;
|
||||
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
pub trait FromDbModel {
|
||||
type DbModel: Clone;
|
||||
type DbModelCache: Clone;
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn from_db_model_cache(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
fn convert_db_list_generic<T: FromDbModel>(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_models: Vec<T::DbModel>,
|
||||
cache: Option<T::DbModelCache>,
|
||||
) -> Result<Vec<T>, DatabaseError> {
|
||||
let mut result: Vec<T> = Vec::new();
|
||||
for db_model in db_models {
|
||||
let new = match &cache {
|
||||
Some(c) => T::from_db_model_cache(conn, db_model, c.clone()),
|
||||
None => T::from_db_model(conn, db_model),
|
||||
}?;
|
||||
result.push(new);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn convert_db_list<T: FromDbModel>(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_models: Vec<T::DbModel>,
|
||||
) -> Result<Vec<T>, DatabaseError> {
|
||||
convert_db_list_generic(conn, db_models, None)
|
||||
}
|
||||
|
||||
pub fn convert_db_list_cache<T: FromDbModel>(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_models: Vec<T::DbModel>,
|
||||
cache: T::DbModelCache,
|
||||
) -> Result<Vec<T>, DatabaseError> {
|
||||
convert_db_list_generic(conn, db_models, Some(cache))
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
use std::time::Instant;
|
||||
|
||||
use chrono::NaiveTime;
|
||||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::models::FromDbModel;
|
||||
use crate::types::EmgauwaUid;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Relay {
|
||||
#[serde(flatten)]
|
||||
pub r: DbRelay,
|
||||
pub controller: DbController,
|
||||
pub controller_id: EmgauwaUid,
|
||||
pub schedules: Vec<DbSchedule>,
|
||||
pub active_schedule: DbSchedule,
|
||||
pub is_on: Option<bool>,
|
||||
pub tags: Vec<String>,
|
||||
|
||||
// for internal use only.
|
||||
#[serde(skip)]
|
||||
pub pulsing: Option<Instant>,
|
||||
}
|
||||
|
||||
|
||||
impl FromDbModel for Relay {
|
||||
type DbModel = DbRelay;
|
||||
type DbModelCache = DbController;
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let cache = block_on(db_model.get_controller(conn))?;
|
||||
Self::from_db_model_cache(conn, db_model, cache)
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let tags = block_on(db_model.get_tags(conn))?;
|
||||
let controller_id = cache.uid.clone();
|
||||
|
||||
let schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &db_model))?;
|
||||
let active_schedule = block_on(db_model.get_active_schedule(conn))?;
|
||||
|
||||
let is_on = None;
|
||||
|
||||
Ok(Relay {
|
||||
r: db_model,
|
||||
controller: cache,
|
||||
controller_id,
|
||||
schedules,
|
||||
active_schedule,
|
||||
is_on,
|
||||
tags,
|
||||
pulsing: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Relay {
|
||||
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||
self.r = block_on(self.r.reload(conn))?;
|
||||
self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?;
|
||||
self.reload_active_schedule(conn)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reload_active_schedule(
|
||||
&mut self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
self.active_schedule = block_on(self.r.get_active_schedule(conn))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
||||
self.active_schedule.is_on(now)
|
||||
}
|
||||
|
||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||
self.active_schedule.get_next_time(now)
|
||||
}
|
||||
|
||||
pub fn check_pulsing(&mut self, now: &Instant) -> Option<Instant> {
|
||||
match self.pulsing {
|
||||
Some(dur_instant) => {
|
||||
if dur_instant.lt(now) {
|
||||
self.pulsing = None;
|
||||
None
|
||||
} else {
|
||||
Some(dur_instant)
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::DbSchedule;
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::models::FromDbModel;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Schedule {
|
||||
#[serde(flatten)]
|
||||
pub s: DbSchedule,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl FromDbModel for Schedule {
|
||||
type DbModel = DbSchedule;
|
||||
type DbModelCache = Vec<String>;
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let cache = block_on(db_model.get_tags(conn))?;
|
||||
Self::from_db_model_cache(conn, db_model, cache)
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
_conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let schedule = db_model.clone();
|
||||
|
||||
Ok(Schedule {
|
||||
s: schedule,
|
||||
tags: cache,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
use actix::MessageResponse;
|
||||
use futures::executor::block_on;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbRelay, DbSchedule, DbTag};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::models::{convert_db_list, FromDbModel, Relay, Schedule};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
||||
pub struct Tag {
|
||||
pub tag: String,
|
||||
pub relays: Vec<Relay>,
|
||||
pub schedules: Vec<Schedule>,
|
||||
}
|
||||
|
||||
impl FromDbModel for Tag {
|
||||
type DbModel = DbTag;
|
||||
type DbModelCache = (Vec<Relay>, Vec<Schedule>);
|
||||
|
||||
fn from_db_model(
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let db_schedules = block_on(DbSchedule::get_by_tag(conn, &db_model))?;
|
||||
let schedules: Vec<Schedule> = convert_db_list(conn, db_schedules)?;
|
||||
|
||||
let db_relays = block_on(DbRelay::get_by_tag(conn, &db_model))?;
|
||||
let relays: Vec<Relay> = convert_db_list(conn, db_relays)?;
|
||||
|
||||
let cache = (relays, schedules);
|
||||
Self::from_db_model_cache(conn, db_model, cache)
|
||||
}
|
||||
|
||||
fn from_db_model_cache(
|
||||
_conn: &mut PoolConnection<Sqlite>,
|
||||
db_model: Self::DbModel,
|
||||
cache: Self::DbModelCache,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
let tag = db_model.tag.clone();
|
||||
let (relays, schedules) = cache;
|
||||
Ok(Tag {
|
||||
tag,
|
||||
relays,
|
||||
schedules,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
use serde_derive::Deserialize;
|
||||
|
||||
use crate::constants;
|
||||
use crate::errors::EmgauwaError;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
#[allow(unused)]
|
||||
pub struct Server {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
#[allow(unused)]
|
||||
pub struct Logging {
|
||||
pub level: String,
|
||||
pub file: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
#[allow(unused)]
|
||||
pub struct Permissions {
|
||||
pub user: String,
|
||||
pub group: String,
|
||||
}
|
||||
|
||||
impl Default for Server {
|
||||
fn default() -> Self {
|
||||
Server {
|
||||
host: String::from("127.0.0.1"),
|
||||
port: constants::DEFAULT_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Logging {
|
||||
fn default() -> Self {
|
||||
Logging {
|
||||
level: String::from("info"),
|
||||
file: String::from("stdout"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load<T>(config_name: &str, env_prefix: &str) -> Result<T, EmgauwaError>
|
||||
where
|
||||
for<'de> T: serde::Deserialize<'de>,
|
||||
{
|
||||
let etc_file =
|
||||
config::File::with_name(&format!("/etc/emgauwa/{}", config_name)).required(false);
|
||||
let local_file = config::File::with_name(&format!("./emgauwa-{}", config_name)).required(false);
|
||||
|
||||
config::Config::builder()
|
||||
.add_source(etc_file)
|
||||
.add_source(local_file)
|
||||
.add_source(
|
||||
config::Environment::with_prefix(&format!("EMGAUWA_{}", env_prefix))
|
||||
.prefix_separator("__")
|
||||
.separator("__"),
|
||||
)
|
||||
.build()?
|
||||
.try_deserialize::<T>()
|
||||
.map_err(EmgauwaError::from)
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use sqlx::database::HasArguments;
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
||||
use sqlx::{Decode, Encode, Sqlite, Type};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct EmgauwaUid(Uuid);
|
||||
|
||||
impl Default for EmgauwaUid {
|
||||
fn default() -> Self {
|
||||
Self(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EmgauwaUid {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", String::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for EmgauwaUid {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
String::from(self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for EmgauwaUid {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str())
|
||||
.map_err(|_| serde::de::Error::custom("invalid uid"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EmgauwaUid> for String {
|
||||
fn from(uid: &EmgauwaUid) -> String {
|
||||
uid.0.as_hyphenated().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Type<Sqlite> for EmgauwaUid {
|
||||
fn type_info() -> SqliteTypeInfo {
|
||||
<&[u8] as Type<Sqlite>>::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &SqliteTypeInfo) -> bool {
|
||||
<&[u8] as Type<Sqlite>>::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'q> Encode<'q, Sqlite> for EmgauwaUid {
|
||||
//noinspection DuplicatedCode
|
||||
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
|
||||
<Vec<u8> as Encode<Sqlite>>::encode(Vec::from(self), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> Decode<'r, Sqlite> for EmgauwaUid {
|
||||
//noinspection DuplicatedCode
|
||||
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
|
||||
Self::try_from(<&[u8] as Decode<Sqlite>>::decode(value)?).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EmgauwaUid> for Vec<u8> {
|
||||
fn from(uid: &EmgauwaUid) -> Vec<u8> {
|
||||
uid.0.as_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for EmgauwaUid {
|
||||
type Error = uuid::Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let uuid = Uuid::from_str(value)?;
|
||||
Ok(Self(uuid))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for EmgauwaUid {
|
||||
type Error = uuid::Error;
|
||||
|
||||
fn try_from(value: &[u8]) -> Result<EmgauwaUid, uuid::Error> {
|
||||
Ok(Self(Uuid::from_slice(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for EmgauwaUid {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self::try_from(value.as_slice()).expect("Failed to parse uid from database")
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
mod emgauwa_uid;
|
||||
mod request;
|
||||
mod schedule_uid;
|
||||
|
||||
use actix::Message;
|
||||
pub use emgauwa_uid::EmgauwaUid;
|
||||
pub use request::*;
|
||||
pub use schedule_uid::ScheduleUid;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::db::DbSchedule;
|
||||
use crate::errors::EmgauwaError;
|
||||
use crate::models::{Controller, Relay};
|
||||
|
||||
pub type Weekday = i64;
|
||||
|
||||
pub type RelayStates = Vec<Option<bool>>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Message)]
|
||||
#[rtype(result = "Result<(), EmgauwaError>")]
|
||||
pub enum ControllerWsAction {
|
||||
Register(Controller),
|
||||
Disconnect,
|
||||
Schedules(Vec<DbSchedule>),
|
||||
Relays(Vec<Relay>),
|
||||
Controller(Controller),
|
||||
RelayStates((EmgauwaUid, RelayStates)),
|
||||
RelayPulse((i64, Option<u32>)),
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
|
||||
use crate::db::{DbPeriods, DbSchedule};
|
||||
use crate::errors::DatabaseError;
|
||||
use crate::types::{EmgauwaUid, ScheduleUid};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestScheduleCreate {
|
||||
pub name: String,
|
||||
pub periods: DbPeriods,
|
||||
pub tags: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestScheduleUpdate {
|
||||
pub name: Option<String>,
|
||||
pub periods: Option<DbPeriods>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestRelayUpdate {
|
||||
pub name: Option<String>,
|
||||
pub active_schedule: Option<RequestScheduleId>,
|
||||
pub schedules: Option<Vec<RequestScheduleId>>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestRelayPulse {
|
||||
pub duration: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestScheduleId {
|
||||
pub id: ScheduleUid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestControllerUpdate {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestTagCreate {
|
||||
pub tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestMacroActionRelay {
|
||||
pub number: i64,
|
||||
pub controller_id: EmgauwaUid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestMacroActionSchedule {
|
||||
pub id: ScheduleUid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestMacroAction {
|
||||
pub weekday: i64,
|
||||
pub relay: RequestMacroActionRelay,
|
||||
pub schedule: RequestMacroActionSchedule,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestMacroCreate {
|
||||
pub name: String,
|
||||
pub actions: Vec<RequestMacroAction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestMacroUpdate {
|
||||
pub name: Option<String>,
|
||||
pub actions: Option<Vec<RequestMacroAction>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RequestMacroExecute {
|
||||
pub weekday: Option<i64>,
|
||||
}
|
||||
|
||||
impl RequestScheduleId {
|
||||
pub async fn get_schedule(
|
||||
&self,
|
||||
conn: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<DbSchedule, DatabaseError> {
|
||||
DbSchedule::get_by_uid(conn, &self.id)
|
||||
.await?
|
||||
.ok_or(DatabaseError::NotFound)
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use sqlx::database::HasArguments;
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
|
||||
use sqlx::{Decode, Encode, Sqlite, Type};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ScheduleUid {
|
||||
Off,
|
||||
On,
|
||||
Any(Uuid),
|
||||
}
|
||||
|
||||
impl ScheduleUid {
|
||||
const OFF_STR: &'static str = "off";
|
||||
const OFF_U128: u128 = 0;
|
||||
const OFF_U8: u8 = 0;
|
||||
const ON_STR: &'static str = "on";
|
||||
const ON_U128: u128 = 1;
|
||||
const ON_U8: u8 = 1;
|
||||
}
|
||||
|
||||
impl Default for ScheduleUid {
|
||||
fn default() -> Self {
|
||||
Self::Any(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ScheduleUid {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Off => Self::OFF_STR.fmt(f),
|
||||
Self::On => Self::ON_STR.fmt(f),
|
||||
Self::Any(value) => value.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ScheduleUid {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Off, Self::Off) => true,
|
||||
(Self::On, Self::On) => true,
|
||||
(Self::Any(my_uuid), Self::Any(other_uuid)) => my_uuid == other_uuid,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type<Sqlite> for ScheduleUid {
|
||||
fn type_info() -> SqliteTypeInfo {
|
||||
<&[u8] as Type<Sqlite>>::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &SqliteTypeInfo) -> bool {
|
||||
<&[u8] as Type<Sqlite>>::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'q> Encode<'q, Sqlite> for ScheduleUid {
|
||||
//noinspection DuplicatedCode
|
||||
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
|
||||
<Vec<u8> as Encode<Sqlite>>::encode(Vec::from(self), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> Decode<'r, Sqlite> for ScheduleUid {
|
||||
//noinspection DuplicatedCode
|
||||
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
|
||||
Self::try_from(<&[u8] as Decode<Sqlite>>::decode(value)?).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ScheduleUid {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
String::from(self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ScheduleUid {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str())
|
||||
.map_err(|_| serde::de::Error::custom("invalid schedule uid"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for ScheduleUid {
|
||||
fn from(uid: Uuid) -> Self {
|
||||
match uid.as_u128() {
|
||||
Self::OFF_U128 => Self::Off,
|
||||
Self::ON_U128 => Self::On,
|
||||
_ => Self::Any(uid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for ScheduleUid {
|
||||
type Error = uuid::Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Self::OFF_STR => Ok(Self::Off),
|
||||
Self::ON_STR => Ok(Self::On),
|
||||
any => match Uuid::from_str(any) {
|
||||
Ok(uuid) => Ok(Self::Any(uuid)),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ScheduleUid> for Uuid {
|
||||
fn from(uid: &ScheduleUid) -> Uuid {
|
||||
match uid {
|
||||
ScheduleUid::Off => Uuid::from_u128(ScheduleUid::OFF_U128),
|
||||
ScheduleUid::On => Uuid::from_u128(ScheduleUid::ON_U128),
|
||||
ScheduleUid::Any(value) => *value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ScheduleUid> for String {
|
||||
fn from(uid: &ScheduleUid) -> String {
|
||||
match uid {
|
||||
ScheduleUid::Off => String::from(ScheduleUid::OFF_STR),
|
||||
ScheduleUid::On => String::from(ScheduleUid::ON_STR),
|
||||
ScheduleUid::Any(value) => value.as_hyphenated().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ScheduleUid> for Vec<u8> {
|
||||
fn from(uid: &ScheduleUid) -> Vec<u8> {
|
||||
match uid {
|
||||
ScheduleUid::Off => vec![ScheduleUid::OFF_U8],
|
||||
ScheduleUid::On => vec![ScheduleUid::ON_U8],
|
||||
ScheduleUid::Any(value) => value.as_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for ScheduleUid {
|
||||
type Error = uuid::Error;
|
||||
|
||||
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||
let result = match value {
|
||||
[Self::OFF_U8] => Self::Off,
|
||||
[Self::ON_U8] => Self::On,
|
||||
value_bytes => Self::Any(Uuid::from_slice(value_bytes)?),
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ScheduleUid {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self::try_from(value.as_slice()).expect("Failed to parse schedule uid from database")
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue