Simple and performant ORM for sql.DB

Simple and performant ORM for sql.DB

build workflow PkgGoDev Documentation Chat

Main features are:

Resources:

github.com/frederikhors/orm-benchmark results
  4000 times - Insert
  raw_stmt:     0.38s        94280 ns/op     718 B/op     14 allocs/op
       raw:     0.39s        96719 ns/op     718 B/op     13 allocs/op
 beego_orm:     0.48s       118994 ns/op    2411 B/op     56 allocs/op
       bun:     0.57s       142285 ns/op     918 B/op     12 allocs/op
        pg:     0.58s       145496 ns/op    1235 B/op     12 allocs/op
      gorm:     0.70s       175294 ns/op    6665 B/op     88 allocs/op
      xorm:     0.76s       189533 ns/op    3032 B/op     94 allocs/op

  4000 times - MultiInsert 100 row
       raw:     4.59s      1147385 ns/op  135155 B/op    916 allocs/op
  raw_stmt:     4.59s      1148137 ns/op  131076 B/op    916 allocs/op
 beego_orm:     5.50s      1375637 ns/op  179962 B/op   2747 allocs/op
       bun:     6.18s      1544648 ns/op    4265 B/op    214 allocs/op
        pg:     7.01s      1753495 ns/op    5039 B/op    114 allocs/op
      gorm:     9.52s      2379219 ns/op  293956 B/op   3729 allocs/op
      xorm:    11.66s      2915478 ns/op  286140 B/op   7422 allocs/op

  4000 times - Update
  raw_stmt:     0.26s        65781 ns/op     773 B/op     14 allocs/op
       raw:     0.31s        77209 ns/op     757 B/op     13 allocs/op
 beego_orm:     0.43s       107064 ns/op    1802 B/op     47 allocs/op
       bun:     0.56s       139839 ns/op     589 B/op      4 allocs/op
        pg:     0.60s       149608 ns/op     896 B/op     11 allocs/op
      gorm:     0.74s       185970 ns/op    6604 B/op     81 allocs/op
      xorm:     0.81s       203240 ns/op    2994 B/op    119 allocs/op

  4000 times - Read
       raw:     0.33s        81671 ns/op    2081 B/op     49 allocs/op
  raw_stmt:     0.34s        85847 ns/op    2112 B/op     50 allocs/op
 beego_orm:     0.38s        94777 ns/op    2106 B/op     75 allocs/op
        pg:     0.42s       106148 ns/op    1526 B/op     22 allocs/op
       bun:     0.43s       106904 ns/op    1319 B/op     18 allocs/op
      gorm:     0.65s       162221 ns/op    5240 B/op    108 allocs/op
      xorm:     1.13s       281738 ns/op    8326 B/op    237 allocs/op

  4000 times - MultiRead limit 100
       raw:     1.52s       380351 ns/op   38356 B/op   1037 allocs/op
  raw_stmt:     1.54s       385541 ns/op   38388 B/op   1038 allocs/op
        pg:     1.86s       465468 ns/op   24045 B/op    631 allocs/op
       bun:     2.58s       645354 ns/op   30009 B/op   1122 allocs/op
 beego_orm:     2.93s       732028 ns/op   55280 B/op   3077 allocs/op
      gorm:     4.97s      1241831 ns/op   71628 B/op   3877 allocs/op
      xorm:     doesn't work

Installation

go get github.com/uptrace/bun
go get github.com/uptrace/bun/dialect/sqlitedialect

Quickstart

First you need to create a sql.DB. Here we using the SQLite3 driver.

import _ "github.com/mattn/go-sqlite3"

sqldb, err := sql.Open("sqlite3", ":memory:?cache=shared")
if err != nil {
	panic(err)
}

And then create a bun.DB on top of it using the corresponding SQLite dialect:

import (
	"github.com/uptrace/bun"
	"github.com/uptrace/bun/dialect/sqlitedialect"
)

db := bun.NewDB(sqldb, sqlitedialect.New())

Now you are ready to issue some queries:

type User struct {
	ID	 int64
	Name string
}

user := new(User)
err := db.NewSelect().
	Model(user).
	Where("name != ?", "").
	OrderExpr("id ASC").
	Limit(1).
	Scan(ctx)

The code above is equivalent to:

query := "SELECT id, name FROM users AS user WHERE name != '' ORDER BY id ASC LIMIT 1"

rows, err := sqldb.QueryContext(ctx, query)
if err != nil {
	panic(err)
}

if !rows.Next() {
    panic(sql.ErrNoRows)
}

user := new(User)
if err := db.ScanRow(ctx, rows, user); err != nil {
	panic(err)
}

if err := rows.Err(); err != nil {
    panic(err)
}

Basic example

First we need to load some data for our basic example. To provide initial data we are going to use Bun fixtures:

import "github.com/uptrace/bun/dbfixture"

// Register models for the fixture.
db.RegisterModel((*User)(nil), (*Story)(nil))

// WithRecreateTables tells Bun to drop existing tables and create new ones.
fixture := dbfixture.New(db, dbfixture.WithRecreateTables())

// Load fixture.yaml which contains data for User and Story models.
if err := fixture.Load(ctx, os.DirFS("."), "fixture.yaml"); err != nil {
	panic(err)
}

The fixture.yaml looks like this:

- model: User
  rows:
    - _id: admin
      name: admin
      emails: ['admin1@admin', 'admin2@admin']
    - _id: root
      name: root
      emails: ['root1@root', 'root2@root']

- model: Story
  rows:
    - title: Cool story
      author_id: '{{ $.User.admin.ID }}'

To select all users:

users := make([]User, 0)
if err := db.NewSelect().Model(&users).OrderExpr("id ASC").Scan(ctx); err != nil {
	panic(err)
}

To select a single user by id:

user1 := new(User)
if err := db.NewSelect().Model(user1).Where("id = ?", 1).Scan(ctx); err != nil {
	panic(err)
}

To select a story and the associated author in a single query:

story := new(Story)
if err := db.NewSelect().
	Model(story).
	Relation("Author").
	Limit(1).
	Scan(ctx); err != nil {
	panic(err)
}

To select a user into a map:

m := make(map[string]interface{})
if err := db.NewSelect().
	Model((*User)(nil)).
	Limit(1).
	Scan(ctx, &m); err != nil {
	panic(err)
}

To select all users scanning each column into a separate slice:

var ids []int64
var names []string
if err := db.NewSelect().
	ColumnExpr("id, name").
	Model((*User)(nil)).
	OrderExpr("id ASC").
	Scan(ctx, &ids, &names); err != nil {
	panic(err)
}

For more details, please consult docs and check examples.

Owner
Uptrace
All-in-one tool to optimize performance and monitor errors & logs
Uptrace
Comments
  • Should there be a way to migrate to a specific target?

    Should there be a way to migrate to a specific target?

    I want to suggest add a method to migrate.Migrations to migrate to a specific group number / target. E.g.

    func(m *Migrations) MigrateTo(ctx context.Context, db *bun.DB, target int64) error
    

    Or an example on how to achieve this without this method.

    Use-case:

    1. Deploy new API that require the latest schema version (e.g. 5).
    2. Find there is a bug in the API, and roll it back to a previous version that requires an earlier db schema (e.g. 3).
    3. Run to migrate to group 3 (automatically rollback any migrations with a higher group number, and apply any migrations with a lower or eqaul group number).

    Assumes that migrations group numbers can be set from the source.

  • TIMEZONE issue with version before mysql 8.0

    TIMEZONE issue with version before mysql 8.0

    https://github.com/uptrace/bun/blob/57ab844745cfc84bd902250ffd6042fe907f3fe9/dialect/append.go#L97

    test mysql version: 5.7.*

    time.Time is converted to a time string(in UTC without timezone) in AppendTime function, while mysql will consider this time string as the local time of the timezone set in the connection session. For ‘timestamp’ columns, mysql will convert this time string to UTC time again.

    So, if original time is '2021-09-08T12:00:00+08:00', it becomes to '2021-09-08 04:00:00' after sql building, then it becomes to '2021-09-07T20:00:00+00:00' in db if the session timezone is '+08:00'.

    In my view, bun should convert time.Time according to the session timezone.

  • ERROR #42P02 there is no parameter $1 when using pgdriver with SQLBoiler

    ERROR #42P02 there is no parameter $1 when using pgdriver with SQLBoiler

    I was impressed by the benchmarks relative to pgx, so tried it out on my project that's already using SQLBoiler. However, most of my tests fail with:

    ERROR #42P02 there is no parameter $1
    

    For reference, the project is here: https://github.com/hortbot/hortbot

    If you want to test this, changing the driver for the entire project is as simple as changing the _ import and driver name here: https://github.com/hortbot/hortbot/blob/master/internal/db/driver/driver.go

    I can enable SQLBoiler's debugging to get a trace of the SQL queries it tried for one of the tests:

    --- FAIL: TestScripts (0.00s)
        --- FAIL: TestScripts/misc_errors (1.16s)
            print.go:265: SELECT r.* FROM repeated_commands r JOIN channels c ON r.channel_id = c.id WHERE r.enabled AND c.active
            print.go:265: []
            print.go:265: SELECT s.* FROM scheduled_commands s JOIN channels c ON s.channel_id = c.id WHERE s.enabled AND c.active
            print.go:265: []
            write_syncer.go:66: 2021-06-28T20:04:32.448-0700	ERROR	bot/handle.go:81	error during handle	{"xid": "c3d8rg2fi36ho6imuqog", "irc_command": "PRIVMSG", "error": "ERROR #42P02 there is no parameter $1", "message": "@id=d079f2bc-12cc-4c06-a9a4-2212c69decd8;room-id=999;user-id=1 :[email protected] PRIVMSG #hortbot :!join"}
                github.com/hortbot/hortbot/internal/bot.(*Bot).Handle
                	/home/jake/zikaeroh/hortbot/hortbot2/internal/bot/handle.go:81
                github.com/hortbot/hortbot/internal/bot/btest.(*scriptTester).handleM.func1
                	/home/jake/zikaeroh/hortbot/hortbot2/internal/bot/btest/irc.go:57
                github.com/hortbot/hortbot/internal/bot/btest.(*scriptTester).test
                	/home/jake/zikaeroh/hortbot/hortbot2/internal/bot/btest/script_tester.go:207
                github.com/hortbot/hortbot/internal/bot/btest.RunScript
                	/home/jake/zikaeroh/hortbot/hortbot2/internal/bot/btest/script_tester.go:49
                github.com/hortbot/hortbot/internal/bot_test.TestScripts.func1
                	/home/jake/zikaeroh/hortbot/hortbot2/internal/bot/script_test.go:28
                testing.tRunner
                	/usr/lib/go/src/testing/testing.go:1193
            irc.go:129: assertion failed: expression is false: st.sender.SendMessageCallCount() > callNum: SendMessage not called: line 2
    FAIL
    FAIL	github.com/hortbot/hortbot/internal/bot	1.655s
    FAIL
    
  • Multi tenant, an elegant and easy way

    Multi tenant, an elegant and easy way

    Now that you have refactored a lot of things in go-pg and Bun is born, I think it's the right time to ask you something that I have long wanted to solve easily with go-pg.

    I'm talking about the filter with tenant_id for tenantable models.

    Example:

    If Player is tenantable (has Tenant field):

    type Tenant struct {
      ID int
      Name string
    }
    
    type Player struct {
      Tenant
      name string
      age int
    }
    

    I would like to add on each query a where filter like:

    SELECT * FROM players where name LIKE 'John'
    AND where tenant_id = 123 -- this is automagically added
    

    123 here comes from user's tenant_id column.

    I saw that there are a lot of hooks available but not the one before a Select which is what we need here.

    Can you suggest an elegant way?

    Since you also worked on a solution here: https://github.com/elliotcourant/go-pg-multitenant, I would like to hear your opinion on Bun too, @elliotcourant.

  • Heroku postgresql DB fails with `db postgres ping: FATAL #28000 no pg_hba.conf entry for host, ssl off`

    Heroku postgresql DB fails with `db postgres ping: FATAL #28000 no pg_hba.conf entry for host, ssl off`

    URGENT: first time using Bun on Heroku today.

    I'm using the default DATABASE_CONNECTION string Heroku creates, like this:

    postgres://user:[email protected]:5432/DBNAME

    And this code:

    func NewBunDB(database_connection_string string) *bun.DB {
    	dbPG := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(database_connection_string)))
    
    	dbBunPG := bun.NewDB(dbPG, pgdialect.New())
    
      err := dbBunPG.Ping()
      if err != nil {
        return fmt.Errorf("db postgres ping: %w", err)
      }
    
    	return dbBunPG
    }
    

    And the error is scary!

    db postgres ping: FATAL #28000 no pg_hba.conf entry for host \"172.XX.XX.XX\", user \"USERNAME\", database \"DBNAME\", SSL off

    What does this mean?

  • PostgreSQL

    PostgreSQL "Has many relation" optimization

    This example : https://github.com/uptrace/bun/tree/master/example/rel-has-many

    Currently, with Bun's has many implementation, Bun executes two queries.

    [bun]  14:10:17.279   SELECT                   20µs  SELECT "user".* FROM "users" AS "user" ORDER BY user.id ASC LIMIT 1
    [bun]  14:10:17.279   SELECT                   23µs  SELECT "profile"."id", "profile"."lang", "profile"."active", "profile"."user_id" FROM "profiles" AS "profile" WHERE ("profile"."user_id" IN (1)) AND (active IS TRUE)
    

    But this can be done in one query with left join. In PostgreSQL one can do,

     SELECT "users".*,array_agg(profiles.*) FROM "users" left join profiles on profiles.user_id=users.id group by users.id
    

    This will effectively get the same results without needing to chain multiple queries.

  • How to use Bulk() with NewUpdate() ?

    How to use Bulk() with NewUpdate() ?

    I am unable to make work the Bulk() function. There is no example in docs. Can you please tell me if it's possible to use Bulk() to bulk update without manually creating CTE?

  • Make migrations more explicit and generic

    Make migrations more explicit and generic

    I've started to use bun migrations and I have a few suggestions for possible improvements and would like to hear your opinions on them. And if you approve some of them I could start working on a PR.

    1. Remove context and bun.DB parameters from migrations.CreateGo or migrations.CreateSQL function since they are not used. Is it planned for the future?
    2. Make migration directory configurable. Currently, it gets the caller directory, which means I have to alias Create(.*) functions in the directory where my migrations are located since I'm calling Create function from some other directory.
    3. Make package name configurable for CreateGo migration (and/or item 6.)
    func CreateGo(directory, name, package string) error
    func CreateSQL(directory, name string) error
    
    1. Replace logging with fmt.Printf with user configurable logger. Maybe global log function for migration package? Something like:
    var log = func(format string, a ...interface{}) {
    	fmt.Printf(format, a...)
    }
    
    func SetLogFn(fn func(format string, a ...interface{})) {
    	log = fn
    }
    
    1. Add more code to generated go template like the one bellow since this is a MVP for go migration file.
    package {{ package_name }}
    
    import (
    	"context"
    
    	"github.com/uptrace/bun"
    )
    
    func init() {
    	Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
    		fmt.Print(" [up migration] ")
    		return nil
    	}, func(ctx context.Context, db *bun.DB) error {
    		fmt.Print(" [down migration] ")
    		return nil
    	})
    }
    
    1. Add option for adding user template for go and sql migration file creation.
    2. Add a check before migrate if the required migration tables exist, if not, initialize. Quick and dirty way is to run Init(...) on every migration. Might be cheaper to execute then checking first. But speed is not an issue here.
    3. Status function should return a struct containing migration status and not print to console.
  • Execute pgdriver.CopyFrom in the transaction, The CopyFrom fails due to the lock waiting.

    Execute pgdriver.CopyFrom in the transaction, The CopyFrom fails due to the lock waiting.

    I faced a really annoying issue lately with the pgdriver.CopyFrom.

    My code is as follows:

    func main() { ctx := context.Background() dsn := "postgres://postgres:xxxx@xxxx:xxx/database?sslmode=disable" pgdb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn))) db := bun.NewDB(pgdb, pgdialect.New()) db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))

    var err error
    err = db.ResetModel(ctx, (*User)(nil))
    
    user1 := User{Name: "admin1"}
    user2 := User{Name: "admin2"}
    users := []User{user1, user2}
    
    conn, err := db.Conn(ctx)
    if err != nil {
    	_ = fmt.Errorf("failed to get db conn, err: %v", err)
    }
    defer conn.Close()
    
    _, err = conn.NewInsert().Model(&users).Exec(ctx)
    
    path := "/home/dexcloud/user_table"
    f2, _ := os.Open(filepath.Clean(path))
    defer f2.Close()
    
    bf2 := bufio.NewReader(f2)
    
    db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
    	_, err = tx.Exec(`TRUNCATE user_table`)       // TRUNCATE statement
    	_, err = pgdriver.CopyFrom(ctx, conn, bf2, `COPY user_table(id, name) FROM STDIN WITH ENCODING 'UTF-8'`) // exec fails
    	return err
    })
    

    }

    type User struct { bun.BaseModel bun:"table:user_table,alias:u" ID int64 bun:",pk,autoincrement" Name string Email string }

    The file (/home/dexcloud/user_table ) content is as follows: 1 admin1-new 3 admin3

    Problem: The TRUNCATE statement holds the lock, and the data of the pgdriver.CopyFrom operation involves the data whose id is 1, so pgdriver.CopyFrom want to get the lock. However, as a result of the TRUNCATE statement holding the lock, pgdriver.CopyFrom fails.

    image

    In this case, CopyFrom can be executed successfully in the previous go-pg [func (tx *Tx) CopyFrom], but the execution in the uptrace/bun [pgdriver.CopyFrom] fails.

  • SelectOrInsert method?

    SelectOrInsert method?

    In pg-go there was a method SelectOrInsert. The migration guide does not contain any info about deletion of this method. Does it exist in Bun?

    If not - any chance you will add it in near future?

  • 'fk' tag equivalent?

    'fk' tag equivalent?

    Continuing migration from go-pg, I've come across this warning:

    WARN: bun: 2021/05/24 17:43:52 User.OwnerOfGroups has unknown tag option: "fk"
    

    eg

    	OwnerOfGroups          []UserGroup `bun:"fk:owner_id"`
    

    I could not identify this from the (otherwise thorough) documentation provided ...

    Is there support/an equivalent in bun? thanks!

  • Clear up join documentation

    Clear up join documentation

    I was having issues doing a join between to models by using two consecutive join parameters. For my one to many relation to work I have to use a join for the first column and a join_on for the second column. Is that the expected functionality? if so can we update the docs https://github.com/go-bun/bun-docs/edit/master/docs/guide/relations.md

  • Insertion without a model

    Insertion without a model

    How to use bun as a query builder to insert a row into the database?

    When I try this:

    _, err = r.db.NewInsert().
    	Table("custom_path").
    	Value("port_a_id", portAId).
    	Value("port_b_id", portBId).
    	Value("checkpoints", strings.Join(checkpoints, ",")).
    	Value("path", "st_geomfromgeojson(?)", pathJson).
    	On("conflict (port_a_id, port_b_id, checkpoints) do update").
    	Set("path = excluded.path").
    	Exec(r.ctx)
    

    I get an error "bun: Model(nil)".

  • Support for db resolvers

    Support for db resolvers

    Hi,

    I integrated a stable dbresolver into Bun. And used it in production with replicas. Hence. I was able to unblock db bottle necks and gain very low DB latencies in production.

  • Allow string array in WithConnParams

    Allow string array in WithConnParams

    #611 This PR allows multiple parameters to WithConnParams in the form of string slice

    		pgdriver.WithConnParams(map[string]interface{}{
    			"search_path": []string{"foo", "bar"},
    		}),
    
  • Table's schema in the `bun` tag

    Table's schema in the `bun` tag

    Following our discussion here, I am opening an ticket for this feature.

    Context from the linked comment:

    I couldn't find a convenient mechanism in bun's API for specifying the schema to which a certain table belongs. [...] It could be worked around with, e.g. BeforeCreateTableHook, but I feel like we should have a simpler solution (like adding a schema key in the bun: tag) for something so commonplace

    A proposed solution would be:

    It probably can be supported via a tag like you suggested bun:"schema:name", [...]

    For example, if specified:

    type Model struct {
        bun.BaseModel `bun:"schema:custom"`
        ...
    }
    
    db.NewCreateTable().Model((*Model)(nil)).Exec(ctx)
    // Output: CREATE TABLE custom.models;
    
    db.NewSelect().Model((*Model)(nil)).Count().Scan(ctx, &n)
    // Output: SELECT COUNT(*) FROM custom.models;
    
    // Etc.
    

    If omitted, the generated query does not include any schema name (i.e. does not assume public), the behavior stays as is.

Related tags
Using-orm-with-db - Trying to use ORM to work with PostgreSQL
Using-orm-with-db - Trying to use ORM to work with PostgreSQL

Using ORM with db This repo contains the training (rough) code, and possibly not

Jul 31, 2022
A simple wrapper around sql.DB to help with structs. Not quite an ORM.

go-modeldb A simple wrapper around sql.DB to help with structs. Not quite an ORM. Philosophy: Don't make an ORM Example: // Setup require "modeldb" db

Nov 16, 2019
100% type-safe ORM for Go (Golang) with code generation and MySQL, PostgreSQL, Sqlite3, SQL Server support. GORM under the hood.

go-queryset 100% type-safe ORM for Go (Golang) with code generation and MySQL, PostgreSQL, Sqlite3, SQL Server support. GORM under the hood. Contents

Dec 30, 2022
beedb is a go ORM,support database/sql interface,pq/mysql/sqlite

Beedb ❗ IMPORTANT: Beedb is being deprecated in favor of Beego.orm ❗ Beedb is an ORM for Go. It lets you map Go structs to tables in a database. It's

Nov 25, 2022
SQL mapper ORM framework for Golang
 SQL mapper ORM framework for Golang

SQL mapper ORM framework for Golang English 中文 Please read the documentation website carefully when using the tutorial. DOC Powerful Features High Per

Dec 8, 2021
Mybatis for golang - SQL mapper ORM framework

SQL mapper ORM framework for Golang English 中文 Please read the documentation website carefully when using the tutorial. DOC Powerful Features High Per

Nov 10, 2022
Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle, Moved to https://gitea.com/xorm/xorm

xorm HAS BEEN MOVED TO https://gitea.com/xorm/xorm . THIS REPOSITORY WILL NOT BE UPDATED ANY MORE. 中文 Xorm is a simple and powerful ORM for Go. Featur

Jan 3, 2023
Go tool for generating sql scanners, sql statements and other helper functions

sqlgen generates SQL statements and database helper functions from your Go structs. It can be used in place of a simple ORM or hand-written SQL. See t

Nov 24, 2022
Simple Go ORM for Google/Firebase Cloud Firestore

go-firestorm Go ORM (Object-relational mapping) for Google Cloud Firestore. Goals Easy to use Non intrusive Non exclusive Fast Features Basic CRUD ope

Dec 1, 2022
A better ORM for Go, based on non-empty interfaces and code generation.

reform A better ORM for Go and database/sql. It uses non-empty interfaces, code generation (go generate), and initialization-time reflection as oppose

Dec 31, 2022
A better ORM for Go, based on non-empty interfaces and code generation.
A better ORM for Go, based on non-empty interfaces and code generation.

A better ORM for Go and database/sql. It uses non-empty interfaces, code generation (go generate), and initialization-time reflection as opposed to interface{}, type system sidestepping, and runtime reflection. It will be kept simple.

Dec 29, 2022
Golang ORM with focus on PostgreSQL features and performance

go-pg is in a maintenance mode and only critical issues are addressed. New development happens in Bun repo which offers similar functionality but works with PostgreSQL, MySQL, and SQLite.

Jan 8, 2023
Examples of using various popular database libraries and ORM in Go.

Introduction Examples of using various popular database libraries and ORM in Go. sqlx sqlc Gorm sqlboiler ent The aim is to demonstrate and compare us

Dec 12, 2021
Examples of using various popular database libraries and ORM in Go.

Introduction Examples of using various popular database libraries and ORM in Go. sqlx sqlc Gorm sqlboiler ent The aim is to demonstrate and compare us

Dec 28, 2022
ORM-ish library for Go

We've moved! gorp is now officially maintained at: https://github.com/go-gorp/gorp This fork was created when the project was moved, and is provided f

Aug 23, 2022
Database agnostic ORM for Go

If you are looking for something more lightweight and flexible, have a look at jet For questions, suggestions and general topics visit the group. Inde

Nov 28, 2022
QBS stands for Query By Struct. A Go ORM.

Qbs Qbs stands for Query By Struct. A Go ORM. 中文版 README ChangeLog 2013.03.14: index name has changed to {table name}_{column name}. For existing appl

Sep 9, 2022
Generate a Go ORM tailored to your database schema.
Generate a Go ORM tailored to your database schema.

SQLBoiler is a tool to generate a Go ORM tailored to your database schema. It is a "database-first" ORM as opposed to "code-first" (like gorm/gorp). T

Jan 2, 2023
An orm library support nGQL for Golang

norm An ORM library support nGQL for Golang. Overview Build insert nGQL by struct / map (Support vertex, edge). Parse Nebula execute result to struct

Dec 1, 2022