Omitempty

This commit is contained in:
Daniel Ponte 2024-11-25 16:04:07 -05:00
parent 9b3743e79a
commit 4b8a5475a6
3 changed files with 183 additions and 84 deletions

View file

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

View file

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