yago

package module
v0.0.0-...-aa61c75 Latest Latest
Warning

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

Go to latest
Published: Nov 23, 2023 License: MIT Imports: 7 Imported by: 19

README

Yet Another Go ORM

Go Report Card

Yago is an attempt to create an ORM for Go.

Features

Goals/Key concepts

First goals are:

  • Do not hide the SQL, only wrap it with a thin layer allowing multiple dialects. This layer is 'qb', to which we contribute back.
  • Provide a low-cost abstraction on the schema, removing the need to know any actual column or table name when writting queries.
  • Have a 'record-level' API, which is very efficient at CRUD operations with plain structs, and is developer friendly.
  • Be backend agnotistic (as much as possible).

Long term goal is to also provide higher level ORM concepts like instances, session, unit-of-work... It will be based on the record-level API, which needs to be ironned first.

Try it out


go get -u github.com/orus-io/yago
go install github.com/orus-io/yago/cmd/yago

Define your model (for example in model.go):

package main

import (
	"github.com/orus-io/yago"
)

//go:generate yago --fmt

// Model gives easy access to various things
type Model struct {
	Meta *yago.Metadata

	Person      PersonModel
	PhoneNumber PhoneNumberModel
}

// NewModel initialize a model
func NewModel() *Model {
	meta := yago.NewMetadata()
	return &Model{
		Meta:        meta,
		Person:      NewPersonModel(meta),
		PhoneNumber: NewPhoneNumberModel(meta),
	}
}

// Base struct for all model structs
//yago:notable,autoattrs
type Base struct {
	ID        int64 `yago:"primary_key,auto_increment"`
	CreatedAt time.Time
	UpdatedAt *time.Time
}

// BeforeInsert callback
func (b *Base) BeforeInsert(db *yago.DB) {
	b.CreatedAt = time.Now()
}

// BeforeUpdate callback
func (b *Base) BeforeUpdate(db *yago.DB) {
	now := time.Now()
	b.UpdatedAt = &now
}

//yago:autoattrs
type Person struct {
	Base
	Name  string  `yago:"index"`
	Email *string `yago:"email_address,unique_index"`
}

// PhoneNumber is a phone number
//yago:autoattrs
type PhoneNumber struct {
	Base
	PersonID int64 `yago:"fk=Person ondelete cascade onupdate cascade"`
	Name     string
	Number   string
}

Let yago generate the code:

go generate

If you named the file "model.go", this command generated a new file "model_yago.go".

Now we can use the model to read/write things in the database:

package main

import (
	"fmt"

	"github.com/slicebit/qb"
	_ "github.com/mattn/go-sqlite3"

	"github.com/orus-io/yago"
)

func main() {
	model := NewModel()

	engine, err := qb.New("sqlite3", ":memory:")
	if err != nil {
		panic(err)
	}
	engine.SetDialect(qb.NewDialect("sqlite3"))

	if err := model.Meta.GetQbMetadata().CreateAll(engine); err != nil {
		panic(err)
	}

	db := yago.New(model.Meta, engine)

	p := NewPerson()
	p.Name = "Toto"
	db.Insert(p)
	fmt.Println("Inserted", p.Name, "got ID", p.ID)

	q = db.Query(model.Person)
	q = q.Where(model.Person.Name.Eq("Toto"))

	p = &Person{}
	if err := q.One(p); err != nil {
		panic(err)
	}

	var all []Person
	q = db.Query(model.Person)
	if err := q.All(&all); err != nil {
		panic(err)
	}
	fmt.Println("Loaded all persons:", all)
}

Current state:

  • Very experimental, APIs may brake without warning.
  • Current focus is on finding the right API.

Using this code in production is not recommended at this stage (although we are about to do it).

Feel free to come and discuss the design, propose patches...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrRecordNotFound is returned by Update, Delete, or One() if
	// not matching record were found
	ErrRecordNotFound = errors.New("yago.RecordNotFound")

	// ErrMultipleRecords is returned by Update or One() if too many
	// records matched the statement
	ErrMultipleRecords = errors.New("yago.MultipleRecords")

	// ErrInvalidColumns is returned by Scalar if the query returned
	// a number of columns != 1
	ErrInvalidColumns = errors.New("yago.InvalidColumns")
)

Functions

func StringListContains

func StringListContains(list []string, value string) bool

StringListContains returns true if the list containts the passed value, false otherwise

Types

type AfterDelete

type AfterDelete interface {
	AfterDelete(db *DB)
}

AfterDelete can be implemented by structs that need a after delete callback

type AfterInsert

type AfterInsert interface {
	AfterInsert(db *DB)
}

AfterInsert can be implemented by structs that need a after insert callback

type AfterUpdate

type AfterUpdate interface {
	AfterUpdate(db *DB)
}

AfterUpdate can be implemented by structs that need a after update callback

type BeforeDelete

type BeforeDelete interface {
	BeforeDelete(db *DB)
}

BeforeDelete can be implemented by structs that need a before delete callback

type BeforeInsert

type BeforeInsert interface {
	BeforeInsert(db *DB)
}

BeforeInsert can be implemented by structs that need a before insert callback

type BeforeUpdate

type BeforeUpdate interface {
	BeforeUpdate(db *DB)
}

BeforeUpdate can be implemented by structs that need a before update callback

type CallbackDef

type CallbackDef struct {
	// contains filtered or unexported fields
}

CallbackDef is a single callback definition

func AddCallbackSorted

func AddCallbackSorted(defs []CallbackDef, def CallbackDef) []CallbackDef

AddCallbackSorted insert a CallbackDef respecting the before/after args

func Callback

func Callback(name string, callback CallbackFunc) CallbackDef

Callback returns a new CallbackDef

func (CallbackDef) After

func (c CallbackDef) After(name string) CallbackDef

After which callback to be called

func (CallbackDef) Before

func (c CallbackDef) Before(name string) CallbackDef

Before which callback to be called

type CallbackFunc

type CallbackFunc func(db *DB, s MappedStruct)

CallbackFunc is the type of the callback functions

type CallbackList

type CallbackList struct {
	// contains filtered or unexported fields
}

CallbackList containts a list of same-type callbacks

func (*CallbackList) Add

func (c *CallbackList) Add(def CallbackDef)

Add a new callback

func (CallbackList) Call

func (c CallbackList) Call(db *DB, s MappedStruct)

Call runs all the callbacks with the passed arguments

func (*CallbackList) Get

func (c *CallbackList) Get(name string) *CallbackDef

Get a callback by name

func (*CallbackList) Remove

func (c *CallbackList) Remove(name string)

Remove a callback by name

type Callbacks

type Callbacks struct {
	BeforeInsert CallbackList
	AfterInsert  CallbackList
	BeforeUpdate CallbackList
	AfterUpdate  CallbackList
	BeforeDelete CallbackList
	AfterDelete  CallbackList
}

Callbacks containts a set of callbacks

var DefaultCallbacks Callbacks

DefaultCallbacks contains the default callbacks every database will be initialized with.

type DB

type DB struct {
	Metadata  *Metadata
	Engine    *qb.Engine
	Callbacks Callbacks
}

DB is a database handle with callbacks that links a Metadata and a qb.Engine

func New

func New(metadata *Metadata, engine *qb.Engine) *DB

New initialise a new DB

func (*DB) Begin

func (db *DB) Begin() (*Tx, error)

Begin start a new transaction

func (*DB) BeginContext

func (db *DB) BeginContext(ctx context.Context) (*Tx, error)

BeginContext start a new transaction

func (*DB) Close

func (db *DB) Close() error

Close closes the underlying db connection

func (*DB) Delete

func (db *DB) Delete(s MappedStruct) error

Delete a struct in the database

func (*DB) DeleteContext

func (db *DB) DeleteContext(ctx context.Context, s MappedStruct) error

Delete a struct in the database

func (DB) GetEngine

func (db DB) GetEngine() Engine

GetEngine returns the underlying engine

func (*DB) Insert

func (db *DB) Insert(s MappedStruct) error

Insert a struct in the database

func (*DB) InsertContext

func (db *DB) InsertContext(ctx context.Context, s MappedStruct) error

InsertContext a struct in the database

func (*DB) Query

func (db *DB) Query(mp MapperProvider) Query

Query returns a new Query for the struct

func (*DB) Update

func (db *DB) Update(s MappedStruct, fields ...string) error

Update the struct attributes in DB

func (*DB) UpdateContext

func (db *DB) UpdateContext(ctx context.Context, s MappedStruct, fields ...string) error

UpdateContext the struct attributes in DB

type Engine

type Engine interface {
	Exec(builder qb.Builder) (sql.Result, error)
	Query(builder qb.Builder) (*sql.Rows, error)
	QueryRow(builder qb.Builder) qb.Row

	ExecContext(ctx context.Context, builder qb.Builder) (sql.Result, error)
	QueryContext(ctx context.Context, builder qb.Builder) (*sql.Rows, error)
	QueryRowContext(ctx context.Context, builder qb.Builder) qb.Row
}

Engine is the common interface of qb.Engine and qb.Tx

type IDB

type IDB interface {
	Insert(MappedStruct) error
	Update(MappedStruct, ...string) error
	Delete(MappedStruct) error
	Query(MapperProvider) Query

	InsertContext(context.Context, MappedStruct) error
	UpdateContext(context.Context, MappedStruct, ...string) error
	DeleteContext(context.Context, MappedStruct) error

	GetEngine() Engine
}

IDB is the common interface of DB and Tx

type MappedStruct

type MappedStruct interface {
	StructType() reflect.Type
}

MappedStruct is implemented by all mapped structures

type Mapper

type Mapper interface {
	Name() string
	Table() *qb.TableElem
	StructType() reflect.Type
	FieldList() []qb.Clause

	AutoIncrementPKey() bool
	LoadAutoIncrementPKeyValue(instance MappedStruct, value int64)
	SQLValues(instance MappedStruct, fields ...string) map[string]interface{}
	PKey(instance MappedStruct) []interface{}
	PKeyClause(values []interface{}) qb.Clause

	ScanPKey(rows *sql.Rows, instance MappedStruct) error
	Scan(rows *sql.Rows, instance MappedStruct) error
}

Mapper links a mapped struct and table definition

type MapperProvider

type MapperProvider interface {
	GetMapper() Mapper
}

MapperProvider is implemented by any struct that can provide a single mapper

type MarshaledScalarField

type MarshaledScalarField struct {
	ScalarField
}

MarshaledScalarField A text marshaled scalar field

func NewMarshaledScalarField

func NewMarshaledScalarField(column qb.ColumnElem) MarshaledScalarField

NewMarshaledScalarField returns a new ScalarField

func (MarshaledScalarField) Eq

func (f MarshaledScalarField) Eq(value interface{}) qb.Clause

Eq returns a = clause

func (MarshaledScalarField) Gt

func (f MarshaledScalarField) Gt(value interface{}) qb.Clause

Gt returns a > clause

func (MarshaledScalarField) Gte

func (f MarshaledScalarField) Gte(value interface{}) qb.Clause

Gte returns a >= clause

func (MarshaledScalarField) In

func (f MarshaledScalarField) In(values ...interface{}) qb.Clause

In returns a IN clause

func (MarshaledScalarField) Lt

func (f MarshaledScalarField) Lt(value interface{}) qb.Clause

Lt returns a < clause

func (MarshaledScalarField) Lte

func (f MarshaledScalarField) Lte(value interface{}) qb.Clause

Lte returns a <= clause

func (MarshaledScalarField) NotEq

func (f MarshaledScalarField) NotEq(value interface{}) qb.Clause

NotEq returns a != clause

func (MarshaledScalarField) NotIn

func (f MarshaledScalarField) NotIn(values ...interface{}) qb.Clause

NotIn returns a NOT IN clause

type Metadata

type Metadata struct {
	// contains filtered or unexported fields
}

Metadata holds the table defs & mappers of a db

func NewMetadata

func NewMetadata() *Metadata

NewMetadata instanciate a Metadata

func NewMetadataFromQbMetadata

func NewMetadataFromQbMetadata(qbMeta *qb.MetaDataElem) *Metadata

NewMetadataFromQbMetadata returns a Metadata from a qb.Metadata

func (*Metadata) AddMapper

func (m *Metadata) AddMapper(mapper Mapper)

AddMapper add a mapper

func (*Metadata) GetMapper

func (m *Metadata) GetMapper(s MappedStruct) Mapper

GetMapper returns the default mapper of a mapped struct

func (*Metadata) GetQbMetadata

func (m *Metadata) GetQbMetadata() *qb.MetaDataElem

GetQbMetadata returns the underlying

type Model

type Model interface {
	GetMapper() Mapper
}

A Model provides handy access to a struct definition.

type Query

type Query struct {
	// contains filtered or unexported fields
}

Query helps querying structs from the database

func NewQuery

func NewQuery(db IDB, mapper Mapper) Query

NewQuery creates a new query

func (Query) All

func (q Query) All(value interface{}) error

All load all the structs matching the query

func (Query) AllContext

func (q Query) AllContext(ctx context.Context, value interface{}) error

AllContext load all the structs matching the query

func (Query) Count

func (q Query) Count(count interface{}) error

Count change the columns to COUNT(*), execute the query and returns the result

func (Query) CountContext

func (q Query) CountContext(ctx context.Context, count interface{}) error

CountContext change the columns to COUNT(*), execute the query and returns the result

func (Query) Exists

func (q Query) Exists() (exists bool, err error)

Exists return true if any record matches the current query

func (Query) ExistsContext

func (q Query) ExistsContext(ctx context.Context) (exists bool, err error)

ExistsContext return true if any record matches the current query

func (Query) Filter

func (q Query) Filter(clauses ...qb.Clause) Query

Filter combines the given clauses with the current Where clause of the Query

func (Query) ForUpdate

func (q Query) ForUpdate(mps ...MapperProvider) Query

ForUpdate add a FOR UPDATE clause

func (Query) Get

func (q Query) Get(s MappedStruct, pkey ...interface{}) error

Get returns a record from its primary key values

func (Query) GetContext

func (q Query) GetContext(ctx context.Context, s MappedStruct, pkey ...interface{}) error

GetContext returns a record from its primary key values

func (Query) InnerJoin

func (q Query) InnerJoin(mp MapperProvider, clause ...qb.Clause) Query

InnerJoin joins a table

func (Query) LeftJoin

func (q Query) LeftJoin(mp MapperProvider, clause ...qb.Clause) Query

LeftJoin joins a table

func (Query) Limit

func (q Query) Limit(limit int) Query

Limit add a LIMIT clause

func (Query) LimitOffset

func (q Query) LimitOffset(limit int, offset int) Query

LimitOffset add a LIMIT/OFFSET clause

func (Query) Offset

func (q Query) Offset(offset int) Query

Offset add a OFFSET clause

func (Query) One

func (q Query) One(s MappedStruct) error

One returns one and only one struct from the query. If query has no result or more than one, an error is returned

func (Query) OneContext

func (q Query) OneContext(ctx context.Context, s MappedStruct) error

OneContext returns one and only one struct from the query. If query has no result or more than one, an error is returned

func (Query) OrderBy

func (q Query) OrderBy(clauses ...qb.Clause) Query

OrderBy add a ORDER BY clause

func (Query) RightJoin

func (q Query) RightJoin(mp MapperProvider, clause ...qb.Clause) Query

RightJoin joins a table

func (Query) SQLQuery

func (q Query) SQLQuery() (*sql.Rows, error)

SQLQuery runs the query

func (Query) SQLQueryContext

func (q Query) SQLQueryContext(ctx context.Context) (*sql.Rows, error)

SQLQueryContext runs the query

func (Query) SQLQueryRow

func (q Query) SQLQueryRow() qb.Row

SQLQueryRow runs the query and expects at most one row in the result

func (Query) SQLQueryRowContext

func (q Query) SQLQueryRowContext(ctx context.Context) qb.Row

SQLQueryRowContext runs the query and expects at most one row in the result

func (Query) Scalar

func (q Query) Scalar(value interface{}) error

Scalar execute the query and retrieve a single value from it

func (Query) ScalarContext

func (q Query) ScalarContext(ctx context.Context, value interface{}) error

ScalarContext execute the query and retrieve a single value from it

func (Query) Select

func (q Query) Select(clause ...qb.Clause) Query

Select redefines the SELECT clauses

func (Query) SelectStmt

func (q Query) SelectStmt() qb.SelectStmt

SelectStmt returns the builded SelectStmt

func (Query) Where

func (q Query) Where(clauses ...qb.Clause) Query

Where set the filter clause of the query

type ScalarField

type ScalarField struct {
	Column qb.ColumnElem
}

ScalarField A simple scalar field

func NewScalarField

func NewScalarField(column qb.ColumnElem) ScalarField

NewScalarField returns a new ScalarField

func (ScalarField) Accept

func (f ScalarField) Accept(context *qb.CompilerContext) string

Accept calls the underlying column 'Accept'.

func (ScalarField) Eq

func (f ScalarField) Eq(value interface{}) qb.Clause

Eq returns a = clause

func (ScalarField) Gt

func (f ScalarField) Gt(value interface{}) qb.Clause

Gt returns a > clause

func (ScalarField) Gte

func (f ScalarField) Gte(value interface{}) qb.Clause

Gte returns a >= clause

func (ScalarField) In

func (f ScalarField) In(values ...interface{}) qb.Clause

In returns a IN clause

func (ScalarField) Like

func (f ScalarField) Like(pattern string) qb.Clause

Like returns a LIKE clause

func (ScalarField) Lt

func (f ScalarField) Lt(value interface{}) qb.Clause

Lt returns a < clause

func (ScalarField) Lte

func (f ScalarField) Lte(value interface{}) qb.Clause

Lte returns a <= clause

func (ScalarField) NotEq

func (f ScalarField) NotEq(value interface{}) qb.Clause

NotEq returns a != clause

func (ScalarField) NotIn

func (f ScalarField) NotIn(values ...interface{}) qb.Clause

NotIn returns a NOT IN clause

type Tx

type Tx struct {
	// contains filtered or unexported fields
}

Tx is an on-going database transaction

func (Tx) Commit

func (tx Tx) Commit() error

Commit commits the transaction

func (Tx) Delete

func (tx Tx) Delete(s MappedStruct) error

Delete drop a struct from the database

func (Tx) DeleteContext

func (tx Tx) DeleteContext(ctx context.Context, s MappedStruct) error

DeleteContext drop a struct from the database

func (Tx) GetEngine

func (tx Tx) GetEngine() Engine

GetEngine returns the underlying qb.Tx

func (Tx) Insert

func (tx Tx) Insert(s MappedStruct) error

Insert a new struct to the database

func (Tx) InsertContext

func (tx Tx) InsertContext(ctx context.Context, s MappedStruct) error

InsertContext a new struct to the database

func (Tx) Query

func (tx Tx) Query(mp MapperProvider) Query

Query returns a new Query

func (Tx) Rollback

func (tx Tx) Rollback() error

Rollback aborts the transaction

func (Tx) Update

func (tx Tx) Update(s MappedStruct, fields ...string) error

Update write struct values to the database If fields is provided, only theses fields are written

func (Tx) UpdateContext

func (tx Tx) UpdateContext(ctx context.Context, s MappedStruct, fields ...string) error

UpdateContext write struct values to the database If fields is provided, only theses fields are written

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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