Gorm: GORM v2 is on going

Created on 16 Feb 2020  ·  216Comments  ·  Source: go-gorm/gorm

Hello All,

GORM v2 is under active development (https://github.com/jinzhu/gorm/tree/v2_dev), going to release in the next two months.

Before that, I am NOT going to merge any pull requests based on the master branch.

V2 will be overwritten from scratch with similar public API, it would focus on performance, improve usability and fix fragile designs. We will provide a migration guide to help users migrate before the release.

With the new architecture, it opens the possibility to have a better migration tool, a static code generator that generates type-safe code with all the features of GORM, visualizes models and its relationships to help a new team member quickly understand your project, and even support Redis & MongoDB...

Your code review or suggestions would be much appreciated, please comment to this thread, thank you.

Most helpful comment

@jinzhu Could you please add support for generation of migration files like djangos makemigrations? Django's orm is pretty stable, very useful and has lot of good features.

Ref: https://docs.djangoproject.com/en/3.0/ref/django-admin/#django-admin-makemigrations

Example Django application with migrations:

https://github.com/stadtulm/cykel/tree/master/bikesharing/migrations

All 216 comments

@jinzhu Could you please add support for generation of migration files like djangos makemigrations? Django's orm is pretty stable, very useful and has lot of good features.

Ref: https://docs.djangoproject.com/en/3.0/ref/django-admin/#django-admin-makemigrations

Example Django application with migrations:

https://github.com/stadtulm/cykel/tree/master/bikesharing/migrations

  • Fix the foreign key relations (that work in a very convoluted way) and in Postgres only.
  • Write a sensible comprehensible documentation that describes your library in the right way.

Preloads using joins for PostgreSQL (I don't know how that's implemented in other dialects), for me that is by far the most important feature absent in the current version.

As it currently stands, preloads literally stop working once the number of parameters exceed a certain amount. Before then preloads are prohibitively slow partly due to the extra roundtrip per preload, but more importantly due to the missed opportunity for query optimization.

Has any work on static code generator started? I'd be interested in contributing.

Hi @rjeczalik haven't started it, just created some draft notes, was going to start it after the release of v2, but if you are interested, I can create a project for the generator under GORM's organization. ( yes, we will have an organization ;) )

Here is the draft notes (feedback is welcome)

Generate static code based on relationships parsed by https://github.com/jinzhu/gorm/tree/v2_dev/schema

generated code looks like

package models // user defiend

type DB struct {
  DB *gorm.DB
  User User
}

type User struct {
  ID       IntField
  Name     StringField
  Languages HasManyRelation
}

var user = User{
  ID: IntField{
    // xxx
  },
  Name: StringField{
    // xxx
  }
  Languages: HasManyRelation{
    // xxx
  }
}

func New(gorm.Dialector, gorm.Config) *DB {
  return &DB{
    DB: gormDB,
    User: user,
  }
}

Usage API

initalize db

db := models.NewDB(sqlite.Open('xxx'), gorm.Config{
})

with context

db = db.WithContext(ctx)

API

// find
db.User.Select(db.User.Name, db.User.Age).Find() (users []*yourapp.User, err error)

// first
db.User.Select(db.User.Name, db.User.Age).First() (*yourapp.User, error)

// last
db.User.Select(db.User.Name, db.User.Age).Last() (*yourapp.User, error)

// last
db.User.Where(db.User.Name.Like("%jinzhu"), db.User.Age.Eq(10)).Last() (*yourapp.User, error)

// preload
db.User.Preload(db.User.Languages.Where(
  db.Languages.Code.Eq("zh-CN")
)).Select(db.User.Name, db.User.Age).Last() (*yourapp.User, error)

// update
db.User.Update(user)

// Relations
db.User.Languages.Model(user).Add([]*yourapp.Languages{})
db.User.Languages.Model(user).Replace(]*yourapp.Languages{})
db.User.Languages.Model(user).Delete([]*yourapp.Languages{})

@jinzhu Not quite sure what e.g. IntField is, is this a pseudocode for wrapper types like sql.NullInt64 or null.Int64?

There's already a functional generator for MySQL - https://github.com/smallnest/gen. What I wanted to achieve is db-agnostic generator with the ability of generating fields for associations (preloading), configurable via struct tags.

@jinzhu Could you please add support for generation of migration files like djangos makemigrations? Django's orm is pretty stable, very useful and has lot of good features.

Maybe instead of coming up with another migration toolkit, have documentation and examples (or an integration) for using pressly/goose for migrations. There are a few other libraries, but goose can be fully integrated or it can be standalone with sql files for the migrations. Couple that with a generator that follows a convention or specified template for the migrations (generator like in rails, where you generate a new migration file with a rails command)

/cc @donutloop

@rjeczalik sorry, haven't made things clear, this tool WON'T generate models definition from database

You need to defined it by yourself, for example, you already have your user package

package user

type User struct {
  gorm.Model
  Name         string
  Language     Language
  LanguageCode string
}

type Language struct {
  Code string `gorm:primarykey`
}

With this tool, it will generate another package named db:

package db

type DB struct {
  DB *gorm.DB
  User User
}

type User struct {
  ID        IntField
  Name      StringField
  Languages HasManyRelation
}

func (user User) First() (user.User, error) {
  // xxx
}

var user = User{
  ID: IntField{
    DBName: "id",
  },
  Name: StringField{
    DBName: "name",
  }
  Languages: HasManyRelation{
    ReferenceTable: "languages",
    ForeignKey: "code",
  }
}

func New(gorm.Dialector, gorm.Config) *DB {
  return &DB{
    DB: gormDB,
    User: user,
  }
}

In your application, if you want to use the generated code like:

import 'yourapp/db'

var db = db.New(gorm.dialector, gorm.Config{})

func handler(w http.ResponseWriter, r *http.Request) {
  user, err := db.User.First()
  fmt.Println(user.Name) // string
  json.NewEncoder(w).Encode(user)
}

func main() {
  http.HandleFunc("/", handler)
  log.Fatal(http.ListenAndServe(":8080", nil))
}

Please review some crucial fixes, we even had to use our fork to mitigate these problems:

https://github.com/jinzhu/gorm/pull/2737 -- erros on nested preloads get ignored, this is a critical issue.

Also please support context for cancellation and tracing support.

Our fork with context support and fix for ignored nested preload errors: https://github.com/readdle/gorm/tree/nested-preload-fix

With this tool, it will generate another package named db:

@jinzhu Let me know if I understand it correctly - you want to have a generator which will generate objects with API similar to what Active Record in RoR is offering, correct?

@rjeczalik yes, generate type-safe code with similar API like that, suggestions?

allow https://golang.org/pkg/context/ to be passed to the underlying SQL driver.

@edwardsb the API will work like this:

tx := db.WithContext(ctx)
tx.First(&user)
tx.Update(&user)
db.WithContext(ctx).First(&user)

(similar to https://golang.org/pkg/net/http/#Request.WithContext)

could remove cgo depend for sqlites

dynamic model support

Fix the foreign key relations (that work in a very convoluted way) and in Postgres only.

@MurtadhaS just finished that ;)

The most important feature for my team would be a more advanced migration tool. I'm really missing Django's migration framework.

Integration into Goose would be fine, as long as the up/down SQL is generated by Gorm.

The main thing is that the migration tool is able to determine automatically what has changed between versions.

Postgres ErrorCodes support please.
https://www.postgresql.org/docs/10/errcodes-appendix.html

Savepoint (nested transaction) support in transaction please.

Also better handling of Postgres ENUM types would be great.

Another thing.
Handle GUID internally.

Hi. Please check out my PR #2921

Have a clear-well-defined API.

In my experience with gorm I found that there are multiple ways to achieve the same things which bothered me a lot. I could provide some examples in the next day or so

@jinzhu Nice to see v2 rising. So, please don't forget this #1436 ^_^
Good luck

@vzool will make it works with API like db.Joins("Profile").Find(&users)

There is no api for subqueries.

Any release schedules of v2? Maybe a TODO list will be very helpful.

Please notices on https://github.com/jinzhu/gorm/issues/2871

Relations is one thing that I hope to see simplified in new release. Currently you have to manage foreign keys yourself, but I hope in v2 this is automatically managed.

@jinzhu any plans to support amazon xray context ? Is this something you deem possible, could use help on ?
https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-go-sqlclients.html

@jinzhu Why are you going the code generation route? I believe that lot of the functionality that generated code provides could be accomplished through reflecting the user struct.

@jinzhu Why are you going the code generation route? I believe that lot of the functionality that generated code provides could be accomplished through reflecting the user struct.

performance + typesafety

performance

When it comes to database transactions this is absolutely negligible.

Type safety is the primary concern that is solved with code generation
though.

On Sun, Apr 5, 2020 at 12:53 PM inliquid notifications@github.com wrote:

performance
When it comes to database transactions this is absolutely negligible.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/jinzhu/gorm/issues/2886#issuecomment-609472683, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AAH6QHYROASAJQWFVAPGL7TRLDOSNANCNFSM4KV6IZOQ
.

performance

When it comes to database transactions this is absolutely negligible.

reflection has a performance overhead, but my personal issue is definitely the typesafety

If type safety is your main concern and a motivation behind this feature, I believe a more sturdy type safety would be provided by generating code based on reverse engineering you sql schema, not by reading your go structs.

If type safety is your main concern and a motivation behind this feature, I believe a more sturdy type safety would be provided by generating code based on reverse engineering you sql schema, not by reading your go structs.

sql schemas are more tedious to write tbh
compare this:

CREATE TABLE IF NOT EXISTS users (
  id varchar(36) NOT NULL PRIMARY KEY,
  name varchar(255) NOT NULL,
  email varchar(255) NOT NULL,
  password varchar(255) NOT NULL,
  avatar varchar(255) NOT NULL,
  points double NOT NULL,
  role varchar(255) NOT NULL,
  verified tinyint(1) NOT NULL,
  UNIQUE KEY email (email)
-- as well as every relation in other tables
);

with

type User struct {
    ID         uuid.UUID `json:"id,omitempty" db:"id,omitempty"`
    Name       string    `json:"name" db:"name"`
    Email      string    `json:"email" db:"email"`
    Password   string    `json:"-" db:"password"`
    Avatar     string    `json:"avatar" db:"avatar"`
    Points     float64   `json:"points" db:"points"`
    Role       Role      `json:"role" db:"role"`
    Orders     []Order   `json:"orders" db:"-"`
    IsVerified bool      `json:"is_verified" db:"verified"`
}

I am not sure if this point relates to the code generation feature. SQL can get tedious, but I am implying that your database should be source of truth to your structs. i believe your comment has it the other way around.

v2 How is it going. About how long to release v2 ? @jinzhu

  • Will there be a migration path from v1?
  • Is there any backward compatibility or will devs just have to port their code base to v2?

@jimlambrt both your questions are answered in the first post.

  • Will there be a migration path from v1?
  • Is there any backward compatibility or will devs just have to port their code base to v2?

V2 will be overwritten from scratch with similar public API, it would focus on performance, improve usability and fix fragile designs. We will provide a migration guide to help users migrate before the release.

@jinzhu just checking if there's an estimate date for when v2 will be available?

是否会在v2中添加读写分离的支持

Regarding drivers + dialects - I assume v2 will be as interoperable between different drivers? I ask this because jackc/pgx appears to be the preferred replacement for lib/pq, and I was having a hard time migrating Copy In functionality over.

I then saw an issue in this repo slated for the v2 milestone that will support copy in. Would love to know if that's still slated for v2 since that was closed.

@jinzhu Is there a support for generating and querying additionnal fields on join table (Many2Many relation) ?

@jinzhu是否支持在联接表(Many2Many关系)上生成和查询附加字段?

I'm looking forward to this feature.

Example:manytomany need a tenant_id.

@Linzdigr I'm attempting to do the same right now in v1. So far it looks like it might work as long as you create the join table yourself before you create the tables involved in the M2M relationship. Either way, I haven't confirmed it's working yet but it would be excellent to hear from @jinzhu on this. Sometimes junction tables are the only place a piece of data could reasonably be placed.

EDIT: Go-RM does already support this see https://github.com/jinzhu/gorm/issues/719

Would it be possible to change the logger interface to every method accepting a context.Context? Many people use context to carry (for example) a request bound parameters, for example RequestID. This way we could extract these fields from context during logging.

db.Create(&user)
并没有排除零值字段呀!

@rkuska added that, thank you for your suggestion.

Any news about the release date?

Any ETA?

Would be nice if dirty tracking would be possible, since fields are not plain types anymore, this is a long-requested feature: #612 #2147 #2952

612 even has an implementation suggestion

And just to clarify - will db.User.First() from your example return a user.User (with string type name) or a db.User (with StringField type name)?

Can you add support for Read-write separation ???

@jinzhu hi~ Do you have a release plan for version v2?

Any plans for spatial data types in V2?

Hello everyone, I have released a public testing version "v0.2.5" for v2, which is used on some internal production projects already.

If you want to test it, please use the import path: "gorm.io/gorm", version: "v0.2.5", feedbacks welcome!

I am still working on the release note and writing documents, the final release date will depend on feedbacks, If everything goes well, it will be the time we reach 20k stars!

@jinzhu Is there a support for generating and querying additionnal fields on join table (Many2Many relation) ?

We have better support for this in v2, it will be easier to use, refer method 'SetupJoinTable', and waiting for the documents for details.

Official mongo support?

If type safety is your main concern and a motivation behind this feature, I believe a more sturdy type safety would be provided by generating code based on reverse engineering you sql schema, not by reading your go structs.

Added it supports.

@jinzhu Any support plan for batch actions? e.g. insert records etc.

Official mongo support?

Possible to support it in v2, but I am not going to release a MongoDB driver when releasing v2.

@jinzhu Any support plan for batch actions? e.g. insert records etc.

Supported it, just use db.Create(&users)

Hello everyone, I have released a public testing version "v0.2.1" for v2, which is used on some internal production projects already.

If you want to test it, please use the import path: "gorm.io/gorm", version: "v0.2.1", feedbacks welcome!

I am still working on the release note and writing documents, the final release date will depend on feedbacks, If everything goes well, it will be the time we reach 20k stars!

is there any way to see documentation for v2?

Hello everyone, I have released a public testing version "v0.2.2" for v2, which is used on some internal production projects already.

If you want to test it, please use the import path: "gorm.io/gorm", version: "v0.2.2", feedbacks welcome!

I am still working on the release note and writing documents, the final release date will depend on feedbacks, If everything goes well, it will be the time we reach 20k stars!

Official Oracle support?

Hi @jinzhu , I can see that the v2 code has been pushed to master. Is there a ChangeLog stating what's diff for v1 => v2?

Pushed to master?

If it is backward incompatible, it will break many things. Major releases should be released in separate folder module like /v2, according to https://blog.golang.org/v2-go-modules but i don't see v2 subdir

Pushed to master?

If it is backward incompatible, it will break many things. Major releases should be released in separate folder module like /v2, according to https://blog.golang.org/v2-go-modules but i don't see v2 subdir

V2 will use different import path, and the codebase already separated, so merged into master won't break things. V1 will keep using codebase from https://github.com/jinzhu/gorm

Syntax to group conditions something akin to the following would be nice to see in v2

db.Where(
  db.Where("pizza = ?", "pepperoni").And(db.Where("size = ?", "small").Or("size = ?", "medium")),
).Or(
  db.Where("pizza = ?", "hawaiian").And("size = ?", "xlarge"),
).Find(&pizzas)

output:

select * from pizzas where (pizza = 'pepperoni' and (size = 'small' or size = 'medium')) or (pizza = 'hawaiian' and size = 'xlarge')

upperdb demonstrates a neat implementation for composing conditions.
https://upper.io/db.v3/getting-started#composing-conditions-db-or-and-db-and

db.And(
  db.And(
    db.Cond{"age >": 21},
    db.Cond{"age <": 28},
  ),
  db.Or(
    db.Cond{"name": "Joanna"},
    db.Cond{"name": "John"},
    db.Cond{"name": "Jhon"},
  ),
)
( (age > 21 AND age < 28) AND (name = 'Joanna' OR name = 'John' OR name = 'Jhon') )

And hopefully composed conditions would support complex subqueries, not just basic operands/operators.

@jinzhu
I found that v2 has released a new version

Is there any changelog to show the difference with v1?

Is it more reasonable to use db, err := gorm.Open(sqlite.New("gorm.db"), &gorm.Config{})? Because now sqlite.Open is not connected to the database, while returning just a gorm.Dialector implement.

Is batch insertion supported? Upgrade now!!

I am working on the English version Release Note, it will come out sometime this week.

The api looks really nice. Are there plans for adding benchmarks?

The API looks really nice. Are there plans for adding benchmarks?

I have modified https://github.com/yusaer/orm-benchmark to test GORM v2's performance with prepared statement cache enabled and w/o default transaction (like others), although the suit seems to have some issues, the results are unstable at each run, in general, the results still pretty good.

It would be amazing to have benchmarks against go-pg.

@jinzhu
Hi, mysql string type in the table changed from varchar to longtext, is this a bug or a feature?

and

type Model struct {
    ID        uint      `json:"id" gorm:"primary_key"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

type Test struct {
    Model
    Name     string `json:"name"`
}

db.AutoMigrate(&Test{})

Error
Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(3) NULL,updated_atdatetime(3) NULL,namelongtext,PRIMARY KEY (id))' at line 1

v1's datetime becomes datetime(3),what should I pay attention to?

It would be amazing to have benchmarks against go-pg.

Tested against it, performance is similar if not better.

@jinzhu
Hi, mysql string type in the table changed from varchar to longtext, is this a bug or a feature?

and

type Model struct {
  ID        uint      `json:"id" gorm:"primary_key"`
  CreatedAt time.Time `json:"created_at"`
  UpdatedAt time.Time `json:"updated_at"`
}

type Test struct {
  Model
  Name     string `json:"name"`
}

db.AutoMigrate(&Test{})

For string fields without size, not a primary key, no index defined and don't have default values, its data type changed to longtext to avoid incautiously trimming for MySQL, you can define a size for it, it was 256 in v1.

Error
Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(3) NULL,updated_atdatetime(3) NULL,namelongtext,PRIMARY KEY (id))' at line 1

v1's datetime becomes datetime(3),what should I pay attention to?

What's your DB version?

Postgres ErrorCodes support please.
https://www.postgresql.org/docs/10/errcodes-appendix.html

I am available to discuss and work on this ErrorCodes support. would it be fine to discuss ErrorCodes support here or should I start a new issue? @jinzhu

@jinzhu

What's your DB version?

Version : 5.5.60-0+deb7u1
OS : Raspberry Pi
Hub : https://registry.hub.docker.com/r/hypriot/rpi-mysql

Postgres ErrorCodes support please.
https://www.postgresql.org/docs/10/errcodes-appendix.html

I am available to discuss and work on this ErrorCodes support. would it be fine to discuss ErrorCodes support here or should I start a new issue? @jinzhu

Hello, @tanweerdev Let's start a new issue, this issues is too long to discuss. thank you.

@jinzhu

What's your DB version?

Version : 5.5.60-0+deb7u1
OS : Raspberry Pi
Hub : https://registry.hub.docker.com/r/hypriot/rpi-mysql

datatype datetime(3) is supported since MySQL 5.6, is there any reason using 5.5?

datatype datetime(3) is supported since MySQL 5.6, is there any reason using 5.5?

hypriot/rpi-mysql is the most used mirror image of Raspberry Pi, it hasn't been updated for more than two years, you can see that there are 5m users, there's no better option at this time.
V2 has many advantages to drive upgrades, v1 is supported below 5.6 version, if only because the data support this causes upgrades, that is a regret.

datatype datetime(3) is supported since MySQL 5.6, is there any reason using 5.5?

hypriot/rpi-mysql is the most used mirror image of Raspberry Pi, it hasn't been updated for more than two years, you can see that there are 5m users, there's no better option at this time.
V2 has many advantages to drive upgrades, v1 is supported below 5.6 version, if only because the data support this causes upgrades, that is a regret.

Upgrade https://github.com/go-gorm/mysql and use it like:

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

db, err := gorm.Open(mysql.New(mysql.Config{
  DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name, refer https://github.com/go-sql-driver/mysql#dsn-data-source-name
  DisableDatetimePrecision: true, // disable datetime precision support (added since mysql 5.6)
  DefaultStringSize: 256, // add default size for string fields, by default, will use db type `longtext` for fields without size, not a primary key, no index defined and don't have default values
}), &gorm.Config{})

@jinzhu good job, thanks.

v2 looks great :)

This might be a stupid question but there's no Close() on DB anymore, I was wondering how the connection to the database is closed or when ?
Also wondering if there's a way to access the underlying sql.DB object like in v1 ?

@popsUlfr

Also wondering if there's a way to access the underlying sql.DB object like in v1 ?

Added DB method https://github.com/go-gorm/gorm/commit/e487f355a0838bbc158c5c7d848b35753d290884#diff-1f97616c9377ded874040d08c43d6165

This might be a stupid question but there's no Close() on DB anymore, I was wondering how the connection to the database is closed or when ?

As GORM using DB connection pool, so for an application, usually it is not necessary to use the Close method, so we removed it to avoid misuse

@jinzhu Thank you!

As GORM using DB connection pool, so for an application, usually it is not necessary to use the Close method, so we removed it to avoid misuse

In the case of sqlite3 for instance, wouldn't that be problematic if let's say the database is locked in exclusive mode but my application is done doing work with it and wants to release the resources to let another application open it ? Also some operations might be scheduled to run when closing a connection to the database.

Or if generally the work my application is doing with the database is short-lived and it wants to release the resources associated with the connection manually ?

It seems weird to me to reach the end of my application and potentially leave a database connection still open. In my opinion it still makes sense to expose a Close() but maybe document the fact that it might not be necessary in most cases.
Although with you exposing the underlying *sql.DB object, one may close it this way which is fine as well.

Although with you exposing the underlying *sql.DB object, one may close it this way which is fine as well.

Let's use this then ;)

in v2 I'm having an issue with uuid default value function gen_random_uuid() failing against postgres because gorm is wrapping it in single quotes in the CREATE TABLE query.

CREATE TABLE "harumphs" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"ok" uuid NOT NULL DEFAULT 'gen_random_uuid()',PRIMARY KEY ("id"))

``go type Harumph struct { gorm.Model Test uuid.UUIDgorm:"type:uuid;not null;default:gen_random_uuid()"`
}

in v1 it works because the migrator did not wrap the default in single quotes:
```sql
CREATE TABLE "harumphs" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"ok" uuid NOT NULL DEFAULT gen_random_uuid(),PRIMARY KEY ("id"))

I believe it may be related to the migrator checking field.DataType when building a SQL string.
I was hoping because my model uses uuid.UUID which is a [16]byte that it would not assign DataType of string but it is.
https://github.com/go-gorm/gorm/blob/master/migrator/migrator.go#L77

I'm seeing the following AutoMigrate err on fields of type pq.StringArray. This type works in gorm v1.

unsupported data type: &[]
type Harumph struct {
    gorm.Model
    Things pq.StringArray `gorm:"type:text[]"`
}

However if I define my own StringArray type with basic Scan & Value implementations, the unsupported data type err does not occur:

type StringArray []string

func (m StringArray) Value() (driver.Value, error) {
    return json.Marshal(m)
}

func (m *StringArray) Scan(src interface{}) error {
    b, ok := src.([]byte)
    if !ok {
        return errors.New("StringArray.Scan byte assertion failed")
    }

    var value StringArray
    if err := json.Unmarshal(b, &value); err != nil {
        return err
    }

    *m = value

    return nil
}

Here's a scenario that worked in v1 but is no longer working in v2. An embedded struct could implement Scan & Value interface methods. err & example below.

[error] unsupported data type: [123 34 67 111 110 116 101 110 116 34 58 110 117 108 108 125]
panic: runtime error: invalid memory address or nil pointer dereference
/gorm.io/gorm/schema.(*Schema).ParseField(0xc0000d8000, 0xc41f85, 0x8, 0x0, 0x0, 0x1042580, 0xd14580, 0xc41f8f, 0x12, 0x58, ...) 
/gorm.io/gorm/schema/field.go:297 +0xe65
/gorm.io/gorm/schema/schema.go:117 +0x59f
/gorm.io/gorm/statement.go:315 +0x5f
type Harumph struct {
    gorm.Model
    Embedded `gorm:"type:jsonb;"`
}

type Embedded struct {
    Content interface{}
}

func (m Embedded) Value() (driver.Value, error) {
    return json.Marshal(m)
}

func (m *Embedded) Scan(src interface{}) error {
    b, ok := src.([]byte)
    if !ok {
        return errors.New("Embedded.Scan byte assertion failed")
    }

    var value Embedded
    if err := json.Unmarshal(b, &value); err != nil {
        return err
    }

    *m = value

    return nil
}

A workaround is not embedding the struct, but for a particular pattern I've been using on a project, the embed is preferred.

Non embed works:

type Harumph struct {
    gorm.Model
    Named Embedded `gorm:"type:jsonb;"`
}

Byte slices ([]byte) also throw unsupported data type: &[] errors when migrating.

@ItsLeeOwen @popsUlfr

Fixed all those issues, big thanks for your report.

Please upgrade GORM to v0.2.7

Fixed all those issues, big thanks for your report.

It works good job.

With sqlite I noticed that any type information is completely discarded when creating a table :

CREATE TABLE `sqlar` (`name` ,`mode` ,`mtime` ,`sz` ,`data` ,PRIMARY KEY (`name`))

sqlite has dynamic typing sure, but storing the type intents has value.

Here's the model by the way (using sqlite archive) :

// SQLAR https://www.sqlite.org/sqlar.html
type SQLAR struct {
    // name of the file
    Name string `gorm:"COLUMN:name;TYPE:TEXT;PRIMARY_KEY"`
    // access permissions
    Mode uint32 `gorm:"COLUMN:mode;TYPE:INT"`
    // last modification time
    MTime time.Time `gorm:"COLUMN:mtime;TYPE:INT;AUTOUPDATETIME"`
    // original file size
    SZ uint64 `gorm:"COLUMN:sz;TYPE:INT"`
    // compressed content
    Data []byte `gorm:"COLUMN:data;TYPE:BLOB"`
}

// TableName sqlar
func (SQLAR) TableName() string {
    return "sqlar"
}

Also a question about AUTOUPDATETIME : sqlite does not have the shortcut like mysql has with ON UPDATE CURRENT_TIMESTAMP but it could be done with a trigger.
Does gorm inject the update timestamp during an update statement automatically ?

Hi @popsUlfr

Need to upgrade the database driver, for SQLite, the latest version is v1.0.2

Also a question about AUTOUPDATETIME : sqlite does not have the shortcut like mysql has with ON UPDATE CURRENT_TIMESTAMP but it could be done with a trigger.
Does gorm inject the update timestamp during an update statement automatically?

Yes

Need to upgrade the database driver, for SQLite, the latest version is v1.0.2

Ok done.

This is with gorm.io/driver/[email protected].

I did a simple create, updates and select but the AUTOUPDATETIME creates confusion when trying to read back the value :

ar := models.SQLAR{
    Name:  "myfile.txt",
    Mode:  0666,
    MTime: time.Now(),
    SZ:    uint64(len(content)),
    Data:  []byte(content),
}
db.Create(&ar)
db.Model(&ar).Updates(map[string]interface{}{"sz": len(newContent), "data": []byte(newContent)})
db.First(&ar)

Debug() mode output :

SELECT count(*) FROM sqlite_master WHERE type='table' AND name="sqlar"
CREATE TABLE `sqlar` (`name` TEXT,`mode` INT,`mtime` INT,`sz` INT,`data` BLOB,PRIMARY KEY (`name`))
INSERT INTO `sqlar` (`name`,`mode`,`mtime`,`sz`,`data`) VALUES ("myfile.txt",438,"2020-06-18 12:19:07.178",735,"<binary>")
UPDATE `sqlar` SET `data`="hello world",`sz`=11,`mtime`=1592475552 WHERE `name` = "myfile.txt"
SELECT * FROM `sqlar` WHERE `sqlar`.`name` = "myfile.txt" ORDER BY `sqlar`.`name` LIMIT 1
sql: Scan error on column index 2, name "mtime": unsupported Scan, storing driver.Value type int64 into type *time.Time

EDIT : also just realised that the types are there with v1.0.2 :) nice

MTime time.Time `gorm:"COLUMN:mtime;TYPE:INT;AUTOUPDATETIME"`

The type is not necessary, or set it to datetime or time.

Sure but shouldn't the scanner be able to infer the date from the number ?

Like time.Unix(1592475552, 0)

One is free to store the time as text, real or integer in an sqlite database :

  • TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
  • REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
  • INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.

To store jsonb in v1 I could add a gorm tag of type jsonb, and implement Scan/Value on the struct.

This no longer works with the migrator in v2 because the CREATE TABLE query is missing the type of the column.

pq: at or near ",": syntax error
CREATE TABLE "harumphs" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"embedded" ,PRIMARY KEY ("id"))
type Harumph struct {
    gorm.Model
    Embedded `gorm:"type:jsonb;"`
}

type Embedded struct {
    Content interface{}
}

In v2 I also must implement GormDBDataType(db *gorm.DB, field *schema.Field) string for the type to be defined in CREATE TABLE, or embed datatypes.JSON. The new features in datatypes.JSON looks very neat 👍, just want to report a breaking change from v1 json.

To store jsonb in v1 I could add a gorm tag of type jsonb, and implement Scan/Value on the struct.

This no longer works with the migrator in v2 because the CREATE TABLE query is missing the type of the column.

pq: at or near ",": syntax error
CREATE TABLE "harumphs" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"embedded" ,PRIMARY KEY ("id"))
type Harumph struct {
  gorm.Model
  Embedded `gorm:"type:jsonb;"`
}

type Embedded struct {
  Content interface{}
}

In v2 I also must implement GormDBDataType(db *gorm.DB, field *schema.Field) string for the type to be defined in CREATE TABLE, or embed datatypes.JSON. The new features in datatypes.JSON looks very neat 👍, just want to report a breaking change from v1 json.

Upgrade PostgreSQL driver to v0.2.0 should fix this.

Sure but shouldn't the scanner be able to infer the date from the number ?

Like time.Unix(1592475552, 0)

One is free to store the time as text, real or integer in an sqlite database :

  • TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
  • REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
  • INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.

You can just use int with tag autoupdatetime

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#multiple-fields-support-for-auto-creatingupdating-time-which-also-support-unix-nano-seconds-when-the-data-type-is-int


btw, error 'Scan, storing driver.Value type int64 into type *time.Time' returns from sql/database package as it doesn't support it

Upgrade PostgreSQL driver to v0.2.0 should fix this.

Thanks 👍 this works

// go.mod

gorm.io/driver/postgres v0.2.0 h1:Q93Q+keJ7rg0nDvCbjOGJ1ze8wEg86k00ofD70QRCTg=
gorm.io/driver/postgres v0.2.0/go.mod h1:nKAMTWR3HotfKKWcK4A/ZrxU55IqzONLyCxeXyHdzfA=
gorm.io/gorm v0.2.7 h1:hpXSTXLQfOUaITMjnQJ2ah+0uuQJLMsKcLytfqdteBw=
gorm.io/gorm v0.2.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=

@jinzhu in v2 is there a way to specify a many2many foreignkey column name on the jointable?

in v1 I was able to specify the column name on the jointable with association_jointable_foreignkey like this

type Harumph struct {
    gorm.Model
    Relationships []Harumph `gorm:"many2many:harumph_relationships;association_jointable_foreignkey:custom_column_name"`
}

which would create this table
Screen Shot 2020-06-18 at 10 39 23 AM

@jinzhu in v2 is there a way to specify a many2many foreignkey column name on the jointable?

in v1 I was able to specify the column name on the jointable with association_jointable_foreignkey like this

type Harumph struct {
  gorm.Model
  Relationships []Harumph `gorm:"many2many:harumph_relationships;association_jointable_foreignkey:custom_column_name"`
}

which would create this table
Screen Shot 2020-06-18 at 10 39 23 AM

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#association-improvements

I missed the comment for JoinForeignKey

// Many2Many: ForeignKey specifies the current model's primary key, JoinForeignKey specifies join table's foreign key that refers to ForeignKey
// References specifies the association's primary key, JoinReferences specifies join table's foreign key that refers to References

This works

type Harumph struct {
    gorm.Model
    Relationships []Harumph `gorm:"many2many:harumph_relationships;ForeignKey:id;JoinForeignKey:CustomColumnName;"`
}

Is there anything in place to get schema.Field info in v2? It looks like NewScope() has gone away

I'm looking for v1 functionality akin to

scope := db.NewScope(myModel)
field, ok := scope.FieldByName(fieldName)
dbFieldName := field.DBName

I see that schema is stored in cacheStore, but I haven't found a way to either pass in a cacheStore (its unexported in gorm.Config) or get the cacheStore from gorm.

In the meantime I'm doing this, but it would probably be more efficient to lookup from the cacheStore which gorm has already populated:

cacheStore := &sync.Map{}

schema, err := schema.Parse(doc, cacheStore, db.NamingStrategy)
if err != nil {
    return nil, err
}

field := schema.LookUpField(fieldName)
if nil == field {
    return nil, fmt.Errorf("unsupported field '%s'", fieldName)
}

Seeing a difficult to explain breaking change around Scan & Value with embedded structs.

When implementing Value on an embedded struct, the fields are no longer created as columns for the outer struct by the migrator, and can encounter some infinite recursion on the Valuer method during Create.

type Outer struct {
    gorm.Model
    OuterField      string
    OuterJSON interface{} `gorm:"type:jsonb;"`
    Inner
}

type Inner struct {
    InnerField       string
    InnerJSON interface{} `gorm:"type:jsonb;"`
}

func (m Inner) Value() (driver.Value, error) {
    fmt.Println("Inner Value", m)
    if v, err := json.Marshal(m.InnerJSON); err != nil {
        return nil, err
    } else {
        m.InnerJSON = v
    }

    return m, nil
}

func (m *Inner) Scan(src interface{}) error {
    fmt.Println("Inner Scan", src)
    b, ok := src.([]byte)
    if !ok {
        return errors.New("Inner.Scan byte assertion failed")
    }

    var value Inner
    if err := json.Unmarshal(b, &value); err != nil {
        return err
    }

    *m = value

    return nil
}

harumph := Outer{
    OuterField: "abc",
    OuterJSON: map[string]interface{}{
        "outer": "thing",
    },
    Inner: Inner{
        InnerField: "xyz",
        InnerJSON: map[string]interface{}{
            "inner": "stuff",
        },
    },
}


if err := db.Save(&harumph).Error; err != nil {
    log.Fatal(err)
}

var harumphs []Outer

if err := db.Find(&harumphs).Error; err != nil {
    log.Fatal(err)
}

Do you prefer reports as new Issues, or continue using this issue?

Is there anything in place to get schema.Field info in v2? It looks like NewScope() has gone away

https://github.com/go-gorm/gorm/blob/07960fe661b5ced50c9ca30e010aa26513eaf851/tests/migrate_test.go#L140-L151

func (m Inner) Value() (driver.Value, error) {
    fmt.Println("Inner Value", m)
    if v, err := json.Marshal(m.InnerJSON); err != nil {
        return nil, err
    } else {
        m.InnerJSON = v
    }

    return m, nil
}

It should returns m. InnerJSON but not itself?


Do you prefer reports as new Issues, or continue using this issue?

Let open new issues as this one is too long...

is there any chance to support nestedset in v2 ?

3065 Is there such a method? use inline condition for updating method(like db.Updates(updates, " xxx= ?", "xxx")))?

@mostafaznv @heww

Added SavePoint, RollbackTo, Nested Transaction Support

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#savepoint-rollbackto-support

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#nested-transaction-support

@jinzhu
thanks for reply.
but I didn't mean nested transaction.
It was nestedset (or hierarchy, or tree, or flat parent/child structure).

please see this:
https://github.com/vcraescu/gorm-nested

additional information:
https://en.m.wikipedia.org/wiki/Nested_set_model

I wanted to create tree for category model but gorm didn't handle it.
I think it would be perfect if gorm handle it in next release.

@jinzhu
thanks for reply.
but I didn't mean nested transaction.
It was nestedset (or hierarchy, or tree, or flat parent/child structure).

please see this:
https://github.com/vcraescu/gorm-nested

additional information:
https://en.m.wikipedia.org/wiki/Nested_set_model

I wanted to create tree for category model but gorm didn't handle it.
I think it would be perfect if gorm handle it in next release.

sounds like single-table association, refer: https://github.com/go-gorm/gorm/blob/e3292b3b4171cefe59694391729aa997640cc92e/utils/tests/models.go#L14-L26

Yes, I think so.
But how we can get ancestors and descendants? what about tree structure?
Are we using modified preorder tree traversal algorithm to fetch all children (tree)?

sounds like single-table association, refer:

https://github.com/go-gorm/gorm/blob/e3292b3b4171cefe59694391729aa997640cc92e/utils/tests/models.go#L14-L26

But how we can get ancestors and descendants? what about tree structure?

You could use Preload to get ancestors and descendants, e.g:

If you know it is a three-levels structure, then:

db.Preload("Children.Children.Children").Find(&tags)

And you can use Association Mode to manage its data, if you want more focused methods, I would suggest making a package like acts as tree to do the job.

@mostafaznv I don' think GORM should handle it to be honest.

If your tree is not that big the best way is to cache it since it will be much faster than multiple queries to fetch the hierarchy

E.g.

type Cache struct {
    db         *gorm.DB
    byID       map[string]*YOURGORMMODEL
    byParentID map[string][]string
    up         map[string][]string
}

GetTreeUp()
GetTreeDown()

@RichardLindhout
Maybe it's not GORM responsibility but I don't want to fetch the hierarchy with multiple queries (it's not a good approach).
I want to fetch it with one query (using lft, rgt method) and cache it for boost up performance.
I'm new in golang and came up from php/laravel community. I used this method there.
I wanted to implement it here in golang but I have very low experience in golang package development and it takes me time to handle it ...

Syntax to group conditions something akin to the following would be nice to see in v2

db.Where(
  db.Where("pizza = ?", "pepperoni").And(db.Where("size = ?", "small").Or("size = ?", "medium")),
).Or(
  db.Where("pizza = ?", "hawaiian").And("size = ?", "xlarge"),
).Find(&pizzas)

output:

select * from pizzas where (pizza = 'pepperoni' and (size = 'small' or size = 'medium')) or (pizza = 'hawaiian' and size = 'xlarge')

upperdb demonstrates a neat implementation for composing conditions.
https://upper.io/db.v3/getting-started#composing-conditions-db-or-and-db-and

db.And(
  db.And(
    db.Cond{"age >": 21},
    db.Cond{"age <": 28},
  ),
  db.Or(
    db.Cond{"name": "Joanna"},
    db.Cond{"name": "John"},
    db.Cond{"name": "Jhon"},
  ),
)
( (age > 21 AND age < 28) AND (name = 'Joanna' OR name = 'John' OR name = 'Jhon') )

And hopefully composed conditions would support complex subqueries, not just basic operands/operators.

@ItsLeeOwen
Supported https://github.com/go-gorm/gorm/commit/3d8f6f9cf9e225c964c66634b6b34df8e139f792#diff-5668006f0830727adf964efbee0c1a3bR143

Thank you for having context and foreign key improved @jinzhu 😋

@jinzhu is there any callback in v2 to mutate models after retrieval from database, similar to Scan?

AutoMigrate Many2many does not add foreignkey to join table

type User struct {
    gorm.Model
    FirstName string    `gorm:"not null" json:"firstname" validate:"required"`
    LastName  string    `gorm:"not null" json:"lastname" validate:"required"`
    Email     string    `gorm:"not null;unique" json:"email" validate:"required,email"`
    Phone     string    `gorm:"not null;unique" json:"phone"`
    RoleID    int       `gorm:"not null" json:"role"`
    Password  string    `gorm:"not null" json:"-"`
    Projects  []Project `gorm:"many2many:user_projects;ForeignKey:id;References:id"`
}
type Project struct {
    gorm.Model
    Name        string `gorm:"not null" json:"name" validate:"required"`
    ProjectType string `gorm:"not null;type:enum('onetime','business_unit')" json:"project_type"`
    Status      string `json:"status"`
}
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&domain.Project{}, &domain.User{})

this resulted in table user_projects created but with no foreign key, also user_projects created using default engine (MyISAM as my mariaDB engine default setting, not overrides by db.Set()), but the other table (projects and users) created with InnoDB.

consider supporting FOR UPDATE and FOR UPDATE NOWAIT for a row lock

select * from db_user where name='lisi' for update;
select * from db_user where name='lisi' for update nowait;
db.Model(user).Where("name = ?", "list").ForUpdate(true /* true = nowait OPTIONAL */).First(&user)

@jinzhu is there any callback in v2 to mutate models after retrieval from database, similar to Scan?

ScanRows? https://github.com/go-gorm/gorm/blob/master/finisher_api.go#L335

consider supporting FOR UPDATE and FOR UPDATE NOWAIT for a row lock

select * from db_user where name='lisi' for update;
select * from db_user where name='lisi' for update nowait;
db.Model(user).Where("name = ?", "list").ForUpdate(true /* true = nowait OPTIONAL */).First(&user)
DB.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users) // SELECT * FROM `users` FOR UPDATE

DB.Clauses(clause.Locking{
  Strength: "SHARE",
  Table: clause.Table{Name: clause.CurrentTable},
}).Find(&users)
// SELECT * FROM `users` FOR SHARE OF `users`

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#locking

Another thing, is it uniform (standard) capitalization rules

I have found that in some places, uppercase and lowercase are used, and there seems to be no uniform standard

type Blog struct {
  ID         uint   `gorm:"primary_key"`
  Locale     string `gorm:"primary_key"`
  Subject    string
  Body       string
  // 默认用使用对象的全部主键 (ID, Locale) 来创建关联表
  Tags       []Tag `gorm:"many2many:blog_tags;"`
  // 对于 Blog, Tag 都将只使用 ID 做为主键
  SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
  // 对于 Blog 使用ID, Locale作为主键, Tag 只使用ID做为主键
  LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
}

many2many/primary_key/unique/index is lowercase
References/ForeignKey is uppercase

same with var style. why ForeignKey, not foreign_key?

These are easy to confuse how to use, I hope there is a unified rule and style

AutoMigrate Many2many does not add foreignkey to join table

type User struct {
  gorm.Model
  FirstName string    `gorm:"not null" json:"firstname" validate:"required"`
  LastName  string    `gorm:"not null" json:"lastname" validate:"required"`
  Email     string    `gorm:"not null;unique" json:"email" validate:"required,email"`
  Phone     string    `gorm:"not null;unique" json:"phone"`
  RoleID    int       `gorm:"not null" json:"role"`
  Password  string    `gorm:"not null" json:"-"`
  Projects  []Project `gorm:"many2many:user_projects;ForeignKey:id;References:id"`
}
type Project struct {
  gorm.Model
  Name        string `gorm:"not null" json:"name" validate:"required"`
  ProjectType string `gorm:"not null;type:enum('onetime','business_unit')" json:"project_type"`
  Status      string `json:"status"`
}
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&domain.Project{}, &domain.User{})

this resulted in table user_projects created but with no foreign key, also user_projects created using default engine (MyISAM as my mariaDB engine default setting, not overrides by db.Set()), but the other table (projects and users) created with InnoDB.

Fixed, please upgrade to v0.2.11

Another thing, is it uniform (standard) capitalization rules

I have found that in some places, uppercase and lowercase are used, and there seems to be no uniform standard

type Blog struct {
  ID         uint   `gorm:"primary_key"`
  Locale     string `gorm:"primary_key"`
  Subject    string
  Body       string
  // 默认用使用对象的全部主键 (ID, Locale) 来创建关联表
  Tags       []Tag `gorm:"many2many:blog_tags;"`
  // 对于 Blog, Tag 都将只使用 ID 做为主键
  SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
  // 对于 Blog 使用ID, Locale作为主键, Tag 只使用ID做为主键
  LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
}

many2many/primary_key/unique/index is lowercase
References/ForeignKey is uppercase

same with var style. why ForeignKey, not foreign_key?

These are easy to confuse how to use, I hope there is a unified rule and style

Cases don't matter, so both foreignkey and ForeignKey are ok

primary_key is just for compatibility, recommend to use PrimaryKey, and you should use CamelCase–style for all other tags.

Another thing, is it uniform (standard) capitalization rules
I have found that in some places, uppercase and lowercase are used, and there seems to be no uniform standard

type Blog struct {
  ID         uint   `gorm:"primary_key"`
  Locale     string `gorm:"primary_key"`
  Subject    string
  Body       string
  // 默认用使用对象的全部主键 (ID, Locale) 来创建关联表
  Tags       []Tag `gorm:"many2many:blog_tags;"`
  // 对于 Blog, Tag 都将只使用 ID 做为主键
  SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
  // 对于 Blog 使用ID, Locale作为主键, Tag 只使用ID做为主键
  LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
}

many2many/primary_key/unique/index is lowercase
References/ForeignKey is uppercase
same with var style. why ForeignKey, not foreign_key?
These are easy to confuse how to use, I hope there is a unified rule and style

Cases don't matter, so both foreignkey and ForeignKey are ok

primary_key is just for compatibility, recommend to use PrimaryKey, and you should use CamelCase–style for all other tags.

So we need to give a clear explanation in the document, which style to use and this should reduce developer doubts

BTW: lower camel case is diff wtih upper camel case

index > Index
unique > Unique
many2many > Many2Many

So we need to give a clear explanation in the document, which style to use and this should reduce developer doubts

Yes, will explain it when rewriting the document

BTW: lower camel case is diff wtih upper camel case

GORM itself doesn't care cases, but I would prefer the upper camel case

Hi, running this code :
`
//db is *gorm.DB and already opened
db = db.Order("id desc")
db.Model(result).Count(&count)
db.Limit(p.Limit).Offset(offset).Find(result)

`
produce undesirable output for the second query (second query still has count(1) ) :

2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:61
[5.928ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL ORDER BY id desc

2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:69
[0.713ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL AND users.deleted_at IS NULL ORDER BY id desc LIMIT 10

Hi, running this code :
`
//db is *gorm.DB and already opened
db = db.Order("id desc")
db.Model(result).Count(&count)
db.Limit(p.Limit).Offset(offset).Find(result)

`
produce undesirable output for the second query (second query still has count(1) ) :

2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:61
[5.928ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL ORDER BY id desc
2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:69
[0.713ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL AND users.deleted_at IS NULL ORDER BY id desc LIMIT 10

Hello @ahmadfarisfs

If you want to share a DB like this, you should use db = db.Order("id desc").Session(&Session{WithConditions:true}).

BTW, Count with Order doesn't work with some db drivers, any reason write code like this?

Hi, running this code :
//db is *gorm.DB and already opened db = db.Order("id desc") db.Model(result).Count(&count) db.Limit(p.Limit).Offset(offset).Find(result)
produce undesirable output for the second query (second query still has count(1) ) :

2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:61
[5.928ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL ORDER BY id desc
2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:69
[0.713ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL AND users.deleted_at IS NULL ORDER BY id desc LIMIT 10

Hello @ahmadfarisfs

If you want to share a DB like this, you should use db = db.Order("id desc").Session(&Session{WithConditions:true}).

BTW, Count with Order doesn't work with some db drivers, any reason write code like this?

Oh i see. I tried to use this (works on v1): https://github.com/biezhi/gorm-paginator using gorm v2, apparently its not plug and play. Thanks @jinzhu !

@jinzhu Does v2 have any support for specifying sql column enums based on a Go enum? Where provided the below scenario, CREATE TABLE would include the enums?

type MyEnum string

const (
    EnumA MyEnum = "a"
    EnumB MyEnum = "b"
    EnumC MyEnum = "c"
)

type MyModel struct {
    gorm.Model
    Type MyEnum
}

Instead of manually defining them on the struct tag?

type MyModel struct {
    gorm.Model
    Type MyEnum `gorm:"type:enum('a','b','c');"`
}

@jinzhu Does v2 have any support for specifying sql column enums based on a Go enum? Where provided the below scenario, CREATE TABLE would include the enums?

type MyEnum string

const (
  EnumA MyEnum = "a"
  EnumB MyEnum = "b"
  EnumC MyEnum = "c"
)

type MyModel struct {
  gorm.Model
  Type MyEnum
}

Instead of manually defining them on the struct tag?

type MyModel struct {
  gorm.Model
  Type MyEnum `gorm:"type:enum('a','b','c');"`
}

Hi, GORM can't know defined MyEnum values, but you need to set the type with tag.

But I think it is better to define a method GormDataType for MyEnum, and it returns above type, refer: https://github.com/go-gorm/datatypes/blob/546ecd30e4baf6e1f33085e185ebb8bf8b7d8235/json.go#L53 for example

Hi, running this code :
//db is *gorm.DB and already opened db = db.Order("id desc") db.Model(result).Count(&count) db.Limit(p.Limit).Offset(offset).Find(result)
produce undesirable output for the second query (second query still has count(1) ) :

2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:61
[5.928ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL ORDER BY id desc
2020/06/21 23:15:33 D:/Gits/mrkrab-be/utilities/pagination.go:69
[0.713ms] [rows:1] SELECT count(1) FROM users WHERE users.deleted_at IS NULL AND users.deleted_at IS NULL ORDER BY id desc LIMIT 10

Hello @ahmadfarisfs

If you want to share a DB like this, you should use db = db.Order("id desc").Session(&Session{WithConditions:true}).

BTW, Count with Order doesn't work with some db drivers, any reason write code like this?

@jinzhu I did what you said, but the result is still the same

orm=orm.Table(xxx).Session(&gorm.Session{WithConditions: true})
orm = orm.Where("name= ?","use111")
orm = orm.Count(&total).Offset(int(page * req.Limit)).Limit(20).Find(&users)

//SQL:
SELECT count(1) FROM `xxx` WHERE  xxx.`name` = ("use111")
//Why? 
SELECT count(1) FROM `xxx` WHERE  xxx.`name` = ("use111") LIMIT 10,20

3065

tx :=orm.Table(xxx).Where("name= ?","use111").Session(&gorm.Session{WithConditions: true})
tx.Count(&total)
tx.Offset(int(page * req.Limit)).Limit(20).Find(&users)
tx :=orm.Table(xxx).Where("name= ?","use111").Session(&gorm.Session{WithConditions: true})
tx.Count(&total)
tx.Offset(int(page * req.Limit)).Limit(20).Find(&users)

thanks

Hi @jinzhu ,
I don't know what I'm doing wrong, but "total" always returns zero (0):

package main

import (
    "fmt"
    "log"
    "os"
    "time"

    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

type User struct {
    Id   int
    Name string
    Date time.Time
}

var Default = logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
    SlowThreshold: 100 * time.Millisecond,
    LogLevel:      logger.Info,
    Colorful:      true,
})

func main() {
    dsn := "root:password@tcp(localhost:3306)/db?charset=utf8&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: Default})

    _ = db.Migrator().DropTable(&User{})

    _ = db.AutoMigrate(&User{})

    now := time.Date(2010, 1, 1, 1, 1, 1, 1, time.Now().Location())
    users := []*User{{Name: "mark", Date: now},
        {Name: "jhon", Date: now}}
    err := db.Create(&users).Error
    fmt.Println(err)

    var total int64
    db = db.Table("users").Where("name= ?", "mark").Session(&gorm.Session{WithConditions: true})
    db.Count(&total)
    fmt.Println(total)

    db.Order("id desc").Limit(10).Offset(0).Find(&users)
    fmt.Println(users[0])

}

Hi @jinzhu ,
I don't know what I'm doing wrong, but "total" always returns zero (0):

package main

import (
  "fmt"
  "log"
  "os"
  "time"

  "gorm.io/driver/mysql"
  "gorm.io/gorm"
  "gorm.io/gorm/logger"
)

type User struct {
  Id   int
  Name string
  Date time.Time
}

var Default = logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
  SlowThreshold: 100 * time.Millisecond,
  LogLevel:      logger.Info,
  Colorful:      true,
})

func main() {
  dsn := "root:password@tcp(localhost:3306)/db?charset=utf8&parseTime=True&loc=Local"
  db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: Default})

  _ = db.Migrator().DropTable(&User{})

  _ = db.AutoMigrate(&User{})

  now := time.Date(2010, 1, 1, 1, 1, 1, 1, time.Now().Location())
  users := []*User{{Name: "mark", Date: now},
      {Name: "jhon", Date: now}}
  err := db.Create(&users).Error
  fmt.Println(err)

  var total int64
  db = db.Table("users").Where("name= ?", "mark").Session(&gorm.Session{WithConditions: true})
  db.Count(&total)
  fmt.Println(total)

  db.Order("id desc").Limit(10).Offset(0).Find(&users)
  fmt.Println(users[0])

}

Fixed, thank you for your report, please upgrade to v0.2.15

@jinzhu in v2 how can I get the model table name? Before I can do db.NewScope(&user).TableName(), but now?

@jinzhu I've tried to change the log level with db.Config.Logger.LogMode(logger.Silent) but I still see the gorm log messages on stdout. If I change the logger in this way, all works as expected.

db.Config.Logger = logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
  SlowThreshold: 100 * time.Millisecond,
  LogLevel:      logger.Silent,
  Colorful:      true,
})

@jinzhu in v2 how can I get the model table name? Before I can do db.NewScope(&user).TableName(), but now?

Hi @pioz, you can do it like this, btw, could you let me know your use case?

stmt := &gorm.Statement{DB: DB}
stmt.Parse(value)
stmt.Table

@jinzhu I've tried to change the log level with db.Config.Logger.LogMode(logger.Silent) but I still see the gorm log messages on stdout.

Change LogMode will create a new logger to avoid affect other projects using the same default logger, refer:
https://github.com/go-gorm/gorm/blob/7e1fa4a44de7b1febfc5620cab4afe77276b4a72/logger/logger.go#L102-L106

So you can change the logger like:

db.Config.Logger = db.Config.Logger.LogMode(logger.Silent)

I tried to immigrate from jinzhu to go-gorm, I did get a lot of errors, missing methods (some turned out in other package, ex HasTable...), some are really missing

    db.DB().SetMaxIdleConns(50)
    db.DB().SetMaxOpenConns(1500)

Another problem is the code is kind of mixed github.com and gorm.io,

        db.Logger.LogMode(logger.Info)

github.com/go-gorm/gorm/gorm.go imports

    "gorm.io/gorm/clause"
    "gorm.io/gorm/logger"
    "gorm.io/gorm/schema"

Finally I gave up.
when it will be ready for production for this go-gorm?

@seaguest db.DB() returns two results includes error message. Maybe you are using outdated gorm v2?

Can the array and map in postgresql be fully supported?

Can the array and map in postgresql be fully supported?

It is possible to fully support it like https://github.com/go-gorm/datatypes, but we haven't started to work on Postgres specified-thing, Pull Request welcome ;)

@jinzhu in v2 how can I get the model table name? Before I can do db.NewScope(&user).TableName(), but now?

Hi @pioz, you can do it like this, btw, could you let me know your use case?

stmt := &gorm.Statement{DB: DB}
stmt.Parse(value)
stmt.Table

I need the table name to create a trigger.

I handy shortcut method should be great: db.TableName(&user) => "users"

@jinzhu Could you please add support for generation of migration files like djangos makemigrations? Django's orm is pretty stable, very useful and has lot of good features.

Ref: https://docs.djangoproject.com/en/3.0/ref/django-admin/#django-admin-makemigrations

Example Django application with migrations:

https://github.com/stadtulm/cykel/tree/master/bikesharing/migrations

I have imp the migrations with gormV1 due to i am a pythoner as well .Btw Automigrate maybe a better way for modern app.

@jinzhu I am trying to migrate this model:

type User struct {
    ID       uint64 `gorm:"primary_key;type:bigint unsigned auto_increment"`
    Username string
}

type Product struct {
    ID              uint64
    Name            string `gorm:"type:varchar(255)"`
    CollectorNumber string
    Condition       string
    BundleSize      int    `gorm:"type:smallint"`
    Language        string
    PropertyType    string
    UserId          uint64 `gorm:"not null;autoincrement:false"`
    User            *User  `gorm:"foreignkey:UserId"`
}

But I get this error:

Error 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key
[0.469ms] [rows:0] CREATE TABLE `products` (`id` bigint unsigned AUTO_INCREMENT,`name` varchar(255),`collector_number` longtext,`condition` longtext,`bundle_size` smallint,`language` longtext,`property_type` longtext,`user_id` bigint unsigned auto_increment NOT NULL,PRIMARY KEY (`id`),CONSTRAINT `fk_products_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))

Seems that gorm try to add auto_increment option to foreign_key column by default, also if I set in the tag AutoIncrement:false.

Also, the default type for int is BIGINT and for string is LONGTEXT. In my opinion, it should be INT and VARCHAR(255) (Rails default types).

Seems that gorm try to add auto_increment option to foreign_key column by default, also if I set in the tag AutoIncrement:false.

GORM WON'T add auto_increment option to foreign_key column by default, but GORM will use your primary key's data type as foreign key's data type to make sure they are using same data type, then we can create a database foreign key.

The issue is caused by you are setting type:bigint unsigned auto_increment to user's ID, change your User model to this should be ok.

type User struct {
    ID       uint64 `gorm:"primary_key;type:bigint unsigned"` // unsigned bigint is uint64's default data type, so it is not necessary.
    Username string
}

Also, the default type for int is BIGINT

You can use int32 or int16

and for string is LONGTEXT. In my opinion, it should be INT and VARCHAR(255) (Rails default types).

Change the DefaultStringSize when initializing MySQL driver

https://github.com/go-gorm/mysql/blob/544aababdcc9ddc4c75c4056ae46c7c01b07b911/mysql.go#L18-L25

@jinzhu I'm trying to migrate this model:

type User struct {
    Id        uint64
    Email     string    `gorm:"type:varchar(255);not null;index:,unique"`
    Username  string    `gorm:"type:varchar(255);not null;default:'foo'"`
}

But I get Error 1064: You have an error in your SQL syntax;:

CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`email` varchar(255) NOT NULL,`username` varchar(255) NOT NULL DEFAULT foo,PRIMARY KEY (`id`),INDEX idx_users_email (`email`))

Seems that the default value is not quoted.
How can I set the default value? I need to set also the blank string as default value (name varchar(255) NOT NULL DEFAULT '').

Also the index on email field is not unique, also if the tag specify unique.
Thank you!

@jinzhu I'm trying to migrate this model:

type User struct {
  Id        uint64
  Email     string    `gorm:"type:varchar(255);not null;index:,unique"`
  Username  string    `gorm:"type:varchar(255);not null;default:'foo'"`
}

But I get Error 1064: You have an error in your SQL syntax;:

CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`email` varchar(255) NOT NULL,`username` varchar(255) NOT NULL DEFAULT foo,PRIMARY KEY (`id`),INDEX idx_users_email (`email`))

Seems that the default value is not quoted.
How can I set the default value? I need to set also the blank string as default value (name varchar(255) NOT NULL DEFAULT '').

Also the index on email field is not unique, also if the tag specify unique.
Thank you!

tests passed, make sure you are using latest release of GORM and MySQL driver.

https://github.com/go-gorm/gorm/blob/fb56fe993af7ce155662c17fd24f94722fb3a8eb/tests/default_value_test.go#L9-L37

@jinzhu I'm trying to migrate this model:

type User struct {
    Id        uint64
    Email     string    `gorm:"type:varchar(255);not null;index:,unique"`
    Username  string    `gorm:"type:varchar(255);not null;default:'foo'"`
}

But I get Error 1064: You have an error in your SQL syntax;:

CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`email` varchar(255) NOT NULL,`username` varchar(255) NOT NULL DEFAULT foo,PRIMARY KEY (`id`),INDEX idx_users_email (`email`))

Seems that the default value is not quoted.
How can I set the default value? I need to set also the blank string as default value (name varchar(255) NOT NULL DEFAULT '').
Also the index on email field is not unique, also if the tag specify unique.
Thank you!

tests passed, make sure you are using latest release of GORM and MySQL driver.

https://github.com/go-gorm/gorm/blob/fb56fe993af7ce155662c17fd24f94722fb3a8eb/tests/default_value_test.go#L9-L37

I've upgraded to gorm v0.2.15 and MySQL driver v0.2.6, but the issue persists (I can't find a way to specify a default value). This seems to happen only when I use type:VARCHAR(255);default:'foo'.

The index is now created correctly (unique).

This seems to happen only when I use type:VARCHAR(255);default:'foo'.

Yes, I can reproduce it with the type:VARCHAR(255);, fixed it in v0.2.16.

BTW, it not necessary to set the data type like this, you can just set the size then GORM can generate type compatible with all database drivers

type User struct {
  Name string  `gorm:"size:255;not null;index:,unique"`
}

For MySQL, if you want to change all string fields's default size to 255, you can initialize *gorm.DB like this:

db, err := gorm.Open(mysql.New(mysql.Config{
  DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", 
  DefaultStringSize: 255,
}), &gorm.Config{})

This seems to happen only when I use type:VARCHAR(255);default:'foo'.

Yes, I can reproduce it with the type:VARCHAR(255);, fixed it in v0.2.16.

@jinzhu Now works. But, if I use the following tag the default value is not set (default to blank string):

Name string `gorm:"size:255;not null;default:''"`

In this way when I run a query from cli I have to set the name field:

INSERT INTO users (email) VALUES ('[email protected]'); -- does not work
INSERT INTO users (email,name) VALUES ('[email protected]', '');

I think is this if https://github.com/go-gorm/gorm/blob/c5feff1591518ba500898dc6d1a5b8eb7bee1092/migrator/migrator.go#L67

@jinzhu Now works. But, if I use the following tag the default value is not set (default to blank string):

Name string `gorm:"size:255;not null;default:''"`

Fixed it, update to v0.2.17, thank you for your report.

@jinzhu I have the follow schema:

CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `first_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `last_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_users_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

My GO model is:

type User struct {
    ID        uint64    `faker:"-"`
    Email     string    `gorm:"size:255;not null;index:,unique" faker:"email,unique"`
    Username  string    `gorm:"size:255;not null;default:''"`
    FirstName string    `gorm:"size:255;not null;default:''"`
    LastName  string    `gorm:"size:255;not null;default:''"`
    CreatedAt time.Time `gorm:"type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" faker:"-"`
    UpdatedAt time.Time `gorm:"type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" faker:"-"`
}

Now I wish to create a new user with:

u := User{Email: "[email protected]"}
db.Create(&u)

but I get the following error:

Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1
[0.544ms] [rows:0] INSERT INTO `users` (`email`,`username`,`first_name`,`last_name`,`created_at`,`updated_at`) VALUES ("[email protected]","","","","0000-00-00 00:00:00","0000-00-00 00:00:00")

(notice that is strange that the error message say ...Incorrect datetime value: '0000-00-00' for... instead of ...Incorrect datetime value: '0000-00-00 00:00:00' for...)

Is it possible to achieve this behavior, or I need to use a pointer *time.Time?
I've seen that similar behavior works for string datatype:

type User struct {
    ID        uint64    `faker:"-"`
    ...
    Username  string    `gorm:"size:255;not null;default:'foo'"`
    ...
}
u := User{Email: "[email protected]"}
db.Create(&u)

create a record with field username equal to "foo" (the default value).

@jinzhu, it seems that ignored columns are not being ignored on select.

type Person struct {
    Id    uuid.UUID `gorm:"column:id;primary_key"`
    Code  string    `gorm:"column:code"`
    Name  string    `gorm:"column:name"`
    Email string    `gorm:"-"`
}

person := &Person{
    Code:  "abc",
    Email: "[email protected]",
}

if err := db.Where(person).Find(person); err != nil {
    panic(err)
}
pq: column person.Email does not exist
SELECT * FROM "person" WHERE "person"."code" = 'abc' AND "person"."Email" = '[email protected]'

My real case is much more complex than that, I just can't simply not set the field.

@jinzhu I have the follow schema:

CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `first_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `last_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_users_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

My GO model is:

type User struct {
  ID        uint64    `faker:"-"`
  Email     string    `gorm:"size:255;not null;index:,unique" faker:"email,unique"`
  Username  string    `gorm:"size:255;not null;default:''"`
  FirstName string    `gorm:"size:255;not null;default:''"`
  LastName  string    `gorm:"size:255;not null;default:''"`
  CreatedAt time.Time `gorm:"type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" faker:"-"`
  UpdatedAt time.Time `gorm:"type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" faker:"-"`
}

Now I wish to create a new user with:

u := User{Email: "[email protected]"}
db.Create(&u)

but I get the following error:

Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1
[0.544ms] [rows:0] INSERT INTO `users` (`email`,`username`,`first_name`,`last_name`,`created_at`,`updated_at`) VALUES ("[email protected]","","","","0000-00-00 00:00:00","0000-00-00 00:00:00")

(notice that is strange that the error message say ...Incorrect datetime value: '0000-00-00' for... instead of ...Incorrect datetime value: '0000-00-00 00:00:00' for...)

Is it possible to achieve this behavior, or I need to use a pointer *time.Time?
I've seen that similar behavior works for string datatype:

type User struct {
  ID        uint64    `faker:"-"`
    ...
  Username  string    `gorm:"size:255;not null;default:'foo'"`
    ...
}
u := User{Email: "[email protected]"}
db.Create(&u)

create a record with field username equal to "foo" (the default value).

If you set the data type to *time.Time or NullTime it should work.

But for a CreatedAt time field, GORM should set current time to the field when creating, it wasn't due to you customized its data type, have fixed this issue in v0.2.18

@jinzhu, it seems that ignored columns are not being ignored on select.

type Person struct {
  Id    uuid.UUID `gorm:"column:id;primary_key"`
  Code  string    `gorm:"column:code"`
  Name  string    `gorm:"column:name"`
  Email string    `gorm:"-"`
}

person := &Person{
  Code:  "abc",
  Email: "[email protected]",
}

if err := db.Where(person).Find(person); err != nil {
  panic(err)
}
pq: column person.Email does not exist
SELECT * FROM "person" WHERE "person"."code" = 'abc' AND "person"."Email" = '[email protected]'

My real case is much more complex than that, I just can't simply not set the field.

Please refer:
https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#field-permissions-support-readonly-writeonly-createonly-updateonly-ignored

We have introduced field permission support, supports: readonly, writeonly, createonly, updateonly, ignored

We should use readonly in this case.

type User struct {
  Name string `gorm:"<-:create"` // allow read and create
  Name string `gorm:"<-:update"` // allow read and update
  Name string `gorm:"<-"`        // allow read and write (create and update)
  Name string `gorm:"->:false;<-:create"` // createonly
  Name string `gorm:"->"` // readonly
  Name string `gorm:"-"`  // ignored
}

@jinzhu, it seems that ignored columns are not being ignored on select.

type Person struct {
    Id    uuid.UUID `gorm:"column:id;primary_key"`
    Code  string    `gorm:"column:code"`
    Name  string    `gorm:"column:name"`
    Email string    `gorm:"-"`
}

person := &Person{
    Code:  "abc",
    Email: "[email protected]",
}

if err := db.Where(person).Find(person); err != nil {
    panic(err)
}
pq: column person.Email does not exist
SELECT * FROM "person" WHERE "person"."code" = 'abc' AND "person"."Email" = '[email protected]'

My real case is much more complex than that, I just can't simply not set the field.

Please refer:
https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#field-permissions-support-readonly-writeonly-createonly-updateonly-ignored

We have introduced field permission support, supports: readonly, writeonly, createonly, updateonly, ignored

We should use readonly in this case.

type User struct {
  Name string `gorm:"<-:create"` // allow read and create
  Name string `gorm:"<-:update"` // allow read and update
  Name string `gorm:"<-"`        // allow read and write (create and update)
  Name string `gorm:"->:false;<-:create"` // createonly
  Name string `gorm:"->"` // readonly
  Name string `gorm:"-"`  // ignored
}

I tried the readonly notation, same error.

pq: column person.email does not exist
[17.047ms] [rows:0] SELECT * FROM "person" WHERE "person"."code" = 'abc' AND "person"."email" = '[email protected]'

The only difference is that the column name is parsed in lowercase.

I tried the readonly notation, same error.

Could you create a reproducible pull request here? https://github.com/go-gorm/playground

Thank you.

I tried the readonly notation, same error.

Could you create a reproducible pull request here? https://github.com/go-gorm/playground

Thank you.

https://github.com/go-gorm/playground/pull/8

@jinzhu Is the NewRecord method going to be included in v2?

@jinzhu, isn't gorm throwing ErrRecordNotFound anymore?

@jinzhu Is the NewRecord method going to be included in v2?

NewRecord just checked the primary key value is blank or not, many people misused it, so we decided to remove this method.

@jinzhu, isn't gorm throwing ErrRecordNotFound anymore?

Only throw ErrRecordNotFound error when you are using First, Last, Take to find a record.

I just tried to convert a project from gorm v1 to gorm v2, the callback API seems to be harder to use, on V1, I was doing:

func beforeCreate(sfn *snowflake.Node) func(*gorm.Scope) {
    return func(scope *gorm.Scope) {
        id := sfn.Generate().Int64()
        if err := scope.SetColumn("ID", id); err != nil {
            panic(err)
        }
    }
}

on V2, this is how I made it work:

func beforeCreate(sfn *snowflake.Node) func(*gorm.DB) {
    return func(db *gorm.DB) {
        s := reflect.ValueOf(db.Statement.Dest).Elem()
        if s.Kind() == reflect.Struct {
            f := s.FieldByName("ID")
            if f.IsValid() && f.CanSet() {
                id := sfn.Generate().Int64()
                f.SetInt(id)
            }
        }
    }
}

in both cases, it's registered like this:

db.Callback().Create().Before("gorm:create").Register("snowflake_id", beforeCreate(sfn))

Is there already an easier method available? Do you have plans to add new helpers that may help?

Thank you

I just tried to convert a project from gorm v1 to gorm v2, the callback API seems to be harder to use, on V1, I was doing:

func beforeCreate(sfn *snowflake.Node) func(*gorm.Scope) {
  return func(scope *gorm.Scope) {
      id := sfn.Generate().Int64()
      if err := scope.SetColumn("ID", id); err != nil {
          panic(err)
      }
  }
}

on V2, this is how I made it work:

func beforeCreate(sfn *snowflake.Node) func(*gorm.DB) {
  return func(db *gorm.DB) {
      s := reflect.ValueOf(db.Statement.Dest).Elem()
      if s.Kind() == reflect.Struct {
          f := s.FieldByName("ID")
          if f.IsValid() && f.CanSet() {
              id := sfn.Generate().Int64()
              f.SetInt(id)
          }
      }
  }
}

in both cases, it's registered like this:

db.Callback().Create().Before("gorm:create").Register("snowflake_id", beforeCreate(sfn))

Is there already an easier method available? Do you have plans to add new helpers that may help?

Thank you

db.Statement.Schema.LookUpField("ID").Set(db.Statement.ReflectValue, sfn.Generate().Int64())

fyi, I needed to add some additional checks to avoid triggering panic in some cases:

func beforeCreate(sfn *snowflake.Node) func(*gorm.DB) {
        return func(db *gorm.DB) {
                if db.Statement == nil || db.Statement.Schema == nil || !db.Statement.ReflectValue.IsValid() {
                        return
                }
                db.Statement.Schema.LookUpField("ID").Set(db.Statement.ReflectValue, sfn.Generate().Int64())
        }
}

@jinzhu, regarding many2many relationship

type User struct {
    IdUser    int64     `gorm:"column:idUser;primary_key"`
    Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`
}

type Company struct {
    IdCompany int64 `gorm:"column:idCompany;primary_key"`
}

db, _ := gorm.Open(sqlite.Open("gorm"), &gorm.Config{
    DryRun: true,
    NamingStrategy: schema.NamingStrategy{
        SingularTable: true,
    },
    Logger: logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
        LogLevel: logger.Info,
    }),
})

db.Model(User{}).Association("Companies").Find([]Company{})
SELECT *
  FROM `company`
  JOIN `credentials` ON `credentials`.`company_id_company` = `company`.`idCompany`
   AND `user_id_user` IN (NULL)
  1. Naming Strategy seems not to be working properly for junction table
  2. If I'm not mistaken, ForeignKey and References should do the trick when not following the naming convention

@jinzhu, regarding many2many relationship

type User struct {
  IdUser    int64     `gorm:"column:idUser;primary_key"`
  Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`
}

type Company struct {
  IdCompany int64 `gorm:"column:idCompany;primary_key"`
}

db, _ := gorm.Open(sqlite.Open("gorm"), &gorm.Config{
  DryRun: true,
  NamingStrategy: schema.NamingStrategy{
      SingularTable: true,
  },
  Logger: logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
      LogLevel: logger.Info,
  }),
})

db.Model(User{}).Association("Companies").Find([]Company{})
SELECT *
  FROM `company`
  JOIN `credentials` ON `credentials`.`company_id_company` = `company`.`idCompany`
   AND `user_id_user` IN (NULL)
  1. Naming Strategy seems not to be working properly for junction table
  2. If I'm not mistaken, ForeignKey and References should do the trick when not following the naming convention

Fixed that, thank you for your report. https://github.com/go-gorm/gorm/commit/2d048d9ece097f86ecf77872ba050c0ce242bfc0

2.0是否支持查询后对数据处理? 类似于获取器的功能!!

I added the SetColumn method back, also added a new method Changed, please check out https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#use-changed-to-check-fields-changed-or-not

@moul

Hi @jinzhu,

Is it possible to continue using the date function in queries in v2?

db.Model(&Object{}).Select("date(last_reading)").Group("date(in_objects.last_reading)")

First of all, Thanks!

@jinzhu, regarding many2many relationship

type User struct {
    IdUser    int64     `gorm:"column:idUser;primary_key"`
    Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`
}

type Company struct {
    IdCompany int64 `gorm:"column:idCompany;primary_key"`
}

db, _ := gorm.Open(sqlite.Open("gorm"), &gorm.Config{
    DryRun: true,
    NamingStrategy: schema.NamingStrategy{
        SingularTable: true,
    },
    Logger: logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
        LogLevel: logger.Info,
    }),
})

db.Model(User{}).Association("Companies").Find([]Company{})
SELECT *
  FROM `company`
  JOIN `credentials` ON `credentials`.`company_id_company` = `company`.`idCompany`
   AND `user_id_user` IN (NULL)
  1. Naming Strategy seems not to be working properly for junction table
  2. If I'm not mistaken, ForeignKey and References should do the trick when not following the naming convention

Fixed that, thank you for your report. 2d048d9

@jinzhu

SingularTable looks good now, thank you! But I still have issues regarding column naming convention.

I expected this:

SELECT * 
  FROM `company` 
  JOIN `credential` ON `credential`.`idCompany` = `company`.`idCompany` 
   AND `credential`.`idUser` IN (NULL)

But I got this:

SELECT * 
  FROM `company` 
  JOIN `credential` ON `credential`.`company_id_company` = `company`.`idCompany` 
   AND `user_id_user` IN (NULL)

Am I doing something wrong here? Is it possible to set column name in junction table using tags?

Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`

@jinzhu, regarding many2many relationship

type User struct {
  IdUser    int64     `gorm:"column:idUser;primary_key"`
  Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`
}

type Company struct {
  IdCompany int64 `gorm:"column:idCompany;primary_key"`
}

db, _ := gorm.Open(sqlite.Open("gorm"), &gorm.Config{
  DryRun: true,
  NamingStrategy: schema.NamingStrategy{
      SingularTable: true,
  },
  Logger: logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
      LogLevel: logger.Info,
  }),
})

db.Model(User{}).Association("Companies").Find([]Company{})
SELECT *
  FROM `company`
  JOIN `credentials` ON `credentials`.`company_id_company` = `company`.`idCompany`
   AND `user_id_user` IN (NULL)
  1. Naming Strategy seems not to be working properly for junction table
  2. If I'm not mistaken, ForeignKey and References should do the trick when not following the naming convention

Fixed that, thank you for your report. 2d048d9

@jinzhu

SingularTable looks good now, thank you! But I still have issues regarding column naming convention.

I expected this:

SELECT * 
  FROM `company` 
  JOIN `credential` ON `credential`.`idCompany` = `company`.`idCompany` 
   AND `credential`.`idUser` IN (NULL)

But I got this:

SELECT * 
  FROM `company` 
  JOIN `credential` ON `credential`.`company_id_company` = `company`.`idCompany` 
   AND `user_id_user` IN (NULL)

Am I doing something wrong here? Is it possible to set column name in junction table using tags?

Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;References:IdCompany"`

image

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#association-improvements

Hi @jinzhu,

Is it possible to continue using the date function in queries in v2?

db.Model(&Object{}).Select("date(last_reading)").Group("date(in_objects.last_reading)")

First of all, Thanks!

Yes, it is expected to work, I just submitted a commit to supporting SQL function for Group. https://github.com/go-gorm/gorm/commit/ee1f46e3a1295f2342e72d5da9dc33f8a2a2a9d5

image

https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#association-improvements

I tried using both tags before

Companies []Company `gorm:"many2many:credential;ForeignKey:IdUser;JoinForeignKey:IdUser;References:IdCompany;JoinReferences:IdCompany"`

But GORM still forces the naming convention

SELECT * 
  FROM `company` 
  JOIN `credential` ON `credential`.`id_company` = `company`.`idCompany` 
   AND `id_user` IN (NULL)

This is the expected behavior, GORM will use the default naming convention to convert the specified foreign key, change the default naming strategy here. https://github.com/go-gorm/gorm/blob/master/gorm.go#L22 @seriallink

use Count exec error

    var all []Album
    var count int64
    if key == "*" {
        if err := db.Model(&Album{}).Count(&count).Order("id desc").Limit(limit).Offset((page - 1) * limit).Find(&all).Error; err != nil {
            return all, 0
        }
        return all, count
    }

I use this code exec is error.

show the log

[0.129ms] [rows:1] SELECT count(1) FROM `albums`


[0.286ms] [rows:1] SELECT count(1) FROM `albums` ORDER BY id desc LIMIT 10

use Count exec error

  var all []Album
  var count int64
  if key == "*" {
      if err := db.Model(&Album{}).Count(&count).Order("id desc").Limit(limit).Offset((page - 1) * limit).Find(&all).Error; err != nil {
          return all, 0
      }
      return all, count
  }

I use this code exec is error.

show the log

[0.129ms] [rows:1] SELECT count(1) FROM `albums`


[0.286ms] [rows:1] SELECT count(1) FROM `albums` ORDER BY id desc LIMIT 10

Fixed that. https://github.com/go-gorm/gorm/commit/d02b592c6cd276c169ade515b8999132def9e555

@jinzhu
We are eagerly waiting for the release of Go ORM V2.0. Lots of my headaches will be solved with version 2.0.

@jinzhu
We are eagerly waiting for the release of Go ORM V2.0. Lots of my headaches will be solved with version 2.0.

Hi @SujalKokh, consider migrating your project to v2.0 now :) It has been used in some production services already, and if you found any issues, most of them should be resolved in less than 24 hours.

How do I integrate the Go ORM version 2.0 with my Go app? Running go get -u github.com/jinzhu/gorm installs GORM version 1.9.14. Please help me.

When will the gorm.io docs be up to date?

@jinzhu will v2 work with qor admin?

Hi,jinzhu, I Use gorm.Model in my struct and created this , and i Create data not set CreatedAt and CreatedAt value, exec this is error, report Trace: reflect: call of reflect.flag.mustBeExported on zero Value

@jinzhu will v2 work with qor admin?

QOR Admin will migrate to GORM v2, but I need to check with the current maintainer for its plan.

When will the gorm.io docs be up to date?

Working on it should be ready in the next two weeks

Hi,jinzhu, I Use gorm.Model in my struct and created this , and i Create data not set CreatedAt and CreatedAt value, exec this is error, report Trace: reflect: call of reflect.flag.mustBeExported on zero Value

Please follow the document, if you believe there is an issue, create a PR here https://github.com/go-gorm/playground

@jinzhu Hi I encountered an issue with the JoinForeignKey and JoinReferences tags. I made a minimal reproducible test case :

package main

import (
    "log"

    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type ModelA struct {
    ID []byte `gorm:"COLUMN:id;TYPE:BINARY(32);PRIMARY_KEY;NOT NULL" json:"id"`
}

type ModelB struct {
    ID []byte `gorm:"COLUMN:id;TYPE:BINARY(10);PRIMARY_KEY;NOT NULL" json:"id"`

    ModelAs []*ModelA `gorm:"Many2Many:model_a_model_b;ForeignKey:id;References:id;JoinForeignKey:model_a_id;JoinReferences:model_b_id" json:"model_as,omitempty"`
}

func main() {
    db, err := gorm.Open(sqlite.Open(":memory:?_foreign_keys=1"), nil)
    if err != nil {
        log.Fatal(err)
    }

    err = db.AutoMigrate(
        &ModelA{},
        &ModelB{})
    if err != nil {
        log.Fatal(err)
    }
}

Results in a panic

panic: reflect.StructOf: field "model_a_id" is unexported but missing PkgPath

goroutine 1 [running]:
reflect.runtimeStructField(0x6cbb6d, 0xa, 0x0, 0x0, 0x744d80, 0x6a7240, 0xc0000e6840, 0x35, 0x0, 0x0, ...)
        /usr/lib/go/src/reflect/type.go:2769 +0x1df
reflect.StructOf(0xc00009d2b0, 0x2, 0x2, 0x0, 0x0)
        /usr/lib/go/src/reflect/type.go:2385 +0x1e3f
gorm.io/gorm/schema.(*Schema).buildMany2ManyRelation(0xc00018e1c0, 0xc000182090, 0xc000083680, 0x6cbb32, 0xf)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/schema/relationship.go:249 +0xccc
gorm.io/gorm/schema.(*Schema).parseRelation(0xc00018e1c0, 0xc000083680)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/schema/relationship.go:77 +0x9d0
gorm.io/gorm/schema.Parse(0x6a0f00, 0xc0001597a0, 0xc0001595f0, 0x742f00, 0xc000180220, 0x0, 0x0, 0x0)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/schema/schema.go:212 +0x157e
gorm.io/gorm.(*Statement).Parse(0xc00009f1e0, 0x6a0f00, 0xc0001597a0, 0x0, 0x1)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/statement.go:332 +0x5f
gorm.io/gorm/migrator.Migrator.ReorderModels.func1(0x6a0f00, 0xc0001597a0, 0xc000100301)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/migrator/migrator.go:537 +0xce
gorm.io/gorm/migrator.Migrator.ReorderModels(0xc000168c01, 0xc000159620, 0x743a40, 0xc000165010, 0xc000180c20, 0x2, 0x2, 0xc000180c01, 0x20, 0x20, ...)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/migrator/migrator.go:585 +0x5c9
gorm.io/gorm/migrator.Migrator.AutoMigrate(0x5c2a01, 0xc000159620, 0x743a40, 0xc000165010, 0xc000180c20, 0x2, 0x2, 0x743a40, 0xc000165010)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/migrator/migrator.go:83 +0x95
gorm.io/gorm.(*DB).AutoMigrate(0xc000159620, 0xc000180c20, 0x2, 0x2, 0x0, 0x0)
        /home/popsulfr/go/pkg/mod/gorm.io/[email protected]/migrator.go:17 +0x70
main.main()
        /home/popsulfr/work/rezom/datascience/dsp2p/cmd/problem/main.go:26 +0x162
exit status 2

Without JoinForeignKey:model_a_id;JoinReferences:model_b_id it otherwise works. Am I using them wrong ?

the value of JoinForeignKey:model_a_id;JoinReferences:model_b_id needs to be upper case, but I have handled that in lastest commit. https://github.com/go-gorm/gorm/commit/d4f8a524423baf81aecfc6caf2780eb14e2eb187

Add a way for omitting some columns also on querying, not only on saving.

fyi, I needed to add some additional checks to avoid triggering panic in some cases:

func beforeCreate(sfn *snowflake.Node) func(*gorm.DB) {
        return func(db *gorm.DB) {
                if db.Statement == nil || db.Statement.Schema == nil || !db.Statement.ReflectValue.IsValid() {
                        return
                }
                db.Statement.Schema.LookUpField("ID").Set(db.Statement.ReflectValue, sfn.Generate().Int64())
        }
}

I am setting below thing for each request in http middleware.

tx := db.Scopes(func(db *gorm.DB) *gorm.DB {
            db = db.Set("IP", IP)
            return db.Set("org_id", ctx.Value("org_id"))
        })
ctx = context.WithValue(ctx, "tx", tx)

    db.Callback().Create().Before("gorm:update").Register("update_org", updateOrg)
    db.Callback().Row().Before("gorm:row_query").Register("query_org", queryOrg)

func queryOrg(scope *gorm.DB) {
    if scope.HasColumn("org_id") {
        orgID, ok := scope.Get("org_id")
        if !ok {
            return
        }
        scope.Search.Where(scope.TableName()+".org_id = ?", orgID)
}

func updateOrg(scope *gorm.Scope) {
    if scope.HasColumn("org_id") {
        orgID, ok := scope.Get("org_id")
        if !ok {
            return
        }
        scope.Search.Where(scope.TableName()+".org_id = ?", orgID)
    }
}

Can you please give the replacement for the above thing. @jinzhu @moul

I have finished the draft v2 documents, please check it out http://v2.gorm.io (will use http://gorm.io after the final release)

Closing this issue, please create a new issue on any bug report or suggestion.

Tried out GORM v2 and it is fantastic. However, I am having difficulty finding a proper way of implementing migrations. Can we expect a migration for v2 similar to that of Ruby on Rails/Django @jinzhu ? The problem is that once I run the auto-migration I need to manually delete or update the names of the column of tables if it requires changes.

@SujalKokh That is the expected behaviour. Deletes/updates through auto-migrations are not safe and can cause severe damage. You can use DropColumn for dropping a column though.

Question, I've been rewriting an API backend which utilized Gorm 1.X, and I notice the following doesn't return any associated books. What am I doing wrong? Thanks for any help you can provide, I absolutely love GORM 2's API.

When hitting the API with /series/1 (which is valid and created with the following CURL command: curl -d '{"description":"value1", "title":"value2", "books":[{"title":"Harry Potter", "author": "lol"}]}' -H "Content-Type: application/json" -X POST http://localhost:8000/series), the response is:

{
  "ID":1,
  "CreatedAt":"2020-07-19T10:26:13.948013-04:00",
  "UpdatedAt":"2020-07-19T10:26:13.948013-04:00",
  "DeletedAt": {
    "Time":"0001-01-01T00:00:00Z",
    "Valid":false
  },
  "title":"value2",
  "description":"value1",
  "books":[]
}

Confused because looking into the sqlite database, I see the bridge table and book being created.

type Book struct {
    gorm.Model
    Title  string `json:"title"`
    Author string `json:"author"`
}

type Series struct {
    gorm.Model
    Title       string `json:"title"`
    Description string `json:"description"`
    Books       []Book `json:"books" gorm:"many2many:Series_Book"`
}

func CreateSeries(app *application.Application) gin.HandlerFunc {
    return func(c *gin.Context) {
        var input models.CreateSeriesInput
        if err := c.ShouldBindJSON(&input); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        series := models.Series{Title: input.Title, Description: input.Description, Books: input.Books}

        app.Database.Client.Create(&series)

        c.JSON(http.StatusOK, series)
    }
}

func RetrieveSeriesByID(db *gorm.DB, c *gin.Context, series *models.Series) bool {
    if err := db.Where("id = ?", c.Param("id")).First(&series).Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
        return false
    }

    // Associtation Mode
    if err := db.Model(&series).Association("Books").Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }

    db.Model(&series).Association("Books").Find(&series.Books)

    return true
}

when i write a custom logger, how can i get sql.DB object for get sql.DBStats, i want to log DBStatus.InUse and DBStatus.Idle

@jinzhu great work, thanks!

I'm currently trying out v2 (MySQL) and have 3 questions:

  • Won't there be a Close() connection func anymore?
  • I'm reusing a single instance of *gorm.DB (provided by gorm.Open()) for multiple queries and faced unexpected behavior: It seemed like it stored conditions of queries executed before and reused them when executing other queries. Using a *gorm.DB instance from db.Session(&gorm.Session{}) the problem disappeared. Is this how it should be used?
  • Testing the batch inserts I got Error 1390: Prepared statement contains too many placeholders - gorm could execute it in chunks to avoid this, right? Otherwise everybody would have to reimplement the chunk logic..

@jinzhu great work, thanks!

I'm currently trying out v2 (MySQL) and have 3 questions:

  • Won't there be a Close() connection func anymore?
  • I'm reusing a single instance of *gorm.DB (provided by gorm.Open()) for multiple queries and faced unexpected behavior: It seemed like it stored conditions of queries executed before and reused them when executing other queries. Using a *gorm.DB instance from db.Session(&gorm.Session{}) the problem disappeared. Is this how it should be used?
  • Testing the batch inserts I got Error 1390: Prepared statement contains too many placeholders - gorm could execute it in chunks to avoid this, right? Otherwise everybody would have to reimplement the chunk logic..

http://v2.gorm.io/docs/connecting_to_the_database.html#Connection-Pool
http://v2.gorm.io/docs/generic_interface.html
http://v2.gorm.io/docs/method_chaining.html

when i write a custom logger, how can i get sql.DB object for get sql.DBStats, i want to log DBStatus.InUse and DBStatus.Idle

initialize the logger with DB

@jinzhu We are in the process of migrating from gorm V1 to V2, and V2 has been great!

One question though: does V2 Postgres driver support jsonb? I can't seem to find the relevant functions.

I might be having a bug with Joins. When adding joins to a query it isn't in the query in the same order as v1.

can I use the last commit in production ?

can I use the last commit in production?

There are hundreds of services already using GORM V2 ;)

@jinzhu We are in the process of migrating from gorm V1 to V2, and V2 has been great!

One question though: does V2 Postgres driver support jsonb? I can't seem to find the relevant functions.

https://github.com/go-gorm/datatypes

I might be having a bug with Joins. When adding joins to a query it isn't in the query in the same order as v1.

consider creating a PR on Playground

Hope to develop a cache system plug-in

could remove cgo depend for sqlites

This is not GORM stuff. cgo come from the sql driver.

Here is the all driver list, some of them are using cgo. Unfortunately, sqlite is using cgo.
https://github.com/golang/go/wiki/SQLDrivers

@jinzhu
gorm.io/driver/mysql v0.3.1
gorm.io/gorm v0.2.31
Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1
gorm.Model.CreatedAt default value
db.Save(&row)

hello world

Was this page helpful?
0 / 5 - 0 ratings

Related issues

easonlin404 picture easonlin404  ·  3Comments

satb picture satb  ·  3Comments

fieryorc picture fieryorc  ·  3Comments

Ganitzsh picture Ganitzsh  ·  3Comments

bramp picture bramp  ·  3Comments