db

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2019 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

The db package works with the rest of the orm to interface between a database and the ORM abstraction of reading and querying a database. It is architected so that both SQL and NoSQL databases can be used with the abstraction. This allows you to potentially write code that is completely agnostic to what kind of database you are using. Even if 100% portability is not achievable in your use case, the ORM and database abstraction layers should be able to handle most of your needs, such that if you ever did have to port to a different database, it would minimize the amount of custom code you would need to write.

Generally, SQL and NoSQL databases work very differently. However, many SQL databases have recently added NoSQL capabilities, like storing and searching JSON text. Similarly, NoSQL databases have added features to enable searching a database through relationships, similar to SQL capabilities. In addition, NoSQL design advice is often to flatten the database structure as much as possible, so that it looks a whole lot like a SQL database.

The general approach Goradd takes is to generally describe data with key/value pairs. This fits in well with SQL, as key/value pairs are just table-column/field pairs. NoSQL generally works with key-value pairs anyways.

Relationships between structures are described as relationships, either one-to-many, or many-to-many. By keeping the description at a higher level, we allow databases to implement those relationships in the way that works best.

SQL implements one-to-many relationships using foreign keys. In the data description, you will see a Reference type of relationship, which points from the many to the one, and a ReverseRelationship, which is a kind of virtual representation of pointing from the one side to the many. ReverseRelationship lists are populated at the time of a query. In SQL, Many-to-many relationships use an intermediate table, called an Association Table, that has foreign keys pointing in both directions.

NoSQL implements one-to-many relationships using foreign-keys as well, but both sides of the relationship store the foreign key, or keys, that point to the other side. This means that a ReverseRelationship will represent an actual field in the database structure that contains a list of all of the items pointing back at itself. This also means that when these relationships are created or destroyed, both sides of the relationship need to be updated. Similarly, NoSQL many-to-many relationships have lists of foreign keys stored on both sides of the relationship.

The other major difference between SQL and NoSQL databases is the built-in capabilities to do aggregate calculations. In SQL, you generally can create a filtered list of records and ask SQL to sum all the values from a particular field. Some NoSQL databases can do this, and some cannot. The ones that cannot expect the programmer to do their own filtering and summing. GoRADD handles this difference by allowing individual GORADD database drivers to be written that add some aggregate capabilities to a database, and also providing ways for individual developers to simply create their own custom queries that will be non-portable between databases. In any case, there is always a way to do what you want to do, just some databases are easier to work with. It depends what you want to do.

Index

Constants

View Source
const (
	MysqlTypeSet  = "Set"
	MysqlTypeEnum = "Enum"
)
View Source
const (
	QueryOperationUnknown = iota
	QueryOperationLoad
	QueryOperationDelete
	QueryOperationCount
)
View Source
const (
	SqlTypeUnknown   = "Unknown"
	SqlTypeBlob      = "Blob"
	SqlTypeVarchar   = "VarChar"
	SqlTypeChar      = "Char"
	SqlTypeText      = "Text"
	SqlTypeInteger   = "Int"
	SqlTypeTimestamp = "Timestamp"
	SqlTypeDatetime  = "DateTime"
	SqlTypeDate      = "Date"
	SqlTypeTime      = "Time"
	SqlTypeFloat     = "Float"
	SqlTypeDouble    = "Double"
	SqlTypeBool      = "Bool"
	SqlTypeDecimal   = "Decimal" // a fixed point type
)

Variables

This section is empty.

Functions

func AddDatabase

func AddDatabase(d DatabaseI, key string)

AddDatabase adds a database to the global database store. Only call this during app startup.

func AnalyzeDatabases

func AnalyzeDatabases()

AnalyzeDatabases will open all the databases and extra the table information found there. Its primary use is to extract the schema out of SQL databases so that it can be exported into a database neutral format, perhaps a json or yaml representation.

func IsProfiling

func IsProfiling(ctx context.Context) bool

IsProfiling returns true if we are currently collection SQL database profiling information.

func LowerCaseIdentifier added in v0.1.1

func LowerCaseIdentifier(s string) (i string)

func NewRestBuilder added in v0.0.9

func NewRestBuilder(db *Rest) *restBuilder

NewrestBuilder creates a new restBuilder object.

func NewSqlBuilder

func NewSqlBuilder(db SqlDbI) *sqlBuilder

NewSqlBuilder creates a new sqlBuilder object.

func NewjoinTreeItemSliceMap added in v0.0.7

func NewjoinTreeItemSliceMap() *joinTreeItemSliceMap

NewjoinTreeItemSliceMap creates a new map that maps string's to *joinTreeItem's.

func NewjoinTreeItemSliceMapFrom added in v0.0.7

func NewjoinTreeItemSliceMapFrom(i joinTreeItemMapI) *joinTreeItemSliceMap

NewjoinTreeItemSliceMapFrom creates a new joinTreeItemMap from a joinTreeItemMapI interface object

func NewjoinTreeItemSliceMapFromMap added in v0.0.7

func NewjoinTreeItemSliceMapFromMap(i map[string]*joinTreeItem) *joinTreeItemSliceMap

NewjoinTreeItemSliceMapFromMap creates a new joinTreeItemSliceMap from a GO map[string]*joinTreeItem object. Note that this will pass control of the given map to the new object. After you do this, DO NOT change the original map.

func ReceiveRows

func ReceiveRows(rows *sql.Rows, columnTypes []GoColumnType, columnNames []string) (values []map[string]interface{})

ReceiveRows gets data from a sql result set and returns it as a slice of maps. Each column is mapped to its column name. If you provide column names, those will be used in the map. Otherwise it will get the column names out of the result set provided

func UpperCaseIdentifier added in v0.1.1

func UpperCaseIdentifier(s string) (i string)

Types

type ColumnDescription

type ColumnDescription struct {
	// DbName is the name of the column in the database. This is blank if this is a "virtual" table for sql tables like an association or virtual attribute query.
	DbName string
	// GoName is the name of the column in go code
	GoName string
	// NativeType is the type of the column as described by the database itself.
	NativeType string
	//  ColumnType is the goradd defined column type
	ColumnType GoColumnType
	// MaxCharLength is the maximum length of characters to allow in the column if a string type column.
	// If the database has the ability to specify this, this will correspond to what is specified.
	// In any case, we will generate code to prevent fields from getting bigger than this.
	MaxCharLength uint64
	// DefaultValue is the default value as specified by the database. We will initialize new ORM objects
	// with this value. It will be case to the corresponding GO type.
	DefaultValue interface{}
	// MaxValue is the maximum value allowed for numeric values. This can be used by UI objects to tell the user what the limits are.
	MaxValue interface{}
	// MinValue is the minimum value allowed for numeric values. This can be used by UI objects to tell the user what the limits are.
	MinValue interface{}
	// IsId is true if this column represents a unique identifier generated by the database
	IsId bool
	// IsPk is true if this is the primary key column. PK's do not necessarily need to be ID columns, and if not, we will need to do our own work to generate unique PKs.
	IsPk bool
	// IsNullable is true if the column can be given a NULL value
	IsNullable bool
	// IsIndexed is true if the column's table has a single index on the column, which will generate a LoadArrayBy function.
	IsIndexed bool
	// IsUnique is true if the column's table has a single unique index on the column.
	IsUnique bool
	// IsTimestamp is true if the field is a timestamp. Timestamps represent a specific point in world time.
	IsTimestamp bool
	// IsAutoUpdateTimestamp is true if the database is updating the timestamp. Otherwise we will do it manually.
	IsAutoUpdateTimestamp bool
	// Comment is the contents of the comment associated with this field
	Comment string

	// Filled in by analyzer
	// Options are the options extracted from the comments string
	Options *maps.SliceMap
	// ForeignKey is additional information describing a foreign key relationship
	ForeignKey *ForeignKeyColumn
	// ModelName is a cache for the internal model name of this column.
	ModelName string
}

ColumnDescription describes a database column. Most of the information is either gleaned from the structure of the database, or is taken from a file that describes the relationships between different record types. Some of the information is filled in after analysis. Some of the information can be provided through information embedded in database comments.

func (*ColumnDescription) DefaultConstantName

func (cd *ColumnDescription) DefaultConstantName(tableName string) string

DefaultConstantName returns the name of the default value constant that will be used to refer to the default value

func (*ColumnDescription) DefaultValueAsConstant

func (cd *ColumnDescription) DefaultValueAsConstant() string

DefaultValueAsConstant returns the default value of the column as a GO constant

func (*ColumnDescription) DefaultValueAsValue

func (cd *ColumnDescription) DefaultValueAsValue() string

DefaultValueAsValue returns the default value of the column as a GO value

func (*ColumnDescription) IsReference

func (cd *ColumnDescription) IsReference() bool

IsReference returns true if the column is a foreign key pointing to another table

func (*ColumnDescription) JsonKey added in v0.1.1

func (cd *ColumnDescription) JsonKey() string

func (*ColumnDescription) ReferenceFunction added in v0.1.1

func (cd *ColumnDescription) ReferenceFunction(dd *DatabaseDescription) string

ReferenceFunction returns the function name that should be used to refer to the object that is referred to by a forward reference. It is extracted from the name of foreign key.

func (*ColumnDescription) ReferenceJsonKey added in v0.1.1

func (cd *ColumnDescription) ReferenceJsonKey(dd *DatabaseDescription) string

ReferenceJsonKey returns the key that will be used for the referenced object in JSON.

type Copier

type Copier interface {
	Copy() interface{}
}

Copier implements the copy interface, that returns a deep copy of an object.

type DatabaseDescription

type DatabaseDescription struct {
	// The database key corresponding to its key in the global database cluster
	DbKey string
	// Tables are the tables in the database
	Tables []*TableDescription
	// TypeTables contains a description of the enumerated types from the type tables in the database
	TypeTables []*TypeTableDescription
	// The prefix for related objects.
	AssociatedObjectPrefix string

	// Text to strip off the end of foreign key references when converting to names. Defaults to "_id"
	ForeignKeySuffix string
	// contains filtered or unexported fields
}

The DatabaseDescription is the top level struct that contains a complete description of a database for purposes of generating and creating queries

func NewDatabaseDescription

func NewDatabaseDescription(dbKey string, objectPrefix string, fkSuffix string) *DatabaseDescription

NewDatabaseDescription creates a new database description. This is the structure returned by database analysis.

func (*DatabaseDescription) IsTypeTable

func (dd *DatabaseDescription) IsTypeTable(name string) bool

IsTypeTable returns true if the given name is the name of a type table in the database

func (*DatabaseDescription) TableDescription

func (dd *DatabaseDescription) TableDescription(name string) *TableDescription

TableDescription returns a TableDescription from the database given the table name.

func (*DatabaseDescription) TypeTableDescription

func (dd *DatabaseDescription) TypeTableDescription(name string) *TypeTableDescription

TypeTableDescription returns a TypeTableDescription from the database given the table name.

type DatabaseI

type DatabaseI interface {
	// Describe returns a DatabaseDescription object, which is a complete description of the tables and fields in
	// a database and their potential relationships. SQL databases can, for the most part, generate this description
	// based on their structure. NoSQL databases would need to get this description some other way, like through
	// a json file.
	Describe() *DatabaseDescription

	// AssociatedObjectPrefix is a prefix we add to all variables that point to ORM objects. By default this is an "o".
	AssociatedObjectPrefix() string

	// NewBuilder returns a newly created query builder
	NewBuilder() QueryBuilderI

	// Update will put the given values into a record that already exists in the database. The "fields" value
	// should include only fields that have changed.
	Update(ctx context.Context, table string, fields map[string]interface{}, pkName string, pkValue string)
	// Insert will insert a new record into the database with the given values, and return the new record's primary key value.
	// The fields value should include all the required values in the database.
	Insert(ctx context.Context, table string, fields map[string]interface{}) string
	// Delete will delete the given record from the database
	Delete(ctx context.Context, table string, pkName string, pkValue interface{})

	// Begin will begin a transaction in the database and return the transaction id
	Begin(ctx context.Context) TransactionID
	// Commit will commit the given transaction
	Commit(ctx context.Context, txid TransactionID)
	// Rollback will roll back the given transaction PROVIDED it has not been committed. If it has been
	// committed, it will do nothing. Rollback can therefore be used in a defer statement as a safeguard in case
	// a transaction fails.
	Rollback(ctx context.Context, txid TransactionID)
}

DatabaseI is the interface that describes the behaviors required for a database implementation.

func GetDatabase

func GetDatabase(key string) DatabaseI

GetDatabase returns the database given the database's key.

func GetDatabases

func GetDatabases() []DatabaseI

GetDatabases returns all databases in the datastore

type DatabaseIGetter added in v0.0.9

type DatabaseIGetter interface {
	Get(key string) (val DatabaseI)
}

type DatabaseILoader added in v0.0.9

type DatabaseILoader interface {
	Load(key string) (val DatabaseI, ok bool)
}

type DatabaseIMapI added in v0.0.9

type DatabaseIMapI interface {
	Get(key string) (val DatabaseI)
	Has(key string) (exists bool)
	Values() []DatabaseI
	Keys() []string
	Len() int
	// Range will iterate over the keys and values in the map. Pattern is taken from sync.Map
	Range(f func(key string, value DatabaseI) bool)
	Merge(i DatabaseIMapI)
}

The DatabaseIMapI interface provides a common interface to the many kinds of similar map objects.

Most functions that change the map are omitted so that you can wrap the map in additional functionality that might use Set or SetChanged. If you want to use them in an interface setting, you can create your own interface that includes them.

type DatabaseISetter added in v0.0.9

type DatabaseISetter interface {
	Set(string, DatabaseI)
}

type DatabaseISliceMap added in v0.0.9

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

A DatabaseISliceMap combines a map with a slice so that you can range over a map in a predictable order. By default, the order will be the same order that items were inserted, i.e. a FIFO list. This is similar to how PHP arrays work. DatabaseISliceMap implements the sort interface so you can change the order before ranging over the values if desired. It is NOT safe for concurrent use. The zero of this is usable immediately. The DatabaseISliceMap satisfies the DatabaseIMapI interface.

func NewDatabaseISliceMap added in v0.0.9

func NewDatabaseISliceMap() *DatabaseISliceMap

NewDatabaseISliceMap creates a new map that maps string's to DatabaseI's.

func NewDatabaseISliceMapFrom added in v0.0.9

func NewDatabaseISliceMapFrom(i DatabaseIMapI) *DatabaseISliceMap

NewDatabaseISliceMapFrom creates a new DatabaseIMap from a DatabaseIMapI interface object

func NewDatabaseISliceMapFromMap added in v0.0.9

func NewDatabaseISliceMapFromMap(i map[string]DatabaseI) *DatabaseISliceMap

NewDatabaseISliceMapFromMap creates a new DatabaseISliceMap from a GO map[string]DatabaseI object. Note that this will pass control of the given map to the new object. After you do this, DO NOT change the original map.

func (*DatabaseISliceMap) Clear added in v0.0.9

func (o *DatabaseISliceMap) Clear()

func (*DatabaseISliceMap) Copy added in v0.0.9

Copy will make a copy of the map and a copy of the underlying data.

func (*DatabaseISliceMap) Delete added in v0.0.9

func (o *DatabaseISliceMap) Delete(key string)

Delete removes the item with the given key.

func (*DatabaseISliceMap) Equals added in v0.0.9

func (o *DatabaseISliceMap) Equals(i DatabaseIMapI) bool

Equals returns true if the map equals the given map, paying attention only to the content of the map and not the order.

func (*DatabaseISliceMap) Get added in v0.0.9

func (o *DatabaseISliceMap) Get(key string) (val DatabaseI)

Get returns the value based on its key. If the key does not exist, an empty value is returned.

func (*DatabaseISliceMap) GetAt added in v0.0.9

func (o *DatabaseISliceMap) GetAt(position int) (val DatabaseI)

GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned.

func (*DatabaseISliceMap) GetKeyAt added in v0.0.9

func (o *DatabaseISliceMap) GetKeyAt(position int) (key string)

GetKeyAt returns the key based on its position. If the position is out of bounds, an empty value is returned.

func (*DatabaseISliceMap) Has added in v0.0.9

func (o *DatabaseISliceMap) Has(key string) (ok bool)

Has returns true if the given key exists in the map.

func (*DatabaseISliceMap) IsNil added in v0.0.9

func (o *DatabaseISliceMap) IsNil() bool

func (*DatabaseISliceMap) Keys added in v0.0.9

func (o *DatabaseISliceMap) Keys() (keys []string)

Keys returns the keys of the map, in the order they were added or sorted

func (*DatabaseISliceMap) Len added in v0.0.9

func (o *DatabaseISliceMap) Len() int

Len returns the number of items in the map

func (*DatabaseISliceMap) Less added in v0.0.9

func (o *DatabaseISliceMap) Less(i, j int) bool

Less is part of the interface that allows the map to be sorted by keys. It returns true if the value at position i should be sorted before the value at position j.

func (*DatabaseISliceMap) Load added in v0.0.9

func (o *DatabaseISliceMap) Load(key string) (val DatabaseI, ok bool)

Load returns the value based on its key, and a boolean indicating whether it exists in the map. This is the same interface as sync.Map.Load()

func (*DatabaseISliceMap) MarshalBinary added in v0.0.9

func (o *DatabaseISliceMap) MarshalBinary() (data []byte, err error)

MarshalBinary implements the BinaryMarshaler interface to convert the map to a byte stream.

func (*DatabaseISliceMap) MarshalJSON added in v0.0.9

func (o *DatabaseISliceMap) MarshalJSON() (data []byte, err error)

MarshalJSON implements the json.Marshaler interface to convert the map into a JSON object.

func (*DatabaseISliceMap) Merge added in v0.0.9

func (o *DatabaseISliceMap) Merge(i DatabaseIMapI)

Merge the given map into the current one

func (*DatabaseISliceMap) Range added in v0.0.9

func (o *DatabaseISliceMap) Range(f func(key string, value DatabaseI) bool)

Range will call the given function with every key and value in the order they were placed in the map, or in if you sorted the map, in your custom order. If f returns false, it stops the iteration. This pattern is taken from sync.Map.

func (*DatabaseISliceMap) Set added in v0.0.9

func (o *DatabaseISliceMap) Set(key string, val DatabaseI)

Set sets the given key to the given value. If the key already exists, the range order will not change.

func (*DatabaseISliceMap) SetAt added in v0.0.9

func (o *DatabaseISliceMap) SetAt(index int, key string, val DatabaseI)

SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than the length, or -1, it is the same as Set, in that it puts it at the end. Negative indexes are backwards from the end, if smaller than the negative length, just inserts at the beginning.

func (*DatabaseISliceMap) SetChanged added in v0.0.9

func (o *DatabaseISliceMap) SetChanged(key string, val DatabaseI) (changed bool)

SetChanged sets the value, but also appends the value to the end of the list. It returns true if something in the map changed. If the key was already in the map, the order will not change, but the value will be replaced. If you want the order to change, you must Delete then call SetChanged.

func (*DatabaseISliceMap) String added in v0.0.9

func (o *DatabaseISliceMap) String() string

func (*DatabaseISliceMap) Swap added in v0.0.9

func (o *DatabaseISliceMap) Swap(i, j int)

Swap is part of the interface that allows the slice to be sorted. It swaps the positions of the items and position i and j.

func (*DatabaseISliceMap) UnmarshalBinary added in v0.0.9

func (o *DatabaseISliceMap) UnmarshalBinary(data []byte) (err error)

UnmarshalBinary implements the BinaryUnmarshaler interface to convert a byte stream to a DatabaseISliceMap

func (*DatabaseISliceMap) UnmarshalJSON added in v0.0.9

func (o *DatabaseISliceMap) UnmarshalJSON(data []byte) (err error)

UnmarshalJSON implements the json.Unmarshaler interface to convert a json object to a DatabaseIMap. The JSON must start with an object.

func (*DatabaseISliceMap) Values added in v0.0.9

func (o *DatabaseISliceMap) Values() (vals []DatabaseI)

Values returns a slice of the values in the order they were added or sorted.

type Describer

type Describer interface {
	Describe() *DatabaseDescription
}

Describer is the interface for databases to return their DatabaseDescription

type FKAction

type FKAction int

FKAction indicates how the database handles situations when one side of a relationship is deleted or the key is changed. These generally correspond to the options available in MySQL InnoDB databases.

const (
	FKActionNone FKAction = iota // In a typical database, this is the same as Restrict. For OUR purposes, it means we should deal with it ourselves.
	// This would be the situation when we are emulating foreign key constraints for databases that don't support them.
	FKActionSetNull
	FKActionSetDefault // Not supported in MySQL!
	FKActionCascade    //
	FKActionRestrict   // The database is going to choke on this. We will try to error before something like this happens.
)

The foreign key actions tell us what the database will do automatically if a foreign key object is changed. This allows us to do the appropriate thing when we detect in the ORM that a linked object is changing.

type ForeignKeyColumn added in v0.0.3

type ForeignKeyColumn struct {
	//DbKey string	// We don't support cross database foreign keys yet. Someday maybe.
	// TableName is the name of the table on the other end of the foreign key
	TableName string
	// ColumnName is the database column name in the linked table that matches this column name. Often that is the primary key of the other table.
	ColumnName string
	// UpdateAction indicates how the database will react when the other end of the relationship's value changes.
	UpdateAction FKAction
	// DeleteAction indicates how the database will react when the other end of the relationship's record is deleted.
	DeleteAction FKAction
	// GoName is the name we should use to refer to the related object
	GoName string
	// GoType is the type of the related object
	GoType string
	// GoTypePlural is the plural version of the type when referring to groups of related objects
	GoTypePlural string
	// IsType is true if this is a related type
	IsType bool
	// RR is filled in by the analyzer and represent a reverse reference relationship
	RR *ReverseReference
}

ForeignKeyColumn is additional information to describe what a foreign key points to

func (*ForeignKeyColumn) GoVarName added in v0.0.3

func (fk *ForeignKeyColumn) GoVarName() string

GoVarName returns the name of the go object used to refer to the kind of object the foreign key points to.

type IndexDescription

type IndexDescription struct {
	// KeyName is the name of the index
	KeyName string
	// IsUnique indicates whether the index is for a unique index
	IsUnique bool
	// IsPrimary indicates whether this is the index for the primary key
	IsPrimary bool
	// ColumnNames are the columns that are part of the index
	ColumnNames []string
}

IndexDescription is used by SQL analysis to extract details about an Index in the database. We can use indexes to know how to get to sorted data easily.

type LimitInfo added in v0.0.7

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

type ManyManyReference

type ManyManyReference struct {
	// AssnTableName is the database table creating the association. NoSQL: The originating table. SQL: The association table
	AssnTableName string
	// AssnColumnName is the column creating the association. NoSQL: The table storing the array of ids on the other end. SQL: the column in the association table pointing towards us.
	AssnColumnName string

	// AssociatedTableName is the database table being linked. NoSQL & SQL: The table we are joining to
	AssociatedTableName string
	// AssociatedColumnName is the database column being linked. NoSQL: table point backwards to us. SQL: Column in association table pointing forwards to refTable
	AssociatedColumnName string
	// AssociatedObjectName is the go name of the object created by this reference
	AssociatedObjectName string

	// GoName is the name used to refer to an object on the other end of the reference.
	GoName string
	// GoPlural is the name used to refer to the group of objects on the other end of the reference.
	GoPlural string

	// IsTypeAssociation is true if this is a many-many relationship with a type table
	IsTypeAssociation bool
	// Options are the key-value options taken from the Comments in the association table, if there is one.
	Options maps.SliceMap

	// MM is the many-many reference on the other end of the relationship that points back to this one.
	MM *ManyManyReference
}

The ManyManyReference structure is used by the templates during the codegen process to describe a many-to-many relationship.

func (*ManyManyReference) JsonKey added in v0.1.1

func (*ManyManyReference) ObjName added in v0.1.1

type Mysql5

type Mysql5 struct {
	SqlDb
	// contains filtered or unexported fields
}

Mysql5 is the goradd driver for mysql databases. It works through the excellent go-sql-driver driver, to supply functionality above go's built in driver. To use it, call NewMysql5, but afterwards, work through the DB parent interface so that the underlying database can be swapped out later if needed.

Timezones Timezones are always tricky. Mysql has some interesting quirks:

  • Datetime types are internally stored in the timezone of the server, and then returned based on the

timezone of the client.

  • Timestamp types are internally stored in UTC and returned in the timezone of the client.

The benefit of this is that you can move your database to a server in another timezone, and the times will automatically change to the correct timezone.

  • The mysql-go-driver has the ability to set a default timezone in the Loc configuration parameter

It appears to convert all times to this timezone before sending them to the database, and then when receiving times, it will set this as the timezone of the date.

These issues are further compounded by the fact that MYSQL can initialize date and time values to what it believes is the current date and time in its server's timezone, but will not save the timezone itself.

So, as a general rule, use DATETIME types to represent a date combined with a time, like an appointment in a calendar or a recurring event that happens in whatever the current timezone is. Use TIMESTAMP types to store data that records when an event happened in world time.

Also, set the Loc configuration parameter to be the same as the server's timezone. By default its UTC. That will make it so all dates and times are in the same timezone as those automatically generated by MYSQL. It is best to set this and your database to UTC, as this will make your database portable to other timezones.

Set the ParseTime configuration parameter to TRUE so that the driver will parse the times into the correct timezone, navigating the GO server and database server timezones. Otherwise, we can only assume that the database is in UTC time, since we will not get any timezone info from the server.

Since the driver will return times in the timezone of the mysql server, our own sql driver will convert these to local time. This will mean that you can save data in local time, and you will receive data in local time in your app, but you need to be aware that when you view the data in the SQL, it will appear in whatever timezone the MYSQL server is set to.

func NewMysql5

func NewMysql5(dbKey string, params string, config *mysql.Config) *Mysql5

New Mysql5 returns a new Mysql5 database object that you can add to the datastore.

func (*Mysql5) Delete

func (m *Mysql5) Delete(ctx context.Context, table string, pkName string, pkValue interface{})

Delete deletes the indicated record from the database.

func (*Mysql5) Describe

func (m *Mysql5) Describe() *DatabaseDescription

Describe returns the database description object

func (*Mysql5) Insert

func (m *Mysql5) Insert(ctx context.Context, table string, fields map[string]interface{}) string

Insert inserts the given data as a new record in the database. It returns the record id of the new record.

func (*Mysql5) NewBuilder

func (m *Mysql5) NewBuilder() QueryBuilderI

NewBuilder returns a new query builder to build a query that will be processed by the database.

func (*Mysql5) Update

func (m *Mysql5) Update(ctx context.Context, table string, fields map[string]interface{}, pkName string, pkValue string)

Update sets a record that already exists in the database to the given data.

type ProfileEntry

type ProfileEntry struct {
	DbKey     string
	BeginTime time.Time
	EndTime   time.Time
	Typ       string
	Sql       string
}

ProfileEntry contains the data collected during sql profiling

func GetProfiles

func GetProfiles(ctx context.Context) []ProfileEntry

GetProfiles returns currently collected profile information TODO: Move profiles to a session variable so we can access ajax queries too

type QueryBuilder added in v0.0.7

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

QueryBuilder is a helper to implement the QueryBuilderI interface above in various builder classes. It primarily gathers up the builder instructions as the query is built. It leaves the implementation of the functions that actually query a database -- Load, Delete, Count -- to the containing structure.

func (*QueryBuilder) Alias added in v0.0.7

func (b *QueryBuilder) Alias(name string, n NodeI) QueryBuilderI

Add a node that is given a manual alias name. This is usually some kind of operation, but it can be any Aliaser kind of node.

func (*QueryBuilder) Condition added in v0.0.7

func (b *QueryBuilder) Condition(c NodeI) QueryBuilderI

Condition adds the condition of the Where clause. If a condition already exists, it will be anded to the previous condition.

func (*QueryBuilder) Count added in v0.0.7

func (b *QueryBuilder) Count(ctx context.Context, distinct bool, nodes ...NodeI) uint

func (*QueryBuilder) Delete added in v0.0.7

func (b *QueryBuilder) Delete(ctx context.Context)

func (*QueryBuilder) Distinct added in v0.0.7

func (b *QueryBuilder) Distinct() QueryBuilderI

Distinct sets the distinct bit, causing the query to not return duplicates.

func (*QueryBuilder) Expand added in v0.0.7

func (b *QueryBuilder) Expand(n NodeI) QueryBuilderI

Expands an array type node so that it will produce individual rows instead of an array of items

func (*QueryBuilder) GroupBy added in v0.0.7

func (b *QueryBuilder) GroupBy(nodes ...NodeI) QueryBuilderI

GroupBy sets the nodes that are grouped. According to SQL rules, these then are the only nodes that can be selected, and they MUST be selected.

func (*QueryBuilder) Having added in v0.0.7

func (b *QueryBuilder) Having(node NodeI) QueryBuilderI

Having adds a HAVING condition, which is a filter that acts on the results of a query. In particular its useful for filtering after aggregate functions have done their work.

func (*QueryBuilder) Init added in v0.0.7

func (b *QueryBuilder) Init(self QueryBuilderI)

Init initializes the QueryBuilderBase by saving a copy of the subclass to return for each of the calls for chaining

func (*QueryBuilder) Join added in v0.0.7

func (b *QueryBuilder) Join(n NodeI, condition NodeI) QueryBuilderI

Join will attach the given reference node to the builder

func (*QueryBuilder) Limit added in v0.0.7

func (b *QueryBuilder) Limit(maxRowCount int, offset int) QueryBuilderI

Limit sets the limit parameters of what is returned.

func (*QueryBuilder) Load added in v0.0.7

func (b *QueryBuilder) Load(ctx context.Context) []map[string]interface{}

func (*QueryBuilder) OrderBy added in v0.0.7

func (b *QueryBuilder) OrderBy(nodes ...NodeI) QueryBuilderI

OrderBy adds the order by nodes. If these are table type nodes, the primary key of the table will be used. These nodes can be modified using Ascending and Descending calls.

func (*QueryBuilder) Select added in v0.0.7

func (b *QueryBuilder) Select(nodes ...NodeI) QueryBuilderI

Select specifies what specific nodes are selected. This is an optimization in order to limit the amount of data returned by the query. Without this, the query will expand all the join items to return every column of each table joined.

func (*QueryBuilder) Subquery added in v0.0.7

func (b *QueryBuilder) Subquery() *SubqueryNode

Subquery adds a subquery node, which is like a mini query builder that should result in a single value.

type QueryExport added in v0.0.7

type QueryExport struct {
	Joins      []NodeI
	OrderBys   []NodeI
	Condition  NodeI
	Distinct   bool
	AliasNodes *maps.SliceMap
	// Adds a COUNT(*) to the select list
	GroupBys   []NodeI
	Selects    []NodeI
	LimitInfo  *LimitInfo
	Having     NodeI
	IsSubquery bool
}

func ExportQuery added in v0.0.7

func ExportQuery(b *QueryBuilder) *QueryExport

type QueryOperation added in v0.0.9

type QueryOperation int

type Rest added in v0.0.9

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

func NewRest added in v0.0.9

func NewRest(dbKey string, url string) *Rest

NewRest returns a new Rest goradd database object that you can add to the datastore.

func (*Rest) Begin added in v0.0.9

func (r *Rest) Begin(ctx context.Context) (txid TransactionID)

func (*Rest) Commit added in v0.0.9

func (r *Rest) Commit(ctx context.Context, txid TransactionID)

Commit commits the transaction, and if an error occurs, will panic with the error.

func (*Rest) Delete added in v0.0.9

func (r *Rest) Delete(ctx context.Context, table string, pkName string, pkValue string) (err error)

Delete deletes the indicated record from the database.

func (*Rest) Describe added in v0.0.9

func (r *Rest) Describe() *DatabaseDescription

Describe returns the database description object. Rest databases are not describable at this point. Maybe someday.

func (*Rest) Get added in v0.0.9

func (r *Rest) Get(ctx context.Context, jsonRequest []byte) (result []map[string]interface{}, err error)

func (*Rest) Insert added in v0.0.9

func (r *Rest) Insert(ctx context.Context, table string, fields map[string]interface{}) (id string, err error)

Insert inserts the given data as a new record in the database.

func (*Rest) NewBuilder added in v0.0.9

func (r *Rest) NewBuilder() QueryBuilderI

NewBuilder returns a new query builder to build a query that will be processed by the database.

func (*Rest) Rollback added in v0.0.9

func (r *Rest) Rollback(ctx context.Context, txid TransactionID)

Rollback will rollback the transaction if the transaction is still pointing to the given txid. This gives the effect that if you call Rollback on a transaction that has already been committed, no Rollback will happen. This makes it easier to implement a transaction management scheme, because you simply always defer a Rollback after a Begin. Pass the txid that you got from the Begin to the Rollback

func (*Rest) Update added in v0.0.9

func (r *Rest) Update(ctx context.Context, table string, fields map[string]interface{}, pkName string, pkValue string)

Update sets a record that already exists in the database to the given data, updating only the fields given.

type RestBuilderExport added in v0.0.9

type RestBuilderExport struct {
	QueryExport
	Op QueryOperation
}

type ReverseReference

type ReverseReference struct {
	// DbTable is the database table on the "one" end of the relationship. Its the table that the ReverseReference belongs to.
	DbTable string
	// DbColumn is the database column that is referred to from the many end. This is most likely the primary key of DbTable.
	DbColumn string
	// AssociatedTableName is the table on the "many" end that is pointing to the table containing the ReverseReference.
	AssociatedTableName string
	// AssociatedColumnName is the column on the "many" end that is pointing to the table containing the ReverseReference. It is a foreign-key.
	AssociatedColumnName string
	// GoName is the name used to represent an object in the reverse relationship
	GoName string
	// GoPlural is the name used to represent the group of objects in the reverse relationship
	GoPlural string
	// GoType is the type of object in the collection of "many" objects, which corresponds to the name of the struct corresponding to the table
	GoType string
	// GoTypePlural is the plural of the type of object in the collection of "many" objects
	GoTypePlural string
	// IsUnique is true if the ReverseReference is unique. A unique reference creates a one-to-one relationship rather than one-to-many
	IsUnique bool
}

ReverseReference represents a kind of virtual column that is a result of a foreign-key pointing back to this column. This is the "one" side of a one-to-many relationship. Or, if the relationship is unique, this creates a one-to-one relationship. In SQL, since there is only a one-way foreign key, the side being pointed at does not have any direct data in a table indicating the relationship. We create a ReverseReference during data analysis and include it with the table description so that the table can know about the relationship and use it when doing queries.

func (*ReverseReference) AssociatedGoName added in v0.1.1

func (r *ReverseReference) AssociatedGoName() string

AssociatedGoName returns the name of the column that is pointing back to us. The name returned is the Go name that we could use to name the referenced object.

func (*ReverseReference) JsonKey added in v0.1.1

func (*ReverseReference) MapName added in v0.1.1

func (r *ReverseReference) MapName() string

func (*ReverseReference) ObjName added in v0.1.1

type SqlContext

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

SqlContext is what is stored in the current context to keep track of queries. You must save a copy of this in the current context with the SqlContext key before calling database functions in order to use transactions or database profiling, or anything else the context is required for. The framework does this for you, but you will need to do this yourself if using the orm without the framework.

type SqlDb

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

SqlDb is a mixin to specific SQL database driver that implements common code needed by all SQL database drivers.

func NewSqlDb

func NewSqlDb(dbKey string) SqlDb

NewSqlDb creates a default SqlDb mixin.

func (*SqlDb) AssociatedObjectPrefix

func (s *SqlDb) AssociatedObjectPrefix() string

SetAssociatedObjectPrefix returns the prefix string used in code generation to indicate a variable is a database object.

func (*SqlDb) AssociationTableSuffix

func (s *SqlDb) AssociationTableSuffix() string

AssociationTableSuffix returns the suffix used to identify association tables.

func (*SqlDb) Begin

func (s *SqlDb) Begin(ctx context.Context) (txid TransactionID)

Begin starts a transaction. You should immediately defer a Rollback using the returned transaction id. If you Commit before the Rollback happens, no Rollback will occur.

func (*SqlDb) Commit

func (s *SqlDb) Commit(ctx context.Context, txid TransactionID)

Commit commits the transaction, and if an error occurs, will panic with the error.

func (*SqlDb) DbKey

func (s *SqlDb) DbKey() string

DbKey returns the database key used in the datastore.

func (*SqlDb) Exec

func (s *SqlDb) Exec(ctx context.Context, sql string, args ...interface{}) (r sql.Result, err error)

Exec executes the given SQL code, without returning any result rows.

func (*SqlDb) IdSuffix

func (s *SqlDb) IdSuffix() string

IdSuffix is the suffix used to indicate that a field is a foreign ky to another table.

func (*SqlDb) Query

func (s *SqlDb) Query(ctx context.Context, sql string, args ...interface{}) (r *sql.Rows, err error)

Query executes the given sql, and returns a row result set.

func (*SqlDb) Rollback

func (s *SqlDb) Rollback(ctx context.Context, txid TransactionID)

Rollback will rollback the transaction if the transaction is still pointing to the given txid. This gives the effect that if you call Rollback on a transaction that has already been committed, no Rollback will happen. This makes it easier to implement a transaction management scheme, because you simply always defer a Rollback after a Begin. Pass the txid that you got from the Begin to the Rollback

func (*SqlDb) SetAssociatedObjectPrefix

func (s *SqlDb) SetAssociatedObjectPrefix(prefix string)

SetAssociatedObjectPrefix sets the prefix string used in code generation to indicate a variable is a database object.

func (*SqlDb) SetAssociationTableSuffix

func (s *SqlDb) SetAssociationTableSuffix(suffix string)

SetAssociationTableSuffix sets the suffix used to identify association tables.

func (*SqlDb) SetTypeTableSuffix

func (s *SqlDb) SetTypeTableSuffix(suffix string)

SetTypeTableSuffix sets the suffix used to identify type tables.

func (*SqlDb) StartProfiling

func (s *SqlDb) StartProfiling()

StartProfiling will start the database profiling process.

func (*SqlDb) TypeTableSuffix

func (s *SqlDb) TypeTableSuffix() string

TypeTableSuffix returns the suffix used to identify type tables.

type SqlDbI

type SqlDbI interface {
	// Exec executes a query that does not expect to return values
	Exec(ctx context.Context, sql string, args ...interface{}) (r sql.Result, err error)
	// Exec executes a query that returns values
	Query(ctx context.Context, sql string, args ...interface{}) (r *sql.Rows, err error)
	// TypeTableSuffix returns the suffix used in a table name to indicate that the table is a type table. By default this is "_type".
	TypeTableSuffix() string
	// AssociationTableSuffix returns the suffix used in a table name to indicate that the table is an association table. By default this is "_assn".
	AssociationTableSuffix() string
	// contains filtered or unexported methods
}

The SqlDbI interface describes the interface that a sql database needs to implement so that it will work with the sqlBuilder object.

type SqlReceiver

type SqlReceiver struct {
	R interface{}
}

SqlReceiver is an encapsulation of a way of receiving data from sql queries as interface{} pointers. This allows you to get data without knowing the type of data you are asking for ahead of time, and is easier for dealing with NULL fields. Some database drivers (MySql for one) return different results in fields depending on how you call the query (using a prepared statement can return different results than without one), or if the data does not quite fit (UInt64 in particular will return a string if the returned value is bigger than MaxInt64, but smaller than MaxUint64.)

Pass the address of the R member to the sql.Scan method when using an object of this type, because there are some idiosyncracies with how Go treats return values that prevents returning an address of R from a function

func (SqlReceiver) BoolI

func (r SqlReceiver) BoolI() interface{}

BoolI returns the value as an interface to a boolean

func (SqlReceiver) DoubleI

func (r SqlReceiver) DoubleI() interface{}

DoubleI returns the value as a float64 interface

func (SqlReceiver) FloatI

func (r SqlReceiver) FloatI() interface{}

FloatI returns the value as an interface to a float32 value.

func (SqlReceiver) Int64I

func (r SqlReceiver) Int64I() interface{}

Returns the given value as an interface to an Int64

func (SqlReceiver) IntI

func (r SqlReceiver) IntI() interface{}

func (SqlReceiver) StringI

func (r SqlReceiver) StringI() interface{}

StringI returns the value as an interface to a string

func (SqlReceiver) TimeI

func (r SqlReceiver) TimeI() interface{}

TimeI returns the value as a datetime.DateTime value in the server's timezone.

func (SqlReceiver) Uint64I

func (r SqlReceiver) Uint64I() interface{}

Some drivers (like MySQL) return all integers as Int64. This converts to uint64. Its up to you to make sure you only use this on 64-bit uints or smaller.

func (SqlReceiver) UintI

func (r SqlReceiver) UintI() interface{}

Some drivers (like MySQL) return all integers as Int64. This converts a value to a GO uint. Its up to you to make sure you only use this on 32-bit uints or smaller

func (SqlReceiver) Unpack

func (r SqlReceiver) Unpack(typ GoColumnType) interface{}

Unpack converts a SqlReceiver to a type corresponding to the given GoColumnType

type TableDescription

type TableDescription struct {
	// DbKey is the key used to find the database in the global database cluster
	DbKey string
	// DbName is the name of the database table or object in the database.
	DbName string
	// LiteralName is the name of the object when describing it to the world. Use the "literalName" option in the comment to override the default. Should be lower case.
	LiteralName string
	// LiteralPlural is the plural name of the object. Use the "literalPlural" option in the comment to override the default. Should be lower case.
	LiteralPlural string
	// GoName is name of the struct when referring to it in go code. Use the "goName" option in the comment to override the default.
	GoName string
	// GoPlural is the name of a collection of these objects when referring to them in go code. Use the "goPlural" option in the comment to override the default.
	GoPlural string
	// LcGoName is the same as GoName, but with first letter lower case.
	LcGoName string
	// Columns is a list of ColumnDescriptions, one for each column in the table.
	Columns []*ColumnDescription

	// Indexes are the indexes defined in the database. Unique indexes will result in LoadBy* functions.
	Indexes []IndexDescription
	// Options are key-value pairs of values that can be used to customize how code generation is performed
	Options maps.SliceMap
	// IsType is true if this is a type table
	IsType bool
	// IsAssociation is true if this is an association table, which is used to create a many-to-many relationship between two tables.
	IsAssociation bool
	// Comment is the general comment included in the database
	Comment string

	// ManyManyReferences describe the many-to-many references pointing to this table
	ManyManyReferences []*ManyManyReference
	// ReverseReferences describes the many-to-one references pointing to this table
	ReverseReferences []*ReverseReference
	// HasDateTime is true if the table contains a DateTime column.
	HasDateTime bool
	// PrimaryKeyColumn points to the column that contains the primary key of the table.
	PrimaryKeyColumn *ColumnDescription

	// Skip will cause the table to be skipped in code generation
	Skip bool
	// contains filtered or unexported fields
}

func GetTableDescription

func GetTableDescription(key string, goTypeName string) *TableDescription

GetTableDescription returns a table description given a database key and the struct name corresponding to the table. You must call AnalyzeDatabases first to use this.

func NewTableDescription

func NewTableDescription(tableName string) *TableDescription

NewTableDescription returns a new table description

func (*TableDescription) GetColumn

func (td *TableDescription) GetColumn(name string) *ColumnDescription

GetColumn returns a ColumnDescription given the name of a column

type TransactionID

type TransactionID int

type TypeTableDescription

type TypeTableDescription struct {
	// DbKey is the key used to find the database in the global database cluster
	DbKey string
	// DbName is the name of the table in the database
	DbName string
	// EnglishName is the english name of the object when describing it to the world. Use the "literalName" option in the comment to override the default.
	EnglishName string
	// EnglishPlural is the plural english name of the object. Use the "literalPlural" option in the comment to override the default.
	EnglishPlural string
	// GoName is the name of the item as a go type name.
	GoName string
	// GoPlural is the plural of the go type
	GoPlural string
	// LcGoName is the lower case version of the go name
	LcGoName string
	// FieldNames are the names of the fields defined in the table. The first field name MUST be the name of the id field, and 2nd MUST be the name of the name field, the others are optional extra fields.
	FieldNames []string
	// FieldTypes are the go column types of the fields, indexed by field name
	FieldTypes map[string]GoColumnType
	// Values are the constant values themselves as defined in the table, mapped to field names in each row.
	Values []map[string]interface{}
	// PkField is the name of the private key field
	PkField string

	// Filled in by analyzer
	Constants map[uint]string
}

TypeTableDescription describes a type table, which essentially defines an enumerated type. In the SQL world, they are a table with an integer key (starting index 1) and a "name" value, though they can have other values associated with them too. Goradd will maintain the relationships in SQL, but in a No-SQL situation, it will embed all the ids and values.

func GetTypeTableDescription

func GetTypeTableDescription(key string, goTypeName string) *TypeTableDescription

GetTypeTableDescription returns a type table description given a database key and the struct name corresponding to the table. You must call AnalyzeDatabases first to use this.

func (*TypeTableDescription) FieldGoColumnType added in v0.0.3

func (tt *TypeTableDescription) FieldGoColumnType(i int) GoColumnType

FieldGoColumnType returns the GoColumnType corresponding to the given field offset

func (*TypeTableDescription) FieldGoName

func (tt *TypeTableDescription) FieldGoName(i int) string

FieldGoName returns the go name corresponding to the given field offset

type ValueMap

type ValueMap map[string]interface{}

func NewValueMap

func NewValueMap() ValueMap

func (ValueMap) Copy

func (m ValueMap) Copy() interface{}

Support the deep copy interface

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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