I don't really remember what lead us to use the regexp pattern to strip
out null entries initially but it was a dumb decision.
Changelog-fixed: No longer using regexp to parse null entries from json
(no clue wtf we were thinking there)
---
models/base_url.go | 13 +++++--------
models/link_short.go | 24 +++++++++---------------
models/listing.go | 34 ++++++++++++----------------------
models/org_link.go | 24 ++++++++----------------
models/utils.go | 23 +++++++++++++++++++++++
5 files changed, 57 insertions(+), 61 deletions(-)
diff --git a/models/base_url.go b/models/base_url.go
index affaa04..18c6560 100644
--- a/models/base_url.go
+++ b/models/base_url.go
@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"net/url"
- "regexp"
"time"
sq "github.com/Masterminds/squirrel"
@@ -90,14 +89,12 @@ func GetBaseURLs(ctx context.Context, opts *database.FilterOptions) ([]*BaseURL,
&url.LastParseAttempt, &url.CreatedOn, &tags); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &url.Tags)
- if err != nil {
- return err
- }
+
+ url.Tags, err = BuildSliceFromJSONString[Tag](tags)
+ if err != nil {
+ return err
}
+
err = url.ToLocalTZ(tz)
if err != nil {
return err
diff --git a/models/link_short.go b/models/link_short.go
index cda1a20..31a38b0 100644
--- a/models/link_short.go
+++ b/models/link_short.go
@@ -5,7 +5,6 @@ import (
"database/sql"
"encoding/json"
"fmt"
- "regexp"
"time"
sq "github.com/Masterminds/squirrel"
@@ -48,14 +47,11 @@ func GetLinkShorts(ctx context.Context, opts *database.FilterOptions) ([]*LinkSh
&ls.OrgID, &ls.UserID, &ls.CreatedOn, &ls.UpdatedOn, &ls.LookupName, &tags); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &ls.Tags)
- if err != nil {
- return err
- }
+ ls.Tags, err = BuildSliceFromJSONString[Tag](tags)
+ if err != nil {
+ return err
}
+
err = ls.ToLocalTZ(tz)
if err != nil {
return err
@@ -263,14 +259,12 @@ func ExportLinkShorts(ctx context.Context, opts *database.FilterOptions) ([]*Exp
if err = rows.Scan(&ls.ID, &ls.Title, &ls.URL, &ls.ShortCode, &ls.CreatedOn, &tags); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &ls.Tags)
- if err != nil {
- return err
- }
+ ls.Tags, err = BuildSliceFromJSONString[ExportTag](tags)
+ err = json.Unmarshal([]byte(tags), &ls.Tags)
+ if err != nil {
+ return err
}
+
linkShorts = append(linkShorts, &ls)
}
return nil
diff --git a/models/listing.go b/models/listing.go
index fa3c778..7e58ce8 100644
--- a/models/listing.go
+++ b/models/listing.go
@@ -3,9 +3,7 @@ package models
import (
"context"
"database/sql"
- "encoding/json"
"fmt"
- "regexp"
"time"
sq "github.com/Masterminds/squirrel"
@@ -43,7 +41,6 @@ func GetListings(ctx context.Context, opts *database.FilterOptions) ([]*Listing,
}
defer rows.Close()
- re := regexp.MustCompile(`(,\s)?null,?`)
for rows.Next() {
var ls Listing
var tags string
@@ -51,13 +48,12 @@ func GetListings(ctx context.Context, opts *database.FilterOptions) ([]*Listing,
&ls.UserID, &ls.IsDefault, &ls.IsActive, &ls.CreatedOn, &ls.UpdatedOn, &ls.LookupName, &tags); err != nil {
return err
}
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &ls.Tags)
- if err != nil {
- return err
- }
+
+ ls.Tags, err = BuildSliceFromJSONString[Tag](tags)
+ if err != nil {
+ return err
}
+
err = ls.ToLocalTZ(tz)
if err != nil {
return err
@@ -249,22 +245,16 @@ func ExportListings(ctx context.Context, opts *database.FilterOptions) ([]*Expor
if err = rows.Scan(&ls.ID, &ls.Title, &ls.Slug, &ls.CreatedOn, &tags, &links); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- links = re.ReplaceAllString(links, "")
- if links != "[]" {
- err = json.Unmarshal([]byte(links), &ls.Links)
- if err != nil {
- return err
- }
+ ls.Links, err = BuildSliceFromJSONString[ExportLink](links)
+ if err != nil {
+ return err
}
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &ls.Tags)
- if err != nil {
- return err
- }
+ ls.Tags, err = BuildSliceFromJSONString[ExportTag](tags)
+ if err != nil {
+ return err
}
+
listings = append(listings, &ls)
}
return nil
diff --git a/models/org_link.go b/models/org_link.go
index acf6da1..d46657c 100644
--- a/models/org_link.go
+++ b/models/org_link.go
@@ -3,10 +3,8 @@ package models
import (
"context"
"database/sql"
- "encoding/json"
"fmt"
"net/url"
- "regexp"
"time"
sq "github.com/Masterminds/squirrel"
@@ -69,14 +67,11 @@ func GetOrgLinks(ctx context.Context, opts *database.FilterOptions) ([]*OrgLink,
&o.BaseURLData, &o.BaseURLCounter, &o.BaseURLHash); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &o.Tags)
- if err != nil {
- return err
- }
+ o.Tags, err = BuildSliceFromJSONString[Tag](tags)
+ if err != nil {
+ return err
}
+
err = o.ToLocalTZ(tz)
if err != nil {
return err
@@ -349,14 +344,11 @@ func ExportOrgLinks(ctx context.Context, opts *database.FilterOptions) ([]*Expor
&o.Unread, &o.Starred, &o.Hash, &o.CreatedOn, &tags); err != nil {
return err
}
- re := regexp.MustCompile(`(,\s)?null,?`)
- tags = re.ReplaceAllString(tags, "")
- if tags != "[]" {
- err = json.Unmarshal([]byte(tags), &o.Tags)
- if err != nil {
- return err
- }
+ o.Tags, err = BuildSliceFromJSONString[ExportTag](tags)
+ if err != nil {
+ return err
}
+
links = append(links, &o)
}
return nil
diff --git a/models/utils.go b/models/utils.go
index 0255066..f8d787e 100644
--- a/models/utils.go
+++ b/models/utils.go
@@ -3,6 +3,8 @@ package models
import (
"context"
"database/sql"
+ "encoding/json"
+ "fmt"
mrand "math/rand"
"strings"
"time"
@@ -96,3 +98,24 @@ func ShowLinkCounter(obj any) bool {
return false
}
}
+
+// SliceNilRemover will remove any nil values from a given slice
+func SliceNilRemover[T any](in []*T) []T {
+ out := make([]T, 0, len(in))
+ for _, item := range in {
+ if item != nil {
+ out = append(out, *item)
+ }
+ }
+ return out
+}
+
+// BuildSliceFromString will build slice from a json_agg PostgreSQL value.
+func BuildSliceFromJSONString[T any](jsonInput string) ([]T, error) {
+ var dval []*T
+ err := json.Unmarshal([]byte(jsonInput), &dval)
+ if err != nil {
+ return nil, fmt.Errorf("invalid JSON array: %w", err)
+ }
+ return SliceNilRemover(dval), nil
+}
--
2.47.2