db

package
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2024 License: GPL-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package db integrates with generic databases, so far it doesn't do much, but it's supposed to do more.

Package db provides convenience-functions for mapping Go-types to a database. It does not address a few well-known issues with database code and is not particularly fast, but is intended to make 90% of the database-work trivial, while not attempting to solve the last 10% at all.

The convenience-functions work well if you are not regularly handling updates to the same content in parallel, and you do not depend on extreme performance for SELECT. If you are unsure if this is the case, I'm willing to bet five kilograms of bananas that it's not. You'd know if it was.

You can always just use the db/DB handle directly, which is provided intentionally.

db tries to automatically map a type to a row, both on insert/update and select. It does this using introspection and the official database/sql package's interfaces for scanning results and packing data types. So if your data types implement sql.Scanner and sql/driver.Value, you can use them directly with 0 extra boiler-plate.

To use it, you need a struct datatype with at least some exported fields that map to a database table. If your field names don't match the column name, you can tag the struct fields with `column:"alternatename"`. If you wish to have this package ignore the field entirely (e.g.: it's exported, but doesn't exist at all in the database), tag it with `column:"-"`.

Index

Constants

This section is empty.

Variables

View Source
var DB *sql.DB

DB is the main database handle used throughout the API

Functions

func Connect

func Connect() error

Connect sets up the database connection, using the configured ConnectionString, and ensures it is working.

func Delete added in v0.0.4

func Delete(table string, searcher ...interface{}) (gondulapi.Report, error)

Delete will delete the element, and will also delete duplicates.

func Exists added in v0.0.4

func Exists(table string, searcher ...interface{}) (found bool, err error)

Exists checks if a row where haystack matches the needle exists on the given table. It returns found=true if it does. It returns found=false if it doesn't find it - including if an error occurs (which will also be returned).

func Get added in v0.0.6

func Get(item interface{}, table string, searcher ...interface{}) (gondulapi.Report, error)

Get is a convenience-wrapper for Select that return suitable gondulapi-errors if the needle is the Zero-value, if the database-query fails or if the item isn't found.

It is provided so callers can implement receiver.Getter by simply calling this to get reasonable default-behavior.

func Insert added in v0.0.2

func Insert(d interface{}, table string) (gondulapi.Report, error)

Insert adds the object to the table specified. It only provides the non-nil-pointer objects as fields, so it is up to the caller and the database schema to enforce default values. It also does not check if an object already exists, so it will happily make duplicates - your database schema should prevent that, and calling code should check if that is not the desired behavior.

func Ping added in v0.0.7

func Ping() error

Ping is a wrapper for DB.Ping: it checks that the database is alive. It's provided to add standard gondulapi-logging and error-types that can be exposed to users.

func Select added in v0.0.4

func Select(d interface{}, table string, searcher ...interface{}) (report gondulapi.Report, err error)

Select populates the provided interface(should be a pointer to a struct) by performing a simple select on the table, matching haystack with needle. E.g: select (elements of d) from table where haystack = needle;

It is not particularly fast, and uses reflection. It is well suited for simple objects, but if performance is important, roll your own.

It only populates exported values, and will use the "column" tag as an alternate name if needed. The data fields are fetched with sql.Scan(), so the data types need to implement sql.Scan() somehow.

If the element is found, "found" is returned as true. If the element is found, but fails to scan, found is returned as true, but err is is non-nil. If an error occurred before the query is executed, or with the query itself (e.g.: bad table, or database issues), found is returned as false, and error is set. As such: if found is true, you can trust it, if it is false, you can only be absolutely sure the element doesn't exist if err is false.

It needs to do two passes (might be a better way if someone better at the inner workings of Go reflection than me steps up). The first pass iterates over the fields of d, preparing both the query and allocating zero-values of the relevant objects. After this, the query is executed and the values are stored on the temporary values. The last pass stores

func SelectMany added in v0.0.6

func SelectMany(d interface{}, table string, searcher ...interface{}) (report gondulapi.Report, reterr error)

SelectMany selects multiple rows from the table, populating the slice pointed to by d. It must, as such, be called with a pointer to a slice as the d-value (it checks).

It returns the data in d, with an error if something failed, obviously. It's not particularly fast, or bullet proof, but:

1. It handles the needle safely, e.g., it lets the sql driver do the escaping.

2. The haystack and table is NOT safe.

3. It uses database/sql.Scan, so as long as your elements implement that, it will Just Work.

It works by first determining the base object/type to fetch by digging into d with reflection. Once that is established, it iterates over the discovered base-structure and does two things: creates the list of columns to SELECT, and creates a reflect.Value for each column to store the result. Once this loop is done, it executes the query, then iterates over the replies, storing them in new base elements. At the very end, the *d is overwritten with the new slice.

func Update added in v0.0.2

func Update(d interface{}, table string, searcher ...interface{}) (gondulapi.Report, error)

Update attempts to update the object in the database, using the provided string and matching the haystack with the needle. It skips fields that are nil-pointers.

func Upsert added in v0.0.4

func Upsert(d interface{}, table string, searcher ...interface{}) (gondulapi.Report, error)

Upsert makes database-people cringe by first checking if an element exists, if it does, it is updated. If it doesn't, it is inserted. This is NOT a transaction-safe implementation, which means: use at your own peril. The biggest risks are:

1. If the element is created by a third party during Upsert, the update will fail because we will issue an INSERT instead of UPDATE. This will generate an error, so can be handled by the frontend.

2. If an element is deleted by a third party during Upsert, Upsert will still attempt an UPDATE, which will fail silently (for now). This can be handled by a front-end doing a double-check, or by just assuming it doesn't happen often enough to be worth fixing.

Types

type Selector added in v0.0.8

type Selector struct {
	Haystack string
	Operator string
	Needle   interface{}
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL