orm

package module
v1.2.4 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2022 License: MIT Imports: 13 Imported by: 0

README

GoDoc CI CodeQL Go Report Card Coverage Status

Golobby ORM

GoLobby ORM is a lightweight yet powerful, fast, customizable, type-safe object-relational mapper for the Go programming language.

Table Of Contents

Introduction

GoLobby ORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using Golobby ORM, each database table has a corresponding "Entity" to interact with that table using elegant APIs.

Features

  • Elegant and easy-to-use APIs with the help of Generics.
  • Type-safety.
  • Using reflection at startup to be fast during runtime.
  • No code generation!
  • Query builder for various query types.
  • Binding query results to entities.
  • Supports different kinds of relationship/Association types:
    • One to one
    • One to Many
    • Many to Many

Performance

You can run performance benchmark against GORM using

make bench

here are results from my laptop

goos: darwin
goarch: arm64
pkg: github.com/golobby/orm/benchmark
BenchmarkGolobby
BenchmarkGolobby-8        235956              4992 ns/op            2192 B/op         66 allocs/op
BenchmarkGorm
BenchmarkGorm-8            54498             21308 ns/op            7208 B/op        147 allocs/op
PASS
ok      github.com/golobby/orm/benchmark        3.118s

Quick Start

The following example demonstrates how to use the GoLobby ORM.

package main

import "github.com/golobby/orm"

// User entity
type User struct {
  ID        int64
  FirstName string
  LastName  string
  Email     string
  orm.Timestamps
}

// It will be called by ORM to setup entity.
func (u User) ConfigureEntity(e *orm.EntityConfigurator) {
    // Specify related database table for the entity.
    e.Table("users")
}

func main() {
  // Setup ORM
  err := orm.Initialize(orm.ConnectionConfig{
    // Name:          "default",  // Optional. Specify connection names if you have more than on database.
    Driver:           "sqlite3",  // Database type. Currently supported sqlite3, mysql, mariadb, postgresql. 
    ConnectionString: ":memory:", // Database DSN.
    DatabaseValidations: true,    // Validates your database tables and each table schema
  })
  
  if err != nil {
	  panic(err)
  }
  
  // Find user by primary key (ID)
  user, err := orm.Find[User](1)
  
  // Update entity
  user.Email = "jack@mail.com"
  
  // Save entity
  orm.Save(&user)
}
Creating a new Entity

Let's create a new Entity to represent User in our application.

package main

import "github.com/golobby/orm"

type User struct {
  ID       int64
  Name     string
  LastName string
  Email    string
  orm.Timestamps
}

func (u User) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Table("users").
      Connection("default") // You can omit connection name if you only have one.
	
}

As you see, our user entity is nothing else than a simple struct and two methods. Entities in GoLobby ORM are implementations of Entity interface, which defines two methods:

  • ConfigureEntity: configures table, fields, and also relations to other entities.
Conventions

We have standard conventions and we encourage you to follow, but if you want to change them for any reason you can use Field method to customize how ORM inferres meta data from your Entity.

Column names

GoLobby ORM for each struct field(except slice, arrays, maps, and other nested structs) assumes a respective column named using snake case syntax. If you want a custom column name, you should specify it in ConfigureEntity method using Field() method.

package main

type User struct {
  Name string
}

func (u User) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Field("Name").ColumnName("custom_name_for_column")

    e.Table("users")
}
Timestamps

for having created_at, updated_at, deleted_at timestamps in your entities you can embed orm.Timestamps struct in your entity,

type User struct {
  ID       int64
  Name     string
  LastName string
  Email    string
  orm.Timestamps
}

Also, if you want custom names for them, you can do it like this.

type User struct {
    ID       int64
    Name     string
    LastName string
    Email    string
    MyCreatedAt sql.NullTime
    MyUpdatedAt sql.NullTime
    MyDeletedAt sql.NullTime
}
func (u User) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Field("MyCreatedAt").IsCreatedAt() // this will make ORM to use MyCreatedAt as created_at column
    e.Field("MyUpdatedAt").IsUpdatedAt() // this will make ORM to use MyUpdatedAt as created_at column
    e.Field("MyDeletedAt").IsDeletedAt() // this will make ORM to use MyDeletedAt as created_at column

    e.Table("users")
}

As always you use Field method for configuring how ORM behaves to your struct field.

Primary Key

GoLobby ORM assumes that each entity has a primary key named id; if you want a custom primary key called, you need to specify it in entity struct.

package main

type User struct {
	PK int64
}
func (u User) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Field("PK").IsPrimaryKey() // this will make ORM use PK field as primary key.
    e.Table("users")
}
Initializing ORM

After creating our entities, we need to initialize GoLobby ORM.

package main

import "github.com/golobby/orm"

func main() {
  orm.Initialize(orm.ConnectionConfig{
    // Name:             "default", You should specify connection name if you have multiple connections
    Driver:           "sqlite3",
    ConnectionString: ":memory:",
  })
}

After this step, we can start using ORM.

Fetching an entity from a database

GoLobby ORM makes it trivial to fetch entities from a database using its primary key.

user, err := orm.Find[User](1)

orm.Find is a generic function that takes a generic parameter that specifies the type of Entity we want to query and its primary key value. You can also use custom queries to get entities from the database.


user, err := orm.Query[User]().Where("id", 1).First()
user, err := orm.Query[User]().WherePK(1).First()

GoLobby ORM contains a powerful query builder, which you can use to build Select, Update, and Delete queries, but if you want to write a raw SQL query, you can.

users, err := orm.QueryRaw[User](`SELECT * FROM users`)
Saving entities or Insert/Update

GoLobby ORM makes it easy to persist an Entity to the database using Save method, it's an UPSERT method, if the primary key field is not zero inside the entity it will go for an update query; otherwise, it goes for the insert.

// this will insert entity into the table
err := orm.Save(&User{Name: "Amirreza"}) // INSERT INTO users (name) VALUES (?) , "Amirreza"
// this will update entity with id = 1
orm.Save(&User{ID: 1, Name: "Amirreza2"}) // UPDATE users SET name=? WHERE id=?, "Amirreza2", 1

Also, you can do custom update queries using query builder or raw SQL again as well.

res, err := orm.Query[User]().Where("id", 1).Update(orm.KV{"name": "amirreza2"})
Using raw SQL
_, affected, err := orm.ExecRaw[User](`UPDATE users SET name=? WHERE id=?`, "amirreza", 1)
Deleting entities

It is also easy to delete entities from a database.

err := orm.Delete(user)

You can also use query builder or raw SQL.

_, affected, err := orm.Query[Post]().WherePK(1).Delete()

_, affected, err := orm.Query[Post]().Where("id", 1).Delete()

_, affected, err := orm.ExecRaw[Post](`DELETE FROM posts WHERE id=?`, 1)
Relationships

GoLobby ORM makes it easy to have entities that have relationships with each other. Configuring relations is using ConfigureEntity method, as you will see.

HasMany
type Post struct {}

func (p Post) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Table("posts").HasMany(&Comment{}, orm.HasManyConfig{})
}

As you can see, we are defining a Post entity that has a HasMany relation with Comment. You can configure how GoLobby ORM queries HasMany relation with orm.HasManyConfig object; by default, it will infer all fields for you. Now you can use this relationship anywhere in your code.

comments, err := orm.HasMany[Comment](post).All()

HasMany and other related functions in GoLobby ORM return QueryBuilder, and you can use them like other query builders and create even more complex queries for relationships. for example, you can start a query to get all comments of a post made today.

todayComments, err := orm.HasMany[Comment](post).Where("created_at", "CURDATE()").All()
HasOne

Configuring a HasOne relation is like HasMany.

type Post struct {}

func (p Post) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Table("posts").HasOne(&HeaderPicture{}, orm.HasOneConfig{})
}

As you can see, we are defining a Post entity that has a HasOne relation with HeaderPicture. You can configure how GoLobby ORM queries HasOne relation with orm.HasOneConfig object; by default, it will infer all fields for you. Now you can use this relationship anywhere in your code.

picture, err := orm.HasOne[HeaderPicture](post)

HasOne also returns a query builder, and you can create more complex queries for relations.

BelongsTo
type Comment struct {}

func (c Comment) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Table("comments").BelongsTo(&Post{}, orm.BelongsToConfig{})
}

As you can see, we are defining a Comment entity that has a BelongsTo relation with Post that we saw earlier. You can configure how GoLobby ORM queries BelongsTo relation with orm.BelongsToConfig object; by default, it will infer all fields for you. Now you can use this relationship anywhere in your code.

post, err := orm.BelongsTo[Post](comment).First()
BelongsToMany
type Post struct {}

func (p Post) ConfigureEntity(e *orm.EntityConfigurator) {
    e.Table("posts").BelongsToMany(&Category{}, orm.BelongsToManyConfig{IntermediateTable: "post_categories"})
}

type Category struct{}

func(c Category) ConfigureEntity(r *orm.EntityConfigurator) {
    e.Table("categories").BelongsToMany(&Post{}, orm.BelongsToManyConfig{IntermediateTable: "post_categories"})
}

We are defining a Post entity and a Category entity with a many2many relationship; as you can see, we must configure the IntermediateTable name, which GoLobby ORM cannot infer. Now you can use this relationship anywhere in your code.

categories, err := orm.BelongsToMany[Category](post).All()
Saving with relation

You may need to save an entity that has some kind of relationship with another entity; in that case, you can use Add method.

orm.Add(post, comments...) // inserts all comments passed in and also sets all post_id to the primary key of the given post.
orm.Add(post, categories...) // inserts all categories and also insert intermediate post_categories records.
Query Builder

GoLobby ORM contains a powerful query builder to help you build complex queries with ease. QueryBuilder is accessible from orm.Query[Entity] method which will create a new query builder for you with given type parameter. Query builder can build SELECT,UPDATE,DELETE queries for you.

Finishers

Finishers are methods on QueryBuilder that will some how touch database, so use them with caution.

All

All will generate a SELECT query from QueryBuilder, execute it on database and return results in a slice of OUTPUT. It's useful for queries that have multiple results.

posts, err := orm.Query[Post]().All() 
Get

Get will generate a SELECT query from QueryBuilder, execute it on database and return results in an instance of type parameter OUTPUT. It's useful for when you know your query has single result.

post, err := orm.Query[Post]().First().Get()
Update

Update will generate an UPDATE query from QueryBuilder and executes it, returns rows affected by query and any possible error.

rowsAffected, err := orm.Query[Post]().WherePK(1).Set("body", "body jadid").Update()
Delete

Delete will generate a DELETE query from QueryBuilder and executes it, returns rows affected by query and any possible error.

rowsAffected, err := orm.Query[Post]().WherePK(1).Delete()
Select

Let's start with Select queries. Each Select query consists of following:

SELECT [column names] FROM [table name] WHERE [cond1 AND/OR cond2 AND/OR ...] ORDER BY [column] [ASC/DESC] LIMIT [N] OFFSET [N] GROUP BY [col]

Query builder has methods for constructing each part, of course not all of these parts are necessary.

Column names

for setting column names to select use Select method as following:

orm.Query[Post]().Select("id", "title")
Table

for setting table name for select use Table method as following:

orm.Query[Post]().Table("users")
Where

for adding where conditions based on what kind of where you want you can use any of following:

orm.Query[Post]().Where("name", "amirreza") // Equal mode: WHERE name = ?, ["amirreza"]
orm.Query[Post]().Where("age", "<", 19) // Operator mode: WHERE age < ?, [19]
orm.Query[Post]().WhereIn("id", 1,2,3,4,5) // WhereIn: WHERE id IN (?,?,?,?,?), [1,2,3,4,5]

You can also chain these together.

orm.Query[Post]().
	Where("name", "amirreza").
	AndWhere("age", "<", 10).
	OrWhere("id", "!=", 1)
    // WHERE name = ? AND age < ? OR id != ?, ["amirreza", 10, 1]
Order By

You can set order by of query using OrderBy as following.

orm.Query[Post]().OrderBy("id", orm.ASC) // ORDER BY id ASC
orm.Query[Post]().OrderBy("id", orm.DESC) // ORDER BY id DESC
Limit

You can set limit setting of query using Limit as following

orm.Query[Post]().Limit1(1) // LIMIT 1
Offset

You can set limit setting of query using Offset as following

orm.Query[Post]().Offset(1) // OFFSET 1
First, Latest

You can use First, Latest method which are also executers of query as you already seen to get first or latest record.

orm.Query[Post]().First() // SELECT * FROM posts ORDER BY id ASC LIMIT 1
orm.Query[Post]().Latest() // SELECT * FROM posts ORDER BY id DESC LIMIT 1
Update

Each Update query consists of following:

UPDATE [table name] SET [col=val] WHERE [cond1 AND/OR cond2 AND/OR ...]
Where

Just like select where stuff, same code.

Table

Same as select.

Set

You can use Set method to set value.

orm.Query[Message]().
  Where("id", 1).
  Set("read", true, "seen", true).
  Update() // UPDATE posts SET read=?, seen=? WHERE id = ?, [true, true, 1]
Delete

Each Delete query consists of following:

DELETE FROM [table name] WHERE [cond1 AND/OR cond2 AND/OR ...]
Table

Same as Select and Update.

Where

Same as Select and Update.

Database Validations

Golobby ORM can validate your database state and compare it to your entities and if your database and code are not in sync give you error. Currently there are two database validations possible:

  1. Validate all necessary tables exists.
  2. Validate all tables contain necessary columns. You can enable database validations feature by enabling DatabaseValidations flag in your ConnectionConfig.
return orm.SetupConnections(orm.ConnectionConfig{
    Name:                    "default",
    DB:                      db,
    Dialect:                 orm.Dialects.SQLite3,
    Entities:                []orm.Entity{&Post{}, &Comment{}, &Category{}, &HeaderPicture{}},
    DatabaseValidations: true,
  })

License

GoLobby ORM is released under the MIT License.

Documentation

Index

Constants

View Source
const (
	ASC  = "ASC"
	DESC = "DESC"
)
View Source
const (
	JoinTypeInner = "INNER"
	JoinTypeLeft  = "LEFT"
	JoinTypeRight = "RIGHT"
	JoinTypeFull  = "FULL OUTER"
	JoinTypeSelf  = "SELF"
)
View Source
const (
	Eq      = "="
	GT      = ">"
	LT      = "<"
	GE      = ">="
	LE      = "<="
	NE      = "!="
	Between = "BETWEEN"
	Like    = "LIKE"
	In      = "IN"
)

Variables

View Source
var Dialects = &struct {
	MySQL      *Dialect
	PostgreSQL *Dialect
	SQLite3    *Dialect
}{
	MySQL: &Dialect{
		DriverName:                  "mysql",
		PlaceholderChar:             "?",
		IncludeIndexInPlaceholder:   false,
		AddTableNameInSelectColumns: true,
		PlaceHolderGenerator:        questionMarks,
		QueryListTables:             "SHOW TABLES",
		QueryTableSchema:            "DESCRIBE %s",
	},
	PostgreSQL: &Dialect{
		DriverName:                  "postgres",
		PlaceholderChar:             "$",
		IncludeIndexInPlaceholder:   true,
		AddTableNameInSelectColumns: true,
		PlaceHolderGenerator:        postgresPlaceholder,
		QueryListTables:             `\dt`,
		QueryTableSchema:            `\d %s`,
	},
	SQLite3: &Dialect{
		DriverName:                  "sqlite3",
		PlaceholderChar:             "?",
		IncludeIndexInPlaceholder:   false,
		AddTableNameInSelectColumns: false,
		PlaceHolderGenerator:        questionMarks,
		QueryListTables:             "SELECT name FROM sqlite_schema WHERE type='table'",
		QueryTableSchema:            `SELECT name,type,"notnull","dflt_value","pk" FROM PRAGMA_TABLE_INFO('%s')`,
	},
}

Functions

func Add added in v1.2.0

func Add(to Entity, items ...Entity) error

Add adds `items` to `to` using relations defined between items and to in ConfigureEntity method of `to`.

func Delete added in v1.2.0

func Delete(obj Entity) error

Delete given Entity from database

func ExecRaw added in v1.2.0

func ExecRaw[E Entity](q string, args ...interface{}) (int64, int64, error)

ExecRaw executes given query string and arguments on given type parameter database connection.

func Find added in v1.2.0

func Find[T Entity](id interface{}) (T, error)

Find finds the Entity you want based on generic type and primary key you passed.

func GetConnection added in v1.2.0

func GetConnection(name string) *connection

func Insert added in v1.2.0

func Insert(o Entity) error

Insert given entity into database based on their ConfigureEntity we can find table and also DB name.

func InsertAll added in v1.2.3

func InsertAll(objs ...Entity) error

InsertAll given entities into database based on their ConfigureEntity we can find table and also DB name.

func QueryRaw added in v1.2.0

func QueryRaw[OUTPUT Entity](q string, args ...interface{}) ([]OUTPUT, error)

QueryRaw queries given query string and arguments on given type parameter database connection.

func Raw added in v1.2.0

func Raw(sql string, args ...interface{}) *raw

Raw creates a Raw sql query chunk that you can add to several components of QueryBuilder like Wheres.

func Save added in v1.2.0

func Save(obj Entity) error

Save saves given entity, if primary key is set we will make an update query and if primary key is zero value we will insert it.

func Schematic added in v1.2.0

func Schematic()

Schematic prints all information ORM inferred from your entities in startup, remember to pass your entities in Entities when you call SetupConnections if you want their data inferred otherwise Schematic does not print correct data since GoLobby ORM also incrementally cache your entities metadata and schema.

func SetupConnections added in v1.2.1

func SetupConnections(configs ...ConnectionConfig) error

SetupConnections declares a new connections for ORM.

func Update added in v1.2.0

func Update(obj Entity) error

Update given Entity in database.

Types

type BelongsToConfig added in v1.2.0

type BelongsToConfig struct {
	// OwnerTable is the table that contains owner of a BelongsTo
	// relationship.
	OwnerTable string
	// LocalForeignKey is name of the field that links property
	// to its owner in BelongsTo relation. for example when
	// a Comment BelongsTo Post, LocalForeignKey is
	// post_id of Comment.
	LocalForeignKey string
	// ForeignColumnName is name of the field that LocalForeignKey
	// field value will point to it, for example when
	// a Comment BelongsTo Post, ForeignColumnName is
	// id of Post.
	ForeignColumnName string
}

BelongsToConfig contains all information we need for a BelongsTo relationship BelongsTo is a relationship between a Comment and it's Post, A Comment BelongsTo Post.

type BelongsToManyConfig added in v1.2.0

type BelongsToManyConfig struct {
	// IntermediateTable is the name of the middle table
	// in a BelongsToMany (Many to Many) relationship.
	// for example when we have Post BelongsToMany
	// Category, this table will be post_categories
	// table, remember that this field cannot be
	// inferred.
	IntermediateTable string
	// IntermediatePropertyID is the name of the field name
	// of property foreign key in intermediate table,
	// for example when we have Post BelongsToMany
	// Category, in post_categories table, it would
	// be post_id.
	IntermediatePropertyID string
	// IntermediateOwnerID is the name of the field name
	// of property foreign key in intermediate table,
	// for example when we have Post BelongsToMany
	// Category, in post_categories table, it would
	// be category_id.
	IntermediateOwnerID string
	// Table name of the owner in BelongsToMany relation,
	// for example in Post BelongsToMany Category
	// Owner table is name of Category table
	// for example `categories`.
	OwnerTable string
	// OwnerLookupColumn is name of the field in the owner
	// table that is used in query, for example in Post BelongsToMany Category
	// Owner lookup field would be Category primary key which is id.
	OwnerLookupColumn string
}

BelongsToManyConfig contains information that we need for creating many to many queries.

type ConnectionConfig added in v1.2.0

type ConnectionConfig struct {
	// Name of your database connection, it's up to you to name them anything
	// just remember that having a connection name is mandatory if
	// you have multiple connections
	Name string
	// If you already have an active database connection configured pass it in this value and
	// do not pass Driver and DSN fields.
	DB *sql.DB
	// Which dialect of sql to generate queries for, you don't need it most of the times when you are using
	// traditional databases such as mysql, sqlite3, postgres.
	Dialect *Dialect
	// List of entities that you want to use for this connection, remember that you can ignore this field
	// and GoLobby ORM will build our metadata cache incrementally but you will lose schematic
	// information that we can provide you and also potentialy validations that we
	// can do with the database
	Entities []Entity
	// Database validations, check if all tables exists and also table schemas contains all necessary columns.
	// Check if all infered tables exist in your database
	DatabaseValidations bool
}

type Dialect

type Dialect struct {
	DriverName                  string
	PlaceholderChar             string
	IncludeIndexInPlaceholder   bool
	AddTableNameInSelectColumns bool
	PlaceHolderGenerator        func(n int) []string
	QueryListTables             string
	QueryTableSchema            string
}

type Entity

type Entity interface {
	// ConfigureEntity should be defined for all of your database entities
	// and it can define Table, DB and also relations of your Entity.
	ConfigureEntity(e *EntityConfigurator)
}

Entity defines the interface that each of your structs that you want to use as database entities should have, it's a simple one and its ConfigureEntity.

type EntityConfigurator added in v1.2.0

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

func (*EntityConfigurator) BelongsTo added in v1.2.0

func (ec *EntityConfigurator) BelongsTo(owner Entity, config BelongsToConfig) *EntityConfigurator

func (*EntityConfigurator) BelongsToMany added in v1.2.0

func (ec *EntityConfigurator) BelongsToMany(owner Entity, config BelongsToManyConfig) *EntityConfigurator

func (*EntityConfigurator) Connection added in v1.2.0

func (ec *EntityConfigurator) Connection(name string) *EntityConfigurator

func (*EntityConfigurator) Field added in v1.2.2

func (ec *EntityConfigurator) Field(name string) *FieldConfigurator

func (*EntityConfigurator) HasMany added in v1.2.0

func (ec *EntityConfigurator) HasMany(property Entity, config HasManyConfig) *EntityConfigurator

func (*EntityConfigurator) HasOne added in v1.2.0

func (ec *EntityConfigurator) HasOne(property Entity, config HasOneConfig) *EntityConfigurator

func (*EntityConfigurator) Table added in v1.2.0

func (ec *EntityConfigurator) Table(name string) *EntityConfigurator

type FieldConfigurator added in v1.2.0

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

func (*FieldConfigurator) ColumnName added in v1.2.0

func (fc *FieldConfigurator) ColumnName(name string) *FieldConfigurator

func (*FieldConfigurator) IsCreatedAt added in v1.2.0

func (fc *FieldConfigurator) IsCreatedAt() *FieldConfigurator

func (*FieldConfigurator) IsDeletedAt added in v1.2.0

func (fc *FieldConfigurator) IsDeletedAt() *FieldConfigurator

func (*FieldConfigurator) IsPrimaryKey added in v1.2.0

func (fc *FieldConfigurator) IsPrimaryKey() *FieldConfigurator

func (*FieldConfigurator) IsUpdatedAt added in v1.2.0

func (fc *FieldConfigurator) IsUpdatedAt() *FieldConfigurator

type GroupBy added in v1.2.0

type GroupBy struct {
	Columns []string
}

func (GroupBy) String added in v1.2.0

func (g GroupBy) String() string

type HasManyConfig added in v1.2.0

type HasManyConfig struct {
	// PropertyTable is table of the property of HasMany relationship,
	// consider `Comment` in Post and Comment relationship,
	// each Post HasMany Comment, so PropertyTable is
	// `comments`.
	PropertyTable string
	// PropertyForeignKey is the foreign key field name in the property table,
	// for example in Post HasMany Comment, if comment has `post_id` field,
	// it's the PropertyForeignKey field.
	PropertyForeignKey string
}

HasManyConfig contains all information we need for querying HasMany relationships. We can infer both fields if you have them in standard way but you can specify them if you want custom ones.

type HasOneConfig added in v1.2.0

type HasOneConfig struct {
	// PropertyTable is table of the property of HasOne relationship,
	// consider `HeaderPicture` in Post and HeaderPicture relationship,
	// each Post HasOne HeaderPicture, so PropertyTable is
	// `header_pictures`.
	PropertyTable string
	// PropertyForeignKey is the foreign key field name in the property table,
	// forexample in Post HasOne HeaderPicture, if header_picture has `post_id` field,
	// it's the PropertyForeignKey field.
	PropertyForeignKey string
}

HasOneConfig contains all information we need for a HasOne relationship, it's similar to HasManyConfig.

type Join added in v1.2.0

type Join struct {
	Type  joinType
	Table string
	On    JoinOn
}

func (Join) String added in v1.2.0

func (j Join) String() string

type JoinOn added in v1.2.0

type JoinOn struct {
	Lhs string
	Rhs string
}

func (JoinOn) String added in v1.2.0

func (j JoinOn) String() string

type Limit added in v1.2.0

type Limit struct {
	N int
}

func (Limit) String added in v1.2.0

func (l Limit) String() string

type Offset added in v1.2.0

type Offset struct {
	N int
}

func (Offset) String added in v1.2.0

func (o Offset) String() string

type QueryBuilder added in v1.2.0

type QueryBuilder[OUTPUT any] struct {
	// contains filtered or unexported fields
}

QueryBuilder is our query builder, almost all methods and functions in GoLobby ORM create or configure instance of QueryBuilder.

func BelongsTo added in v1.2.0

func BelongsTo[OWNER Entity](property Entity) *QueryBuilder[OWNER]

BelongsTo configures a QueryBuilder for a BelongsTo relationship between OWNER type parameter and property argument, so property BelongsTo OWNER.

func BelongsToMany added in v1.2.0

func BelongsToMany[OWNER Entity](property Entity) *QueryBuilder[OWNER]

BelongsToMany configures a QueryBuilder for a BelongsToMany relationship

func HasMany added in v1.2.0

func HasMany[PROPERTY Entity](owner Entity) *QueryBuilder[PROPERTY]

HasMany configures a QueryBuilder for a HasMany relationship this relationship will be defined for owner argument that has many of PROPERTY generic type for example HasMany[Comment](&Post{}) is for Post HasMany Comment relationship.

func HasOne added in v1.2.0

func HasOne[PROPERTY Entity](owner Entity) *QueryBuilder[PROPERTY]

HasOne configures a QueryBuilder for a HasOne relationship this relationship will be defined for owner argument that has one of PROPERTY generic type for example HasOne[HeaderPicture](&Post{}) is for Post HasOne HeaderPicture relationship.

func NewQueryBuilder added in v1.2.0

func NewQueryBuilder[OUTPUT any](s *schema) *QueryBuilder[OUTPUT]

func Query added in v1.2.0

func Query[E Entity]() *QueryBuilder[E]

Query creates a new QueryBuilder for given type parameter, sets dialect and table as well.

func (*QueryBuilder[OUTPUT]) All added in v1.2.0

func (q *QueryBuilder[OUTPUT]) All() ([]OUTPUT, error)

All is a finisher, create the Select query based on QueryBuilder and scan results into slice of type parameter E.

func (*QueryBuilder[OUTPUT]) AndWhere added in v1.2.0

func (q *QueryBuilder[OUTPUT]) AndWhere(parts ...interface{}) *QueryBuilder[OUTPUT]

AndWhere appends a where clause to query builder as And where clause.

func (*QueryBuilder[OUTPUT]) Count added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Count() *QueryBuilder[int]

Count creates and execute a select query from QueryBuilder and set it's field list of selection to COUNT(id).

func (*QueryBuilder[OUTPUT]) Delete added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Delete() (rowsAffected int64, err error)

Delete is a finisher, creates a delete query from query builder and executes it.

func (*QueryBuilder[OUTPUT]) First added in v1.2.0

func (q *QueryBuilder[OUTPUT]) First() *QueryBuilder[OUTPUT]

First returns first record of database using OrderBy primary key ascending order.

func (*QueryBuilder[OUTPUT]) FromQuery added in v1.2.0

func (q *QueryBuilder[OUTPUT]) FromQuery(subQuery *QueryBuilder[OUTPUT]) *QueryBuilder[OUTPUT]

FromQuery sets subquery of QueryBuilder to be given subquery so when doing select instead of from table we do from(subquery).

func (*QueryBuilder[OUTPUT]) FullOuterJoin added in v1.2.0

func (q *QueryBuilder[OUTPUT]) FullOuterJoin(table string, onLhs string, onRhs string) *QueryBuilder[OUTPUT]

FullOuterJoin adds a full outer join section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) Get added in v1.2.1

func (q *QueryBuilder[OUTPUT]) Get() (OUTPUT, error)

Get limit results to 1, runs query generated by query builder, scans result into OUTPUT.

func (*QueryBuilder[OUTPUT]) GroupBy added in v1.2.0

func (q *QueryBuilder[OUTPUT]) GroupBy(columns ...string) *QueryBuilder[OUTPUT]

GroupBy adds a group by section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) InnerJoin added in v1.2.0

func (q *QueryBuilder[OUTPUT]) InnerJoin(table string, onLhs string, onRhs string) *QueryBuilder[OUTPUT]

InnerJoin adds a inner join section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) Join added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Join(table string, onLhs string, onRhs string) *QueryBuilder[OUTPUT]

Join adds a inner join section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) Latest added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Latest() *QueryBuilder[OUTPUT]

Latest is like Get but it also do a OrderBy(primary key, DESC)

func (*QueryBuilder[OUTPUT]) LeftJoin added in v1.2.0

func (q *QueryBuilder[OUTPUT]) LeftJoin(table string, onLhs string, onRhs string) *QueryBuilder[OUTPUT]

LeftJoin adds a left join section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) Limit added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Limit(n int) *QueryBuilder[OUTPUT]

Limit adds limit section to query builder.

func (*QueryBuilder[OUTPUT]) Offset added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Offset(n int) *QueryBuilder[OUTPUT]

Offset adds offset section to query builder.

func (*QueryBuilder[OUTPUT]) OrWhere added in v1.2.0

func (q *QueryBuilder[OUTPUT]) OrWhere(parts ...interface{}) *QueryBuilder[OUTPUT]

OrWhere appends a where clause to query builder as Or where clause.

func (*QueryBuilder[OUTPUT]) OrderBy added in v1.2.0

func (q *QueryBuilder[OUTPUT]) OrderBy(column string, how string) *QueryBuilder[OUTPUT]

OrderBy adds an OrderBy section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) RightJoin added in v1.2.0

func (q *QueryBuilder[OUTPUT]) RightJoin(table string, onLhs string, onRhs string) *QueryBuilder[OUTPUT]

RightJoin adds a right join section to QueryBuilder.

func (*QueryBuilder[OUTPUT]) Select added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Select(columns ...string) *QueryBuilder[OUTPUT]

Select adds columns to QueryBuilder select field list.

func (*QueryBuilder[OUTPUT]) Set added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Set(keyValues ...any) *QueryBuilder[OUTPUT]

func (*QueryBuilder[OUTPUT]) SetDelete added in v1.2.0

func (q *QueryBuilder[OUTPUT]) SetDelete() *QueryBuilder[OUTPUT]

func (*QueryBuilder[OUTPUT]) SetDialect added in v1.2.0

func (q *QueryBuilder[OUTPUT]) SetDialect(dialect *Dialect) *QueryBuilder[OUTPUT]

func (*QueryBuilder[OUTPUT]) SetSelect added in v1.2.0

func (q *QueryBuilder[OUTPUT]) SetSelect() *QueryBuilder[OUTPUT]

SetSelect sets query type of QueryBuilder to Select.

func (*QueryBuilder[OUTPUT]) SetUpdate added in v1.2.0

func (q *QueryBuilder[OUTPUT]) SetUpdate() *QueryBuilder[OUTPUT]

func (*QueryBuilder[OUTPUT]) Table added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Table(t string) *QueryBuilder[OUTPUT]

Table sets table of QueryBuilder.

func (*QueryBuilder[OUTPUT]) ToSql added in v1.2.0

func (q *QueryBuilder[OUTPUT]) ToSql() (string, []interface{}, error)

ToSql creates sql query from QueryBuilder based on internal fields it would decide what kind of query to build.

func (*QueryBuilder[OUTPUT]) Update added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Update() (rowsAffected int64, err error)

Update is a finisher, creates an Update query from QueryBuilder and executes in into database, returns

func (*QueryBuilder[OUTPUT]) Where added in v1.2.0

func (q *QueryBuilder[OUTPUT]) Where(parts ...interface{}) *QueryBuilder[OUTPUT]

Where Adds a where clause to query, if already have where clause append to it as AndWhere.

func (*QueryBuilder[OUTPUT]) WhereIn added in v1.2.0

func (q *QueryBuilder[OUTPUT]) WhereIn(column string, values ...interface{}) *QueryBuilder[OUTPUT]

WhereIn adds a where clause to QueryBuilder using In operator.

func (*QueryBuilder[OUTPUT]) WherePK added in v1.2.0

func (q *QueryBuilder[OUTPUT]) WherePK(value interface{}) *QueryBuilder[OUTPUT]

WherePK adds a where clause to QueryBuilder and also gets primary key name from type parameter schema.

type Timestamps added in v1.2.0

type Timestamps struct {
	CreatedAt sql.NullTime
	UpdatedAt sql.NullTime
	DeletedAt sql.NullTime
}

Jump to

Keyboard shortcuts

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