model

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2021 License: MIT Imports: 9 Imported by: 2

Documentation

Overview

Package model allows Go structs to behave as database models.

While this package exports several types the only one you currently need to be concerned with is type Models. All of the examples in this package use a global instance of Models defined in the examples subpackage; you may refer to that global instance for an instantiation example.

Note that in the examples for this package when you see examples.Models or examples.DB_Insert() it is referring the examples subdirectory for this package and NOT the subdirectory for sqlh (i.e. both sqlh and sqlh/model have an examples subdirectory.)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Model

type Model struct {
	// Table is the related database table.
	Table schema.Table
	// Statements are the SQL database statements.
	Statements statements.Table

	// V is a *set.Value of a model instance M.
	V *set.Value
	// VSlice is a *set.Value of a model slice []M.
	VSlice *set.Value

	// Mapping is the column to struct field mapping.
	Mapping *set.Mapping

	// BoundMapping is a cached BoundMapping of a zero value for
	// the model.  Gathering query arguments and scan targets will
	// be faster when executing queries by performing the following:
	//	cp := Model.BoundMapping.Copy() // Copy the cached BoundMapping.
	//	cp.Rebind( modelInstance ) 		// Bind the copy to an instance of the model.
	//	cp.Fields( ... )				// Get a slice of query arguments by column name.
	//	cp.Assignable( ... )			// Get a slice of scan targets by column name.
	BoundMapping set.BoundMapping
}

Model relates a Go type to its Table.

func (*Model) BindQuery

func (me *Model) BindQuery(query *statements.Query) QueryBinding

BindQuery returns a QueryBinding that facilitates running queries against instaces of the model.

func (*Model) NewInstance

func (me *Model) NewInstance() interface{}

NewInstance creates an instance of the model's zero value.

func (*Model) NewSlice

func (me *Model) NewSlice() interface{}

NewSlice creates a slice that can hold instances of the model's zero value.

type Models

type Models struct {
	//
	// Mapper defines how SQL column names map to fields in Go structs.
	Mapper *set.Mapper
	//
	// Grammar defines the SQL grammar to use for SQL generation.
	Grammar *grammar.Grammar
	//
	// Models is a map of Go types to Model instances.  This member is automatically
	// instantiated during calls to Register().
	Models map[reflect.Type]*Model
	//
	// StructTag specifies the struct tag name to use when inspecting types
	// during register.  If not set will default to "model".
	StructTag string
}

Models is a registry of Models and methods to manipulate them.

Example (Insert)
package main

import (
	"fmt"
	"time"

	"github.com/nofeaturesonlybugs/sqlh/model/examples"
)

func main() {
	model := &examples.Address{
		// Id, CreatedTime, ModifiedTime are not set and updated by the database.
		Street: "1234 The Street",
		City:   "Small City",
		State:  "ST",
		Zip:    "98765",
	}

	// Create a mock database.  Unlike a production database the mock DB tells us
	// which values to expect when scanning back into models via returning.
	db, returning, err := examples.DB_Insert(model)
	if err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Insert our model.  The values from returning (see above) are scanned into
	// auto updating fields of the model (pk, created, modified).
	if err := examples.Models.Insert(db, model); err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Check values from returning were scanned into the model.
	if model.Id != returning[0][0].(int) {
		fmt.Println("unexpected id")
	}
	if !model.CreatedTime.Equal(returning[0][1].(time.Time)) {
		fmt.Println("unexpected created time")
	}
	if !model.ModifiedTime.Equal(returning[0][2].(time.Time)) {
		fmt.Println("unexpected modified time")
	}
	fmt.Printf("Model inserted.")

}
Output:

Model inserted.
Example (InsertSlice)
package main

import (
	"fmt"
	"time"

	"github.com/nofeaturesonlybugs/sqlh/model/examples"
)

func main() {
	models := []*examples.Address{
		// Id, CreatedTime, ModifiedTime are not set and updated by the database.
		{
			Street: "1234 The Street",
			City:   "Small City",
			State:  "ST",
			Zip:    "98765",
		},
		{
			Street: "55 Here We Are",
			City:   "Big City",
			State:  "TS",
			Zip:    "56789",
		},
	}

	// Create a mock database.  Unlike a production database the mock DB tells us
	// which values to expect when scanning back into models via returning.
	db, returning, err := examples.DB_Insert(models)
	if err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Insert our model.  The values from returning (see above) are scanned into
	// auto updating fields of the model (pk, created, modified).
	if err := examples.Models.Insert(db, models); err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Check values from returning were scanned into the model.
	for k, model := range models {
		if model.Id != returning[k][0].(int) {
			fmt.Println("unexpected id")
			return
		}
		if model.CreatedTime != returning[k][1].(time.Time) {
			fmt.Println("unexpected created time")
			return
		}
		if model.ModifiedTime != returning[k][2].(time.Time) {
			fmt.Println("unexpected modified time")
			return
		}
	}
	fmt.Printf("%v model(s) updated.", len(models))
}
Example (Update)
package main

import (
	"fmt"
	"time"

	"github.com/nofeaturesonlybugs/sqlh/model/examples"
)

func main() {
	model := &examples.Address{
		Id:          42,
		CreatedTime: time.Now().Add(-1 * time.Hour),
		// ModifiedTime is zero value; will be updated by database.
		Street: "1234 The Street",
		City:   "Small City",
		State:  "ST",
		Zip:    "98765",
	}

	// Create a mock database.  Unlike a production database the mock DB tells us
	// which values to expect when scanning back into models via returning.
	db, returning, err := examples.DB_Update(model)
	if err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Update our model.  The values from returning (see above) are scanned into
	// auto updating fields of the model (modified).
	if err := examples.Models.Update(db, model); err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Check values from returning were scanned into the model.
	if !model.ModifiedTime.Equal(returning[0][0].(time.Time)) {
		fmt.Println("unexpected modified time")
	}
	fmt.Printf("Model updated.")

}
Output:

Model updated.
Example (UpdateSlice)
package main

import (
	"fmt"
	"time"

	"github.com/nofeaturesonlybugs/sqlh/model/examples"
)

func main() {
	models := []*examples.Address{
		// ModifiedTime is not set and updated by the database.
		{
			Id:          42,
			CreatedTime: time.Now().Add(-2 * time.Hour),
			Street:      "1234 The Street",
			City:        "Small City",
			State:       "ST",
			Zip:         "98765",
		},
		{
			Id:          62,
			CreatedTime: time.Now().Add(-1 * time.Hour),
			Street:      "55 Here We Are",
			City:        "Big City",
			State:       "TS",
			Zip:         "56789",
		},
	}

	// Create a mock database.  Unlike a production database the mock DB tells us
	// which values to expect when scanning back into models via returning.
	db, returning, err := examples.DB_Update(models)
	if err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Update our models.  The values from returning (see above) are scanned into
	// auto updating fields of the model (modified).
	if err := examples.Models.Update(db, models); err != nil {
		fmt.Println("err", err.Error())
		return
	}

	// Check values from returning were scanned into the model.
	for k, model := range models {
		if model.ModifiedTime != returning[k][0].(time.Time) {
			fmt.Println("unexpected modified time")
			return
		}
	}
	fmt.Printf("%v model(s) updated.", len(models))

}
Output:

2 model(s) updated.

func (*Models) Insert

func (me *Models) Insert(Q sqlh.IQueries, value interface{}) error

Insert attempts to persist values via INSERTs.

func (*Models) Lookup

func (me *Models) Lookup(value interface{}) (m *Model, err error)

Lookup returns the model associated with the value.

func (*Models) Register

func (me *Models) Register(value interface{}, opts ...interface{})

Register adds a Go type to the Models instance. As part of initialization your application should register all types T that need to interact with the database.

Register is not goroutine safe; implement locking in the application level if required.

func (*Models) Update

func (me *Models) Update(Q sqlh.IQueries, value interface{}) error

Update attempts to persist values via UPDATESs.

type QueryBinding

type QueryBinding interface {
	// Query accepts either a single model M or a slice of models []M.  It then
	// runs and returns the result of QueryOne or QuerySlice.
	Query(sqlh.IQueries, interface{}) error
	// QueryOne runs the query against a single instance of the model.
	QueryOne(sqlh.IQueries, interface{}) error
	// QuerySlice runs the query against a slice of model instances.
	QuerySlice(sqlh.IQueries, interface{}) error
}

QueryBinding binds a model with a query to facilitate running the query against instances of types described by the model.

type TableName

type TableName string

TableName represents a database table name. Embed the TableName type into a struct and set the approprate struct tag to configure the table name.

Directories

Path Synopsis
Package examples provides types and functions to facilitate the examples and test code in the model package.
Package examples provides types and functions to facilitate the examples and test code in the model package.
Package statements builds uses a grammar to build SQL statements scoped to entities within the database.
Package statements builds uses a grammar to build SQL statements scoped to entities within the database.

Jump to

Keyboard shortcuts

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