accessor

package
v0.2.7 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2024 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Accessor feature summary

  1. public accessor methods Get(ctx context.Context, dest any, query string, args ...any) error Select(ctx context.Context, dest any, query string, args ...any) error Exec(ctx context.Context, query string, args ...any) (result sql.Result, outErr error)

    NamedGet(ctx context.Context, dest any, query string, arg any) error NamedSelect(ctx context.Context, dest any, query string, arg any) error NamedExec(ctx context.Context, query string, arg any) (sql.Result, error)

    SqlizerGet( ctx context.Context, dest any, sqlizer func(builder squirrel.StatementBuilderType) Sqlizer, ) error SqlizerSelect( ctx context.Context, dest any, sqlizer func(builder squirrel.StatementBuilderType) Sqlizer, ) error SqlizerExec( ctx context.Context, sqlizer func(builder squirrel.StatementBuilderType) Sqlizer, ) (result sql.Result, outErr error)

    // Entity CRUD Create(ctx context.Context, entity any, tbl string, idFields ...string) error Read(ctx context.Context, entity any, tbl string, idFields ...string) error Update(ctx context.Context, entity any, tbl string, idFields ...string) (sql.Result, error) Delete(ctx context.Context, entity any, tbl string, idFields ...string) (sql.Result, error)

    EntityGet( ctx context.Context, dest any, tbl string, sqlizer func(builder squirrel.SelectBuilder) Sqlizer, idFields ...string, ) error EntitySelect( ctx context.Context, dest any, tbl string, sqlizer func(builder squirrel.SelectBuilder) Sqlizer, idFields ...string, ) error

  1. public helper functions ExecTx( ctx context.Context, db *pg.DB, txOps *sql.TxOptions, execFn func(ctx context.Context, accessor *Accessor) error, ) (outErr error)

    Column(v any, fieldName string) string Columns(v any) []string

  1. Accessor itself is not thread-safe, however, its underlying backend musts be thread-safe.
  2. Accessor assumes manipulation of Dabatabse entity objects, columns of corresponding column mappings should exist in entity type (in Go struct tag "db")
  3. Delete() and Update() supports default "Id" (column id) mapping
  4. Accessor bridges github.com/jmoiron/sqlx and github.com/Masterminds/squirrel, allows generic database CRUD and SELECT operations with regular literal query binding, named query binding querying by example and programmatical query binding.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Column

func Column(v any, fieldName string) string

Column return the mapped column mapping name in entity type of v and specified Go struct field name. Optimizing with multi-threaded safe caching if it is needed

func Columns

func Columns(v any) []string

Columns return all found column mappings in entity type of v. Optimizing with multi-threaded safe caching if it is needed

func ExecTx

func ExecTx(
	ctx context.Context,
	db *sqlx.DB,
	txOps *sql.TxOptions,
	execFn func(ctx context.Context, accessor *Accessor) error,
) (outErr error)

ExecTx uses annonymous execution function to achieve crash-safe and implicit transaction commission effect Usage example

err := ExecTx(context.Background(), s.Db, &sql.TxOptions{}, func(ctx context.Context, accessor *Accessor) error {
    var p struct {
        FirstName string    `db:"first_name"`
        LastName  string    `db:"last_name"`
        Email     string    `db:"email"`
        AddedAt   time.Time `db:"added_at"`
    }

    err := accessor.Get(context.Background(), &p, "select * from person where first_name=? and last_name=?",
        "foo", "test")

    return nil
})

Types

type Accessor

type Accessor struct {
	Db sqlx.Ext
}

func New

func New(db sqlx.Ext) *Accessor

func (*Accessor) Create

func (a *Accessor) Create(ctx context.Context, entity any, tbl string, idFields ...string) error

Insert a database row based on entity properties.

Create allows caller to specify hint about its primary key column(s). Only when corresponding entity fields have non-zero value(s), will the zon-zero value(s) be used, otherwise, related privary column(s) will be inserted with database supplied value(s).

Zero value of ID fields indicates to insert the row using database's auto-increment value, returning auto-increment ID value will be backfilled into the entity object

If no idFieds is given, Create will try "Id" -> "id" mapping for primary key, if "Id" -> "id" mapping does not exist, Create does not perform special handling of primary key column(s) that may have database auto-increment enabled.

Usage example

// create
city := struct {
    Id      int    `db:"id"`
    Name    string `db:"name"`
    ZipCode string `db:"zip_code"`
}{
    Name:    "San Jose",
    ZipCode: "95120",
}

accessor := New(s.Db.DB)
err := accessor.Create(context.Background(), &city, "city")

func (*Accessor) Delete

func (a *Accessor) Delete(ctx context.Context, entity any, tbl string, idFields ...string) (sql.Result, error)

Usage example:

p := struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}{
    FirstName: "foo",
    LastName:  "test",
}

accessor := New(s.Db.DB)
result, err := accessor.Delete(context.Background(), p, "person", "FirstName", "LastName")

func (*Accessor) EntityGet added in v0.2.7

func (a *Accessor) EntityGet(
	ctx context.Context,
	dest any,
	tbl string,
	sqlizer func(builder squirrel.SelectBuilder) Sqlizer,
	idFields ...string,
) error

For composite entity type, EntityGet can help generate SQL table JOIN statement, let you focus on writing the right WHERE clause

Usage example:

m = Manager{}
err = a.EntityGet(
	context.Background(),
	&m,
	m.TableName(),
	func(builder squirrel.SelectBuilder) accessor.Sqlizer {
		return builder.Where(squirrel.Eq{
			m.Employee.TableName() + "." + m.Employee.EntityFields().Company: "bar.com",
		})
	},
)

func (*Accessor) EntitySelect added in v0.2.7

func (a *Accessor) EntitySelect(
	ctx context.Context,
	dest any,
	tbl string,
	sqlizer func(builder squirrel.SelectBuilder) Sqlizer,
	idFields ...string,
) error

For composite entity type, EntitySelect can help generate SQL table JOIN statement, let you focus on writing the right WHERE clause Usage example:

mgrList := []Manager{}
err = a.EntitySelect(
	context.Background(),
	&mgrList,
	m.TableName(),
	func(builder squirrel.SelectBuilder) accessor.Sqlizer {
		return builder.Where(squirrel.Eq{
			m.Employee.TableName() + "." + m.Employee.EntityFields().Company: "bar.com",
		})
	},
)

func (*Accessor) Exec

func (a *Accessor) Exec(ctx context.Context, query string, args ...any) (result sql.Result, outErr error)

Usage example:

result, err := accessor.Exec(context.Background(), "delete from person where first_name=?", "foo")

func (*Accessor) Get

func (a *Accessor) Get(ctx context.Context, dest any, query string, args ...any) error

Get returns a single found entity. Note: wildcard column selection is allowed, unmatched column to field mapping will be silently ignored

Usage example:

var p struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}

err := accessor.Get(context.Background(), &p, "select * from person where first_name=? and last_name=?",
    "foo", "test")

func (*Accessor) NamedExec

func (a *Accessor) NamedExec(ctx context.Context, query string, arg any) (sql.Result, error)

func (*Accessor) NamedGet

func (a *Accessor) NamedGet(ctx context.Context, dest any, query string, arg any) error

Usage example:

var p struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}

err := accessor.NamedGet(context.Background(), &p, "select * from person where first_name=:first_name and last_name=:last_name",
    map[string]any{
        "first_name": "foo",
        "last_name":  "test",
    })

// query by example
var p, example struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}

example.FirstName = "foo"
example.LastName = "test"
err := accessor.NamedGet(context.Background(), &p, "select * from person where first_name=:first_name and last_name=:last_name", &example)

func (*Accessor) NamedSelect

func (a *Accessor) NamedSelect(ctx context.Context, dest any, query string, arg any) error

Usage example

var p []struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string `db:"email"`
}

err := accessor.NamedSelect(context.Background(), &p, "select * from person where last_name=:last_name order by first_name DESC",
    map[string]any{
        "last_name": "test",
    })

func (*Accessor) Read

func (a *Accessor) Read(ctx context.Context, entity any, tbl string, idFields ...string) error

Usage example

city2 := struct {
    Id      int    `db:"id"`
    Name    string `db:"name"`
    ZipCode string `db:"zip_code"`
}{
    Id: city.Id,
}

err = accessor.Read(context.Background(), &city2, "city")

func (*Accessor) Select

func (a *Accessor) Select(ctx context.Context, dest any, query string, args ...any) error

Usage example:

var p []struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string `db:"email"`
}

err := accessor.Select(context.Background(), &p, "select * from person where last_name=?", "test")

func (*Accessor) SqlizerExec

func (a *Accessor) SqlizerExec(
	ctx context.Context,
	sqlizer func(builder squirrel.StatementBuilderType) Sqlizer,
) (result sql.Result, outErr error)

func (*Accessor) SqlizerGet

func (a *Accessor) SqlizerGet(
	ctx context.Context,
	dest any,
	sqlizer func(builder squirrel.StatementBuilderType) Sqlizer,
) error

Usage example:

var p struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}

err := accessor.SqlizerGet(context.Background(), &p, func(builder squirrel.StatementBuilderType) Sqlizer {
    return builder.Select("*").From("person").Where(squirrel.Eq{
        Column(p, "FirstName"): "foo",
        Column(p, "LastName"):  "test",
    })
})

func (*Accessor) SqlizerSelect

func (a *Accessor) SqlizerSelect(
	ctx context.Context,
	dest any,
	sqlizer func(builder squirrel.StatementBuilderType) Sqlizer,
) error

Usage example:

var p []struct {
    FirstName string    `db:"first_name"`
    LastName  string    `db:"last_name"`
    Email     string    `db:"email"`
    AddedAt   time.Time `db:"added_at"`
}

err := accessor.SqlizerSelect(context.Background(), &p, func(builder squirrel.StatementBuilderType) Sqlizer {
    return builder.Select("*").From("person").Where(squirrel.Eq{
        Column(p, "LastName"): "test",
    })
})

func (*Accessor) Update

func (a *Accessor) Update(ctx context.Context, entity any, tbl string, idFields ...string) (sql.Result, error)

Usage example:

// partial update
p := &PersonWithUpdateTracker{}
p.FirstName = "foo"
p.LastName = "test"

// this update will be tracked
p.SetEmail("foo@test.change")

accessor := New(s.Db.DB)
result, err := accessor.Update(context.Background(), p, "person", "FirstName", "LastName")

// update in full
ppp := &Person{}
ppp.FirstName = "foo"
ppp.LastName = "test"
ppp.Email = "foo@test.change.again"
ppp.AddedAt = time.Now().UTC()
result, err = accessor.Update(context.Background(), ppp, "person", "FirstName", "LastName")

type EntityMappingSchema added in v0.2.0

type EntityMappingSchema struct {
	TableName string

	// field name -> column name (note, fields in embedded type are not included here)
	Columns map[string]string

	// embedded mappings
	BaseMappings []*EntityMappingSchema

	Entity     any
	EntityType reflect.Type
}

func EntitySchema added in v0.2.0

func EntitySchema(v any, typ reflect.Type, tableName string) (*EntityMappingSchema, error)

func (*EntityMappingSchema) GetColumnSelectString added in v0.2.0

func (m *EntityMappingSchema) GetColumnSelectString() string

func (*EntityMappingSchema) GetTableJoinString added in v0.2.0

func (m *EntityMappingSchema) GetTableJoinString(idColumns ...string) string

func (*EntityMappingSchema) Schemas added in v0.2.0

func (m *EntityMappingSchema) Schemas() []*EntityMappingSchema

func (*EntityMappingSchema) Tables added in v0.2.0

func (m *EntityMappingSchema) Tables() []string

type Sqlizer

type Sqlizer interface {
	ToSql() (string, []interface{}, error)
}

type UpdateTracker

type UpdateTracker interface {
	ColumnsChanged(tbl ...string) []string
}

Jump to

Keyboard shortcuts

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