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:
Finn 2024-04-08 21:25:36 -07:00
commit 054008eb1f
20 changed files with 1165 additions and 0 deletions

31
db/db.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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
View 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
View 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 = ?;