go-reform / reform

A better ORM for Go, based on non-empty interfaces and code generation.
https://gopkg.in/reform.v1
MIT License
1.44k stars 73 forks source link

Tag "omitempty" to avoid passing zero values #260

Open dgellow opened 4 years ago

dgellow commented 4 years ago

Is your feature request related to a problem? Please describe.

I have a postgres table with a column of type serial (which is not the primary key, if that matters).

Suppose I have a reform type:

//reform:files
type File struct {
    ID    string `reform:"id,pk"`
    IncID int64  `reform:"inc_id"` // <== column of type 'serial'
}

I then insert it using this way:

record := MyRecord{
  ID: myID,
}
err := db.Insert(&record)

Here I would like the value for inc_id to be ignored during INSERT statements as I would like to use the column default (i.e: the next value of the serial's sequence). Unfortunately when using the Go zero value reform does the insert with the actual value 0. The result in a row with the column set to 0 instead of the result of Postgres' nextval().

Describe the solution you'd like

I would like to be able to mark a field as reform:"inc_id,omitempty", similar to what the official json package does. When the tag "omitempty" is present, reform will not pass the field during calls to Insertor Update.

Given this reform type:

//reform:files
type File struct {
    ID    string `reform:"id,pk"`
    IncID int64  `reform:"inc_id,omitempty"` // <== column of type 'serial'
}

And this insert:

record := MyRecord{
  ID: 123,
}
err := db.Insert(&record)

Something equivalent to the following SQL code should be generated:

INSERT INTO (id) values (123) RETURNING id, inc_id

Describe alternatives you've considered

Other options:

  1. We could use a tag readonly instead, that would specify that the column is never passed during UPDATE or INSERT, but is used for SELECT, without a need for logic based on zero values.

  2. What I would like is currently possible this way:

    cols := record.Table().Columns()
    i := 0
    for i = range cols {
    if cols[i] == "inc_id" {
        break
    }
    }
    cols = append(cols[:i], cols[i+1:]...)
    err := tx.InsertColumns(&record, cols...)

So an alternative that doesn't require to add new tags would be to add a method InsertWithout(&record, "inc_id") that would do the opposite of InsertColumns (insert everything but the specified columns).

AlekSi commented 2 years ago

https://github.com/go-reform/reform/issues/146#issuecomment-359029463

readonly tag sounds interesting…

The last option is covered by #100.