fisch/db.go
2025-03-18 21:19:18 +01:00

320 lines
6.2 KiB
Go
Executable file

package main
import (
"database/sql"
"fmt"
"os"
"strings"
_ "github.com/mattn/go-sqlite3"
)
func ParseSearchString(search string) (out []any) {
for strings.Contains(search, " ") {
search = strings.ReplaceAll(search, " ", " ")
}
searchStrings := strings.Split(search, " ")
out = make([]any, len(searchStrings))
for i, s := range searchStrings {
out[i] = "%" + s + "%"
}
return out
}
type Connection struct {
DB *sql.DB
Error error
}
func Connect() *Connection {
db, err := sql.Open("sqlite3", "./data/fisch.db")
if err != nil {
return &Connection{nil, err}
}
return &Connection{db, nil}
}
func (conn *Connection) InitDatabase() error {
sql, err := os.ReadFile("./data/database.sql")
if err != nil {
return err
}
_, err = conn.DB.Exec(string(sql))
return err
}
func (conn *Connection) SearchPart(search string) ([]*Part, error) {
parsed := ParseSearchString(search)
if len(parsed) == 0 || (len(parsed) == 1 && len(fmt.Sprintf("%v", parsed[0])) == 2) {
return []*Part{}, nil
}
if conn.Error != nil {
return nil, conn.Error
}
searchPattern := ""
for i := 0; i < len(parsed); i++ {
searchPattern += "tags LIKE ?"
if i < len(parsed)-1 {
searchPattern += " OR "
} else {
searchPattern += " "
}
}
rows, err := conn.DB.Query("select id, name, tags, location, container from parts where "+searchPattern, parsed...)
if err != nil {
return nil, err
}
parts := make([]*Part, 0)
for rows.Next() {
part := Part{}
var locationId sql.NullInt64
var containerId sql.NullInt64
err := rows.Scan(&part.Id, &part.Name, &part.Tags, &locationId, &containerId)
if err != nil {
return nil, err
}
var location *Location
if locationId.Valid {
location, err = conn.QueryLocation(locationId.Int64)
if err != nil {
return nil, err
}
}
var container *Container
if containerId.Valid {
container, err = conn.QueryContainer(containerId.Int64)
if err != nil {
return nil, err
}
}
part.Location = *location
part.Container = *container
part.Connection = conn
parts = append(parts, &part)
}
return parts, nil
}
func (conn *Connection) QueryLocations() ([]*Location, error) {
if conn.Error != nil {
return nil, conn.Error
}
rows, err := conn.DB.Query("select id, parent, name, description from locations")
if err != nil {
return nil, err
}
locations := make([]*Location, 0)
for rows.Next() {
location := Location{}
err := rows.Scan(&location.Id, &location.Parent, &location.Name, &location.Description)
if err != nil {
return nil, err
}
location.Connection = conn
locations = append(locations, &location)
}
return locations, nil
}
func (conn *Connection) QueryLocation(id int64) (*Location, error) {
if conn.Error != nil {
return nil, conn.Error
}
row := conn.DB.QueryRow("select parent, name, description from locations where id=?", id)
location := Location{}
location.Id = sql.NullInt64{id, true}
err := row.Scan(&location.Parent, &location.Name, &location.Description)
if err != nil {
return nil, err
}
location.Connection = conn
return &location, nil
}
func (conn *Connection) QueryLocationFullPath(lastChildId int64) (string, error) {
fullPath := ""
nextId := lastChildId
isEnd := false
for !isEnd {
location, err := conn.QueryLocation(nextId)
if err != nil {
return fullPath, err
}
if location.Name.Valid {
fullPath = location.Name.String + "/" + fullPath
} else {
fullPath = fmt.Sprintf("%d/", nextId) + fullPath
}
isEnd = !location.Parent.Valid
if !isEnd {
nextId = location.Parent.Int64
}
}
if fullPath[len(fullPath)-1] == '/' {
fullPath = fullPath[0 : len(fullPath)-1]
}
return "/" + fullPath, nil
}
func (conn *Connection) QueryContainers() ([]*Container, error) {
if conn.Error != nil {
return nil, conn.Error
}
rows, err := conn.DB.Query("select id, name from containers")
if err != nil {
return nil, err
}
containers := make([]*Container, 0)
for rows.Next() {
container := Container{}
err := rows.Scan(&container.Id, &container.Name)
if err != nil {
return nil, err
}
containers = append(containers, &container)
}
return containers, nil
}
func (conn *Connection) QueryContainer(id int64) (*Container, error) {
if conn.Error != nil {
return nil, conn.Error
}
row := conn.DB.QueryRow("select name from containers where id=?", id)
container := Container{}
container.Id = sql.NullInt64{id, true}
err := row.Scan(&container.Name)
if err != nil {
return nil, err
}
return &container, nil
}
func (conn *Connection) QueryParts() ([]*Part, error) {
if conn.Error != nil {
return nil, conn.Error
}
rows, err := conn.DB.Query("select id, name, tags, location, container from parts")
if err != nil {
return nil, err
}
parts := make([]*Part, 0)
for rows.Next() {
part := Part{}
var locationId sql.NullInt64
var containerId sql.NullInt64
err := rows.Scan(&part.Id, &part.Name, &part.Tags, &locationId, &containerId)
if err != nil {
return nil, err
}
var location *Location
if locationId.Valid {
location, err = conn.QueryLocation(locationId.Int64)
if err != nil {
return nil, err
}
}
var container *Container
if containerId.Valid {
container, err = conn.QueryContainer(containerId.Int64)
if err != nil {
return nil, err
}
}
part.Location = *location
part.Container = *container
part.Connection = conn
parts = append(parts, &part)
}
return parts, nil
}
func (conn *Connection) QueryPart(id int64) (*Part, error) {
if conn.Error != nil {
return nil, conn.Error
}
row := conn.DB.QueryRow("select name, tags, location, container from parts where id=?", id)
part := Part{}
part.Id = sql.NullInt64{id, true}
var locationId sql.NullInt64
var containerId sql.NullInt64
err := row.Scan(&part.Name, &part.Tags, &locationId, &containerId)
if err != nil {
return nil, err
}
var location *Location
if locationId.Valid {
location, err = conn.QueryLocation(locationId.Int64)
if err != nil {
return nil, err
}
part.Location = *location
}
var container *Container
if containerId.Valid {
container, err = conn.QueryContainer(containerId.Int64)
if err != nil {
return nil, err
}
part.Container = *container
}
part.Connection = conn
return &part, nil
}