Skip to content
go-jet edited this page Nov 3, 2024 · 10 revisions

Model file contains simple Go struct type used to store result of SQL queries. Model types can be used alone or combined to form complex object composition to store database query result. They are auto-generated from database tables, views and enums.

Table and view model files

Following rules are applied to generate model types from database tables and views:

  • for every table there is one Go file generated. File name is in snake case of the table name.
  • every model file contains one struct type. Type name is a camel case of table name. Package name is always model.
  • for every column of table there is a field in model struct type. Field name is camel case of column name. See below table for type mapping.
  • fields are pointer types, if they relate to column that can be NULL.
  • fields corresponds to primary key columns are tagged with sql:"primary_key". This tag is used during query execution to group row results into desired arbitrary structure. See more at Query Result Mapping (QRM)
Mappings of Postgres database types to Go types
Database type(postgres) Go type
boolean bool
smallint int16
integer int32
bigint int64
real float32
numeric, decimal, double precision float64
date, timestamp, time(with or without timezone) time.Time
bytea []byte
uuid uuid.UUID
enum enum name
text, character, character varying,
and all remaining types string
Mappings of MySQL and MariaDB database types to Go types
Database type(postgres) Go type
boolean or BIT(1) bool
tinylint [unsigned] [u]int8
smallint [unsigned] [u]int16
mediumint [unsigned] [u]int32
integer [unsigned] [u]int32
bigint [unsigned] [u]int64
real float32
numeric, decimal, double precision float64
date, time, datetime, timestamp time.Time
binary, varbinary, tinyblob, blob,
mediumblob, longblob []byte
enum table name + enum name
text, character, character varying,
and all remaining types string

Example:

PostgreSQL table address:

CREATE TABLE dvds.address
(
    address_id serial NOT NULL DEFAULT,
    address character varying(50) NOT NULL,
    address2 character varying(50),
    district character varying(20) NOT NULL,
    city_id smallint NOT NULL,
    postal_code character varying(10),
    phone character varying(20) NOT NULL,
    last_update timestamp without time zone NOT NULL DEFAULT now(),
    CONSTRAINT address_pkey PRIMARY KEY (address_id)
)

Autogenerated model file address.go:

package model

import (
    "time"
)

type Address struct {
    AddressID  int32 `sql:"primary_key"`
    Address    string
    Address2   *string
    District   string
    CityID     int16
    PostalCode *string
    Phone      string
    LastUpdate time.Time
}

Enum model files

Following rules are applied to generate model files from database enums:

  • for every enum there is one Go file generated.
    • PostgreSQL: File name is a snake case of enum name.
    • MySQL or MariaDB: File name is snake case of table name + enum name.
  • every file contains one renamed string type. Type name is a camel case of enum name. Package name is always model. Enum type has two helper methods to:
    • initialize correctly from database query result
    • easily convert enum to string.
  • for every enum value there is one constant defined. Name of the constant is in format {CamelCase(enum_name)}_{CamelCase(enum_value_name)}.
  • there is one slice contains list of all enums defined named {CamelCase(enum_name)}AllValues

Example

PostgreSQL:

CREATE TYPE dvds.mpaa_rating AS ENUM
    ('G', 'PG', 'PG-13', 'R', 'NC-17');

Autogenerated model file mpaa_rating.go

package model

import "errors"

type MpaaRating string

const (
	MpaaRating_G    MpaaRating = "G"
	MpaaRating_Pg   MpaaRating = "PG"
	MpaaRating_Pg13 MpaaRating = "PG-13"
	MpaaRating_R    MpaaRating = "R"
	MpaaRating_Nc17 MpaaRating = "NC-17"
)

var MpaaRatingAllValues = []MpaaRating{
	MpaaRating_G,
	MpaaRating_Pg,
	MpaaRating_Pg13,
	MpaaRating_R,
	MpaaRating_Nc17,
}

func (e *MpaaRating) Scan(value interface{}) error {
	var enumValue string
	switch val := value.(type) {
	case string:
		enumValue = val
	case []byte:
		enumValue = string(val)
	default:
		return errors.New("jet: Invalid scan value for AllTypesEnum enum. Enum value has to be of type string or []byte")
	}

	switch enumValue {
	case "G":
		*e = MpaaRating_G
	case "PG":
		*e = MpaaRating_Pg
	case "PG-13":
		*e = MpaaRating_Pg13
	case "R":
		*e = MpaaRating_R
	case "NC-17":
		*e = MpaaRating_Nc17
	default:
		return errors.New("jet: Invalid scan value '" + enumValue + "' for MpaaRating enum")
	}

	return nil
}

func (e MpaaRating) String() string {
	return string(e)
}

MySQL or MariaDB:

CREATE TABLE film (
  rating ENUM('G','PG','PG-13','R','NC-17') DEFAULT 'G'
)
package model

import "errors"

type FilmRating string

const (
	FilmRating_G    FilmRating = "G"
	FilmRating_Pg   FilmRating = "PG"
	FilmRating_Pg13 FilmRating = "PG-13"
	FilmRating_R    FilmRating = "R"
	FilmRating_Nc17 FilmRating = "NC-17"
)

func (e *FilmRating) Scan(value interface{}) error {
	if v, ok := value.(string); !ok {
		return errors.New("jet: Invalid data for FilmRating enum")
	} else {
		switch string(v) {
		case "G":
			*e = FilmRating_G
		case "PG":
			*e = FilmRating_Pg
		case "PG-13":
			*e = FilmRating_Pg13
		case "R":
			*e = FilmRating_R
		case "NC-17":
			*e = FilmRating_Nc17
		default:
			return errors.New("jet: Inavlid data " + string(v) + "for FilmRating enum")
		}

		return nil
	}
}

func (e FilmRating) String() string {
	return string(e)
}