Omitempty in DB models #54

Merged
amigan merged 1 commit from omitempty into trunk 2024-11-25 16:04:58 -05:00
3 changed files with 183 additions and 84 deletions

View file

@ -25,6 +25,7 @@ generate:
sqlc generate -f sql/sqlc.yaml
protoc -I=pkg/pb/ --go_out=pkg/ pkg/pb/stillbox.proto
go generate ./...
go run ./util/omitempty/omitempty.go
lint:
golangci-lint run

View file

@ -14,115 +14,115 @@ import (
)
type Alert struct {
ID int `json:"id"`
Time pgtype.Timestamptz `json:"time"`
TGID int `json:"tgid"`
SystemID int `json:"system_id"`
Weight *float32 `json:"weight"`
Score *float32 `json:"score"`
OrigScore *float32 `json:"orig_score"`
Notified bool `json:"notified"`
Metadata []byte `json:"metadata"`
ID int `json:"id,omitempty"`
Time pgtype.Timestamptz `json:"time,omitempty"`
TGID int `json:"tgid,omitempty"`
SystemID int `json:"system_id,omitempty"`
Weight *float32 `json:"weight,omitempty"`
Score *float32 `json:"score,omitempty"`
OrigScore *float32 `json:"orig_score,omitempty"`
Notified bool `json:"notified,omitempty"`
Metadata []byte `json:"metadata,omitempty"`
}
type ApiKey struct {
ID int `json:"id"`
Owner int `json:"owner"`
CreatedAt time.Time `json:"created_at"`
Expires pgtype.Timestamp `json:"expires"`
Disabled *bool `json:"disabled"`
ApiKey string `json:"api_key"`
ID int `json:"id,omitempty"`
Owner int `json:"owner,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
Expires pgtype.Timestamp `json:"expires,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
ApiKey string `json:"api_key,omitempty"`
}
type Call struct {
ID uuid.UUID `json:"id"`
Submitter *int32 `json:"submitter"`
System int `json:"system"`
Talkgroup int `json:"talkgroup"`
CallDate pgtype.Timestamptz `json:"call_date"`
AudioName *string `json:"audio_name"`
AudioBlob []byte `json:"audio_blob"`
Duration *int32 `json:"duration"`
AudioType *string `json:"audio_type"`
AudioUrl *string `json:"audio_url"`
Frequency int `json:"frequency"`
Frequencies []int `json:"frequencies"`
Patches []int `json:"patches"`
TGLabel *string `json:"tg_label"`
TGAlphaTag *string `json:"tg_alpha_tag"`
TGGroup *string `json:"tg_group"`
Source int `json:"source"`
Transcript *string `json:"transcript"`
ID uuid.UUID `json:"id,omitempty"`
Submitter *int32 `json:"submitter,omitempty"`
System int `json:"system,omitempty"`
Talkgroup int `json:"talkgroup,omitempty"`
CallDate pgtype.Timestamptz `json:"call_date,omitempty"`
AudioName *string `json:"audio_name,omitempty"`
AudioBlob []byte `json:"audio_blob,omitempty"`
Duration *int32 `json:"duration,omitempty"`
AudioType *string `json:"audio_type,omitempty"`
AudioUrl *string `json:"audio_url,omitempty"`
Frequency int `json:"frequency,omitempty"`
Frequencies []int `json:"frequencies,omitempty"`
Patches []int `json:"patches,omitempty"`
TGLabel *string `json:"tg_label,omitempty"`
TGAlphaTag *string `json:"tg_alpha_tag,omitempty"`
TGGroup *string `json:"tg_group,omitempty"`
Source int `json:"source,omitempty"`
Transcript *string `json:"transcript,omitempty"`
}
type Incident struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description *string `json:"description"`
StartTime pgtype.Timestamp `json:"start_time"`
EndTime pgtype.Timestamp `json:"end_time"`
Location []byte `json:"location"`
Metadata []byte `json:"metadata"`
ID uuid.UUID `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
StartTime pgtype.Timestamp `json:"start_time,omitempty"`
EndTime pgtype.Timestamp `json:"end_time,omitempty"`
Location []byte `json:"location,omitempty"`
Metadata []byte `json:"metadata,omitempty"`
}
type IncidentsCall struct {
IncidentID uuid.UUID `json:"incident_id"`
CallID uuid.UUID `json:"call_id"`
Notes []byte `json:"notes"`
IncidentID uuid.UUID `json:"incident_id,omitempty"`
CallID uuid.UUID `json:"call_id,omitempty"`
Notes []byte `json:"notes,omitempty"`
}
type Setting struct {
Name string `json:"name"`
UpdatedBy *int32 `json:"updated_by"`
Value []byte `json:"value"`
Name string `json:"name,omitempty"`
UpdatedBy *int32 `json:"updated_by,omitempty"`
Value []byte `json:"value,omitempty"`
}
type System struct {
ID int `json:"id"`
Name string `json:"name"`
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
type Talkgroup struct {
ID int `json:"id"`
SystemID int32 `json:"system_id"`
TGID int32 `json:"tgid"`
Name *string `json:"name"`
AlphaTag *string `json:"alpha_tag"`
TGGroup *string `json:"tg_group"`
Frequency *int32 `json:"frequency"`
Metadata jsontypes.Metadata `json:"metadata"`
Tags []string `json:"tags"`
Alert bool `json:"alert"`
AlertConfig rules.AlertRules `json:"alert_config"`
Weight float32 `json:"weight"`
Learned bool `json:"learned"`
Ignored bool `json:"ignored"`
ID int `json:"id,omitempty"`
SystemID int32 `json:"system_id,omitempty"`
TGID int32 `json:"tgid,omitempty"`
Name *string `json:"name,omitempty"`
AlphaTag *string `json:"alpha_tag,omitempty"`
TGGroup *string `json:"tg_group,omitempty"`
Frequency *int32 `json:"frequency,omitempty"`
Metadata jsontypes.Metadata `json:"metadata,omitempty"`
Tags []string `json:"tags,omitempty"`
Alert bool `json:"alert,omitempty"`
AlertConfig rules.AlertRules `json:"alert_config,omitempty"`
Weight float32 `json:"weight,omitempty"`
Learned bool `json:"learned,omitempty"`
Ignored bool `json:"ignored,omitempty"`
}
type TalkgroupVersion struct {
ID int `json:"id"`
Time pgtype.Timestamptz `json:"time"`
CreatedBy *int32 `json:"created_by"`
SystemID *int32 `json:"system_id"`
TGID *int32 `json:"tgid"`
Name *string `json:"name"`
AlphaTag *string `json:"alpha_tag"`
TGGroup *string `json:"tg_group"`
Frequency *int32 `json:"frequency"`
Metadata []byte `json:"metadata"`
Tags []string `json:"tags"`
Alert *bool `json:"alert"`
AlertConfig []byte `json:"alert_config"`
Weight *float32 `json:"weight"`
Learned *bool `json:"learned"`
Ignored *bool `json:"ignored"`
ID int `json:"id,omitempty"`
Time pgtype.Timestamptz `json:"time,omitempty"`
CreatedBy *int32 `json:"created_by,omitempty"`
SystemID *int32 `json:"system_id,omitempty"`
TGID *int32 `json:"tgid,omitempty"`
Name *string `json:"name,omitempty"`
AlphaTag *string `json:"alpha_tag,omitempty"`
TGGroup *string `json:"tg_group,omitempty"`
Frequency *int32 `json:"frequency,omitempty"`
Metadata []byte `json:"metadata,omitempty"`
Tags []string `json:"tags,omitempty"`
Alert *bool `json:"alert,omitempty"`
AlertConfig []byte `json:"alert_config,omitempty"`
Weight *float32 `json:"weight,omitempty"`
Learned *bool `json:"learned,omitempty"`
Ignored *bool `json:"ignored,omitempty"`
}
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
Prefs []byte `json:"prefs"`
ID int `json:"id,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Email string `json:"email,omitempty"`
IsAdmin bool `json:"is_admin,omitempty"`
Prefs []byte `json:"prefs,omitempty"`
}

View file

@ -0,0 +1,98 @@
// This is here until https://github.com/sqlc-dev/sqlc/pull/3117 is merged.
package main
import (
"bytes"
"go/ast"
"go/format"
"go/parser"
"go/token"
"log"
"os"
"strings"
)
const filePath = "./pkg/database/models.go"
func main() {
// Parse the source code
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
// Modify the AST
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.StructType:
for _, field := range x.Fields.List {
if field.Tag == nil {
continue
}
if field.Tag.Value == "" || field.Tag.Kind != token.STRING {
continue
}
field.Tag.Value = modifyJSONTag(field.Tag.Value)
}
}
return true
})
// Write the output back to the original file
var buf bytes.Buffer
err = format.Node(&buf, fset, f)
if err != nil {
log.Fatal(err)
}
outputFile, err := os.Create(filePath)
if err != nil {
log.Fatal(err)
}
defer outputFile.Close()
_, err = outputFile.Write(buf.Bytes())
if err != nil {
log.Fatal(err)
}
}
func modifyJSONTag(tagValue string) string {
tagValue = strings.Trim(tagValue, "`")
tags := strings.Split(tagValue, " ")
var modifiedTags []string
for _, tag := range tags {
// Only modify JSON tags, leave others as they are.
if !strings.HasPrefix(tag, "json:") {
modifiedTags = append(modifiedTags, tag)
continue
}
jsonQuoted := tag[5:] // Remove "json:" prefix
jsonValue := strings.Trim(jsonQuoted, "\"") // Remove quotes
jsonOptions := strings.Split(jsonValue, ",") // Split options
// Check if "omitempty" is already present
hasOmitempty := false
for _, opt := range jsonOptions {
if opt == "omitempty" {
hasOmitempty = true
break
}
}
// Add "omitempty" if not present and the field is not ignored
if !hasOmitempty && jsonOptions[0] != "-" {
jsonOptions = append(jsonOptions, "omitempty")
}
// Reconstruct the JSON tag
newJSONTag := "json:\"" + strings.Join(jsonOptions, ",") + "\""
modifiedTags = append(modifiedTags, newJSONTag)
}
// Reconstruct the full tag
return "`" + strings.Join(modifiedTags, " ") + "`"
}