Initial commit
Connects to zwave-js, syncs all locks and codeslots with database, and records an event log. No support for updating code slots.
This commit is contained in:
commit
054008eb1f
20 changed files with 1165 additions and 0 deletions
31
db/db.go
Normal file
31
db/db.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
53
db/helpers.go
Normal file
53
db/helpers.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"embed"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
goose "github.com/pressly/goose/v3"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"git.janky.solutions/finn/lockserver/config"
|
||||
)
|
||||
|
||||
func Get() (*Queries, *sql.DB, error) {
|
||||
db, err := sql.Open("sqlite3", config.C.Database)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return New(db), db, nil
|
||||
}
|
||||
|
||||
//go:embed migrations
|
||||
var migrations embed.FS
|
||||
|
||||
func Migrate() error {
|
||||
logrus.WithField("dbfile", config.C.Database).Info("migrating database")
|
||||
|
||||
_, conn, err := Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
goose.SetBaseFS(migrations)
|
||||
|
||||
if err := goose.SetDialect("sqlite3"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := goose.Up(conn, "migrations"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NullString(s string) sql.NullString {
|
||||
return sql.NullString{
|
||||
Valid: s != "",
|
||||
String: s,
|
||||
}
|
||||
}
|
88
db/lock_code_slots.sql.go
Normal file
88
db/lock_code_slots.sql.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
// source: lock_code_slots.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const getLockCodeBySlot = `-- name: GetLockCodeBySlot :one
|
||||
SELECT id, lock, code, slot, name, enabled FROM lock_code_slots WHERE lock = ? AND slot = ?
|
||||
`
|
||||
|
||||
type GetLockCodeBySlotParams struct {
|
||||
Lock int64
|
||||
Slot int64
|
||||
}
|
||||
|
||||
func (q *Queries) GetLockCodeBySlot(ctx context.Context, arg GetLockCodeBySlotParams) (LockCodeSlot, error) {
|
||||
row := q.db.QueryRowContext(ctx, getLockCodeBySlot, arg.Lock, arg.Slot)
|
||||
var i LockCodeSlot
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Lock,
|
||||
&i.Code,
|
||||
&i.Slot,
|
||||
&i.Name,
|
||||
&i.Enabled,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLockCodes = `-- name: GetLockCodes :many
|
||||
SELECT id, lock, code, slot, name, enabled FROM lock_code_slots WHERE lock = ?
|
||||
`
|
||||
|
||||
func (q *Queries) GetLockCodes(ctx context.Context, lock int64) ([]LockCodeSlot, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getLockCodes, lock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []LockCodeSlot
|
||||
for rows.Next() {
|
||||
var i LockCodeSlot
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Lock,
|
||||
&i.Code,
|
||||
&i.Slot,
|
||||
&i.Name,
|
||||
&i.Enabled,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const upsertCodeSlot = `-- name: UpsertCodeSlot :exec
|
||||
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, "") ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled
|
||||
`
|
||||
|
||||
type UpsertCodeSlotParams struct {
|
||||
Lock int64
|
||||
Slot int64
|
||||
Code string
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func (q *Queries) UpsertCodeSlot(ctx context.Context, arg UpsertCodeSlotParams) error {
|
||||
_, err := q.db.ExecContext(ctx, upsertCodeSlot,
|
||||
arg.Lock,
|
||||
arg.Slot,
|
||||
arg.Code,
|
||||
arg.Enabled,
|
||||
)
|
||||
return err
|
||||
}
|
58
db/lock_log.sql.go
Normal file
58
db/lock_log.sql.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
// source: lock_log.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const addLogEntry = `-- name: AddLogEntry :exec
|
||||
INSERT INTO lock_log (lock, state, code) VALUES (?, ?, ?)
|
||||
`
|
||||
|
||||
type AddLogEntryParams struct {
|
||||
Lock int64
|
||||
State string
|
||||
Code sql.NullInt64
|
||||
}
|
||||
|
||||
func (q *Queries) AddLogEntry(ctx context.Context, arg AddLogEntryParams) error {
|
||||
_, err := q.db.ExecContext(ctx, addLogEntry, arg.Lock, arg.State, arg.Code)
|
||||
return err
|
||||
}
|
||||
|
||||
const getLogForLock = `-- name: GetLogForLock :many
|
||||
SELECT lock, timestamp, state, code FROM lock_log WHERE lock = ? ORDER BY timestamp DESC
|
||||
`
|
||||
|
||||
func (q *Queries) GetLogForLock(ctx context.Context, lock int64) ([]LockLog, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getLogForLock, lock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []LockLog
|
||||
for rows.Next() {
|
||||
var i LockLog
|
||||
if err := rows.Scan(
|
||||
&i.Lock,
|
||||
&i.Timestamp,
|
||||
&i.State,
|
||||
&i.Code,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
73
db/locks.sql.go
Normal file
73
db/locks.sql.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
// source: locks.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const createLock = `-- name: CreateLock :one
|
||||
INSERT INTO locks (zwave_device_id, name) VALUES (?, "") RETURNING id, name, zwave_device_id
|
||||
`
|
||||
|
||||
func (q *Queries) CreateLock(ctx context.Context, zwaveDeviceID int64) (Lock, error) {
|
||||
row := q.db.QueryRowContext(ctx, createLock, zwaveDeviceID)
|
||||
var i Lock
|
||||
err := row.Scan(&i.ID, &i.Name, &i.ZwaveDeviceID)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLockByDeviceID = `-- name: GetLockByDeviceID :one
|
||||
SELECT id, name, zwave_device_id FROM locks WHERE zwave_device_id = ?
|
||||
`
|
||||
|
||||
func (q *Queries) GetLockByDeviceID(ctx context.Context, zwaveDeviceID int64) (Lock, error) {
|
||||
row := q.db.QueryRowContext(ctx, getLockByDeviceID, zwaveDeviceID)
|
||||
var i Lock
|
||||
err := row.Scan(&i.ID, &i.Name, &i.ZwaveDeviceID)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLocks = `-- name: GetLocks :many
|
||||
SELECT id, name, zwave_device_id FROM locks
|
||||
`
|
||||
|
||||
func (q *Queries) GetLocks(ctx context.Context) ([]Lock, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getLocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Lock
|
||||
for rows.Next() {
|
||||
var i Lock
|
||||
if err := rows.Scan(&i.ID, &i.Name, &i.ZwaveDeviceID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateLockName = `-- name: UpdateLockName :exec
|
||||
UPDATE locks SET name = ? WHERE id = ?
|
||||
`
|
||||
|
||||
type UpdateLockNameParams struct {
|
||||
Name string
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateLockName(ctx context.Context, arg UpdateLockNameParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateLockName, arg.Name, arg.ID)
|
||||
return err
|
||||
}
|
35
db/migrations/1_init.sql
Normal file
35
db/migrations/1_init.sql
Normal file
|
@ -0,0 +1,35 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
CREATE TABLE locks (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
zwave_device_id INTEGER NOT NULL UNIQUE
|
||||
);
|
||||
|
||||
CREATE TABLE lock_code_slots (
|
||||
id INTEGER PRIMARY KEY,
|
||||
lock INTEGER NOT NULL REFERENCES locks(id),
|
||||
code TEXT NOT NULL,
|
||||
slot INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
enabled BOOLEAN NOT NULL DEFAULT 0,
|
||||
|
||||
UNIQUE (lock, slot)
|
||||
);
|
||||
|
||||
CREATE TABLE lock_log (
|
||||
lock INTEGER NOT NULL REFERENCES locks(id),
|
||||
timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
state TEXT NOT NULL,
|
||||
code INTEGER REFERENCES lock_code_slots(id)
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE lock_log;
|
||||
DROP TABLE lock_code_slots;
|
||||
DROP TABLE locks;
|
||||
-- +goose StatementEnd
|
32
db/models.go
Normal file
32
db/models.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Lock struct {
|
||||
ID int64
|
||||
Name string
|
||||
ZwaveDeviceID int64
|
||||
}
|
||||
|
||||
type LockCodeSlot struct {
|
||||
ID int64
|
||||
Lock int64
|
||||
Code string
|
||||
Slot int64
|
||||
Name string
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type LockLog struct {
|
||||
Lock int64
|
||||
Timestamp time.Time
|
||||
State string
|
||||
Code sql.NullInt64
|
||||
}
|
8
db/queries/lock_code_slots.sql
Normal file
8
db/queries/lock_code_slots.sql
Normal file
|
@ -0,0 +1,8 @@
|
|||
-- name: UpsertCodeSlot :exec
|
||||
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, "") ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled;
|
||||
|
||||
-- name: GetLockCodeBySlot :one
|
||||
SELECT * FROM lock_code_slots WHERE lock = ? AND slot = ?;
|
||||
|
||||
-- name: GetLockCodes :many
|
||||
SELECT * FROM lock_code_slots WHERE lock = ?;
|
5
db/queries/lock_log.sql
Normal file
5
db/queries/lock_log.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- name: AddLogEntry :exec
|
||||
INSERT INTO lock_log (lock, state, code) VALUES (?, ?, ?);
|
||||
|
||||
-- name: GetLogForLock :many
|
||||
SELECT * FROM lock_log WHERE lock = ? ORDER BY timestamp DESC;
|
11
db/queries/locks.sql
Normal file
11
db/queries/locks.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
-- name: CreateLock :one
|
||||
INSERT INTO locks (zwave_device_id, name) VALUES (?, "") RETURNING *;
|
||||
|
||||
-- name: GetLocks :many
|
||||
SELECT * FROM locks;
|
||||
|
||||
-- name: GetLockByDeviceID :one
|
||||
SELECT * FROM locks WHERE zwave_device_id = ?;
|
||||
|
||||
-- name: UpdateLockName :exec
|
||||
UPDATE locks SET name = ? WHERE id = ?;
|
Loading…
Add table
Add a link
Reference in a new issue