// Package orm define database data struct package orm import ( "database/sql/driver" "encoding/json" "errors" "fmt" "github.com/jackc/pgx/v5/pgtype" ) // JSONMap define struct of implements the sql.Scanner and driver.Valuer interfaces for handling JSONB fields type JSONMap map[string]any // Value define func to convert the JSONMap to driver.Value([]byte) for writing to the database func (j JSONMap) Value() (driver.Value, error) { if j == nil { return nil, nil } return json.Marshal(j) } // Scan define to scanned values([]bytes) in the database and parsed into a JSONMap for data retrieval func (j *JSONMap) Scan(value any) error { if value == nil { *j = nil return nil } var source []byte switch v := value.(type) { case []byte: source = v case string: source = []byte(v) default: return errors.New("unsupported data type for JSONMap Scan") } return json.Unmarshal(source, j) } // JSONMapArray represents a PostgreSQL jsonb[] column. type JSONMapArray []JSONMap // Value encodes the slice as a PostgreSQL jsonb array. func (j JSONMapArray) Value() (driver.Value, error) { items := make(pgtype.FlatArray[map[string]any], len(j)) for index, item := range j { items[index] = map[string]any(item) } encoded, err := pgtype.NewMap().Encode(pgtype.JSONBArrayOID, pgtype.TextFormatCode, items, nil) if err != nil { return nil, fmt.Errorf("encode JSONMapArray: %w", err) } return string(encoded), nil } // Scan decodes a PostgreSQL jsonb array. func (j *JSONMapArray) Scan(value any) error { if value == nil { *j = nil return nil } var source []byte switch typedValue := value.(type) { case []byte: source = typedValue case string: source = []byte(typedValue) default: return fmt.Errorf("unsupported data type %T for JSONMapArray Scan", value) } var items pgtype.FlatArray[map[string]any] if err := pgtype.NewMap().Scan(pgtype.JSONBArrayOID, pgtype.TextFormatCode, source, &items); err != nil { return fmt.Errorf("decode JSONMapArray: %w", err) } result := make(JSONMapArray, len(items)) for index, item := range items { result[index] = JSONMap(item) } *j = result return nil }