merge v0.23.0-rc changes
This commit is contained in:
@@ -35,6 +35,59 @@ func (d DateTime) Time() time.Time {
|
||||
return d.t
|
||||
}
|
||||
|
||||
// Add returns a new DateTime based on the current DateTime + the specified duration.
|
||||
func (d DateTime) Add(duration time.Duration) DateTime {
|
||||
d.t = d.t.Add(duration)
|
||||
return d
|
||||
}
|
||||
|
||||
// Sub returns a [time.Duration] by subtracting the specified DateTime from the current one.
|
||||
//
|
||||
// If the result exceeds the maximum (or minimum) value that can be stored in a [time.Duration],
|
||||
// the maximum (or minimum) duration will be returned.
|
||||
func (d DateTime) Sub(u DateTime) time.Duration {
|
||||
return d.Time().Sub(u.Time())
|
||||
}
|
||||
|
||||
// AddDate returns a new DateTime based on the current one + duration.
|
||||
//
|
||||
// It follows the same rules as [time.AddDate].
|
||||
func (d DateTime) AddDate(years, months, days int) DateTime {
|
||||
d.t = d.t.AddDate(years, months, days)
|
||||
return d
|
||||
}
|
||||
|
||||
// After reports whether the current DateTime instance is after u.
|
||||
func (d DateTime) After(u DateTime) bool {
|
||||
return d.Time().After(u.Time())
|
||||
}
|
||||
|
||||
// Before reports whether the current DateTime instance is before u.
|
||||
func (d DateTime) Before(u DateTime) bool {
|
||||
return d.Time().Before(u.Time())
|
||||
}
|
||||
|
||||
// Compare compares the current DateTime instance with u.
|
||||
// If the current instance is before u, it returns -1.
|
||||
// If the current instance is after u, it returns +1.
|
||||
// If they're the same, it returns 0.
|
||||
func (d DateTime) Compare(u DateTime) int {
|
||||
return d.Time().Compare(u.Time())
|
||||
}
|
||||
|
||||
// Equal reports whether the current DateTime and u represent the same time instant.
|
||||
// Two DateTime can be equal even if they are in different locations.
|
||||
// For example, 6:00 +0200 and 4:00 UTC are Equal.
|
||||
func (d DateTime) Equal(u DateTime) bool {
|
||||
return d.Time().Equal(u.Time())
|
||||
}
|
||||
|
||||
// Unix returns the current DateTime as a Unix time, aka.
|
||||
// the number of seconds elapsed since January 1, 1970 UTC.
|
||||
func (d DateTime) Unix() int64 {
|
||||
return d.Time().Unix()
|
||||
}
|
||||
|
||||
// IsZero checks whether the current DateTime instance has zero time value.
|
||||
func (d DateTime) IsZero() bool {
|
||||
return d.Time().IsZero()
|
||||
|
||||
+255
-43
@@ -1,6 +1,7 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -41,15 +42,16 @@ func TestParseDateTime(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
dt, err := types.ParseDateTime(s.value)
|
||||
if err != nil {
|
||||
t.Errorf("(%d) Failed to parse %v: %v", i, s.value, err)
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.value), func(t *testing.T) {
|
||||
dt, err := types.ParseDateTime(s.value)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse %v: %v", s.value, err)
|
||||
}
|
||||
|
||||
if dt.String() != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, dt.String())
|
||||
}
|
||||
if dt.String() != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, dt.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +71,210 @@ func TestDateTimeTime(t *testing.T) {
|
||||
result := dt.Time()
|
||||
|
||||
if !expected.Equal(result) {
|
||||
t.Errorf("Expected time %v, got %v", expected, result)
|
||||
t.Fatalf("Expected time %v, got %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeAdd(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
|
||||
d2 := d1.Add(1 * time.Hour)
|
||||
|
||||
if d1.String() != "2024-01-01 10:00:00.123Z" {
|
||||
t.Fatalf("Expected d1 to remain unchanged, got %s", d1.String())
|
||||
}
|
||||
|
||||
expected := "2024-01-01 11:00:00.123Z"
|
||||
if d2.String() != expected {
|
||||
t.Fatalf("Expected d2 %s, got %s", expected, d2.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeSub(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d2, _ := types.ParseDateTime("2024-01-01 10:30:00.123Z")
|
||||
|
||||
result := d2.Sub(d1)
|
||||
|
||||
if result.Minutes() != 30 {
|
||||
t.Fatalf("Expected %v minutes diff, got %v", 30, result.Minutes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeAddDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
|
||||
d2 := d1.AddDate(1, 2, 3)
|
||||
|
||||
if d1.String() != "2024-01-01 10:00:00.123Z" {
|
||||
t.Fatalf("Expected d1 to remain unchanged, got %s", d1.String())
|
||||
}
|
||||
|
||||
expected := "2025-03-04 10:00:00.123Z"
|
||||
if d2.String() != expected {
|
||||
t.Fatalf("Expected d2 %s, got %s", expected, d2.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeAfter(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d2, _ := types.ParseDateTime("2024-01-02 10:00:00.123Z")
|
||||
d3, _ := types.ParseDateTime("2024-01-03 10:00:00.123Z")
|
||||
|
||||
scenarios := []struct {
|
||||
a types.DateTime
|
||||
b types.DateTime
|
||||
expect bool
|
||||
}{
|
||||
// d1
|
||||
{d1, d1, false},
|
||||
{d1, d2, false},
|
||||
{d1, d3, false},
|
||||
// d2
|
||||
{d2, d1, true},
|
||||
{d2, d2, false},
|
||||
{d2, d3, false},
|
||||
// d3
|
||||
{d3, d1, true},
|
||||
{d3, d2, true},
|
||||
{d3, d3, false},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("after_%d", i), func(t *testing.T) {
|
||||
if v := s.a.After(s.b); v != s.expect {
|
||||
t.Fatalf("Expected %v, got %v", s.expect, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeBefore(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d2, _ := types.ParseDateTime("2024-01-02 10:00:00.123Z")
|
||||
d3, _ := types.ParseDateTime("2024-01-03 10:00:00.123Z")
|
||||
|
||||
scenarios := []struct {
|
||||
a types.DateTime
|
||||
b types.DateTime
|
||||
expect bool
|
||||
}{
|
||||
// d1
|
||||
{d1, d1, false},
|
||||
{d1, d2, true},
|
||||
{d1, d3, true},
|
||||
// d2
|
||||
{d2, d1, false},
|
||||
{d2, d2, false},
|
||||
{d2, d3, true},
|
||||
// d3
|
||||
{d3, d1, false},
|
||||
{d3, d2, false},
|
||||
{d3, d3, false},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("before_%d", i), func(t *testing.T) {
|
||||
if v := s.a.Before(s.b); v != s.expect {
|
||||
t.Fatalf("Expected %v, got %v", s.expect, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeCompare(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d2, _ := types.ParseDateTime("2024-01-02 10:00:00.123Z")
|
||||
d3, _ := types.ParseDateTime("2024-01-03 10:00:00.123Z")
|
||||
|
||||
scenarios := []struct {
|
||||
a types.DateTime
|
||||
b types.DateTime
|
||||
expect int
|
||||
}{
|
||||
// d1
|
||||
{d1, d1, 0},
|
||||
{d1, d2, -1},
|
||||
{d1, d3, -1},
|
||||
// d2
|
||||
{d2, d1, 1},
|
||||
{d2, d2, 0},
|
||||
{d2, d3, -1},
|
||||
// d3
|
||||
{d3, d1, 1},
|
||||
{d3, d2, 1},
|
||||
{d3, d3, 0},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("compare_%d", i), func(t *testing.T) {
|
||||
if v := s.a.Compare(s.b); v != s.expect {
|
||||
t.Fatalf("Expected %v, got %v", s.expect, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d2, _ := types.ParseDateTime("2024-01-01 10:00:00.123Z")
|
||||
d3, _ := types.ParseDateTime("2024-01-01 10:00:00.124Z")
|
||||
|
||||
scenarios := []struct {
|
||||
a types.DateTime
|
||||
b types.DateTime
|
||||
expect bool
|
||||
}{
|
||||
{d1, d1, true},
|
||||
{d1, d2, true},
|
||||
{d1, d3, false},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("equal_%d", i), func(t *testing.T) {
|
||||
if v := s.a.Equal(s.b); v != s.expect {
|
||||
t.Fatalf("Expected %v, got %v", s.expect, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeUnix(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
date string
|
||||
expected int64
|
||||
}{
|
||||
{"", -62135596800},
|
||||
{"2022-01-01 11:23:45.678Z", 1641036225},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.date), func(t *testing.T) {
|
||||
dt, err := types.ParseDateTime(s.date)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
v := dt.Unix()
|
||||
|
||||
if v != s.expected {
|
||||
t.Fatalf("Expected %d, got %d", s.expected, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,19 +313,21 @@ func TestDateTimeMarshalJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
dt, err := types.ParseDateTime(s.date)
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.date), func(t *testing.T) {
|
||||
dt, err := types.ParseDateTime(s.date)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result, err := dt.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
}
|
||||
result, err := dt.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(result) != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, string(result))
|
||||
}
|
||||
if string(result) != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, string(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +344,14 @@ func TestDateTimeUnmarshalJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
dt := types.DateTime{}
|
||||
dt.UnmarshalJSON([]byte(s.date))
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.date), func(t *testing.T) {
|
||||
dt := types.DateTime{}
|
||||
dt.UnmarshalJSON([]byte(s.date))
|
||||
|
||||
if dt.String() != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, dt.String())
|
||||
}
|
||||
if dt.String() != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, dt.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,16 +368,18 @@ func TestDateTimeValue(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
dt, _ := types.ParseDateTime(s.value)
|
||||
result, err := dt.Value()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.value), func(t *testing.T) {
|
||||
dt, _ := types.ParseDateTime(s.value)
|
||||
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, result)
|
||||
}
|
||||
result, err := dt.Value()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,16 +401,17 @@ func TestDateTimeScan(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
dt := types.DateTime{}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.value), func(t *testing.T) {
|
||||
dt := types.DateTime{}
|
||||
|
||||
err := dt.Scan(s.value)
|
||||
if err != nil {
|
||||
t.Errorf("(%d) Failed to parse %v: %v", i, s.value, err)
|
||||
continue
|
||||
}
|
||||
err := dt.Scan(s.value)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse %v: %v", s.value, err)
|
||||
}
|
||||
|
||||
if !strings.Contains(dt.String(), s.expected) {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, dt.String())
|
||||
}
|
||||
if !strings.Contains(dt.String(), s.expected) {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, dt.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,32 +6,38 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// JsonArray defines a slice that is safe for json and db read/write.
|
||||
type JsonArray[T any] []T
|
||||
// JSONArray defines a slice that is safe for json and db read/write.
|
||||
type JSONArray[T any] []T
|
||||
|
||||
// internal alias to prevent recursion during marshalization.
|
||||
type jsonArrayAlias[T any] JsonArray[T]
|
||||
type jsonArrayAlias[T any] JSONArray[T]
|
||||
|
||||
// MarshalJSON implements the [json.Marshaler] interface.
|
||||
func (m JsonArray[T]) MarshalJSON() ([]byte, error) {
|
||||
func (m JSONArray[T]) MarshalJSON() ([]byte, error) {
|
||||
// initialize an empty map to ensure that `[]` is returned as json
|
||||
if m == nil {
|
||||
m = JsonArray[T]{}
|
||||
m = JSONArray[T]{}
|
||||
}
|
||||
|
||||
return json.Marshal(jsonArrayAlias[T](m))
|
||||
}
|
||||
|
||||
// String returns the string representation of the current json array.
|
||||
func (m JSONArray[T]) String() string {
|
||||
v, _ := m.MarshalJSON()
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// Value implements the [driver.Valuer] interface.
|
||||
func (m JsonArray[T]) Value() (driver.Value, error) {
|
||||
func (m JSONArray[T]) Value() (driver.Value, error) {
|
||||
data, err := json.Marshal(m)
|
||||
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
// Scan implements [sql.Scanner] interface to scan the provided value
|
||||
// into the current JsonArray[T] instance.
|
||||
func (m *JsonArray[T]) Scan(value any) error {
|
||||
// into the current JSONArray[T] instance.
|
||||
func (m *JSONArray[T]) Scan(value any) error {
|
||||
var data []byte
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
@@ -41,7 +47,7 @@ func (m *JsonArray[T]) Scan(value any) error {
|
||||
case string:
|
||||
data = []byte(v)
|
||||
default:
|
||||
return fmt.Errorf("failed to unmarshal JsonArray value: %q", value)
|
||||
return fmt.Errorf("Failed to unmarshal JSONArray value: %q.", value)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
|
||||
@@ -3,64 +3,92 @@ package types_test
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
func TestJsonArrayMarshalJSON(t *testing.T) {
|
||||
func TestJSONArrayMarshalJSON(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json json.Marshaler
|
||||
expected string
|
||||
}{
|
||||
{new(types.JsonArray[any]), "[]"},
|
||||
{types.JsonArray[any]{}, `[]`},
|
||||
{types.JsonArray[int]{1, 2, 3}, `[1,2,3]`},
|
||||
{types.JsonArray[string]{"test1", "test2", "test3"}, `["test1","test2","test3"]`},
|
||||
{types.JsonArray[any]{1, "test"}, `[1,"test"]`},
|
||||
{new(types.JSONArray[any]), "[]"},
|
||||
{types.JSONArray[any]{}, `[]`},
|
||||
{types.JSONArray[int]{1, 2, 3}, `[1,2,3]`},
|
||||
{types.JSONArray[string]{"test1", "test2", "test3"}, `["test1","test2","test3"]`},
|
||||
{types.JSONArray[any]{1, "test"}, `[1,"test"]`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
if string(result) != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %s", i, s.expected, string(result))
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(result) != s.expected {
|
||||
t.Fatalf("Expected %s, got %s", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonArrayValue(t *testing.T) {
|
||||
func TestJSONArrayString(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json fmt.Stringer
|
||||
expected string
|
||||
}{
|
||||
{new(types.JSONArray[any]), "[]"},
|
||||
{types.JSONArray[any]{}, `[]`},
|
||||
{types.JSONArray[int]{1, 2, 3}, `[1,2,3]`},
|
||||
{types.JSONArray[string]{"test1", "test2", "test3"}, `["test1","test2","test3"]`},
|
||||
{types.JSONArray[any]{1, "test"}, `[1,"test"]`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result := s.json.String()
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected\n%s\ngot\n%s", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONArrayValue(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json driver.Valuer
|
||||
expected driver.Value
|
||||
}{
|
||||
{new(types.JsonArray[any]), `[]`},
|
||||
{types.JsonArray[any]{}, `[]`},
|
||||
{types.JsonArray[int]{1, 2, 3}, `[1,2,3]`},
|
||||
{types.JsonArray[string]{"test1", "test2", "test3"}, `["test1","test2","test3"]`},
|
||||
{types.JsonArray[any]{1, "test"}, `[1,"test"]`},
|
||||
{new(types.JSONArray[any]), `[]`},
|
||||
{types.JSONArray[any]{}, `[]`},
|
||||
{types.JSONArray[int]{1, 2, 3}, `[1,2,3]`},
|
||||
{types.JSONArray[string]{"test1", "test2", "test3"}, `["test1","test2","test3"]`},
|
||||
{types.JSONArray[any]{1, "test"}, `[1,"test"]`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expected, result)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %s, got %#v", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonArrayScan(t *testing.T) {
|
||||
func TestJSONArrayScan(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
value any
|
||||
expectError bool
|
||||
expectJson string
|
||||
expectJSON string
|
||||
}{
|
||||
{``, false, `[]`},
|
||||
{[]byte{}, false, `[]`},
|
||||
@@ -78,7 +106,7 @@ func TestJsonArrayScan(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
arr := types.JsonArray[any]{}
|
||||
arr := types.JSONArray[any]{}
|
||||
scanErr := arr.Scan(s.value)
|
||||
|
||||
hasErr := scanErr != nil
|
||||
@@ -89,8 +117,8 @@ func TestJsonArrayScan(t *testing.T) {
|
||||
|
||||
result, _ := arr.MarshalJSON()
|
||||
|
||||
if string(result) != s.expectJson {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expectJson, string(result))
|
||||
if string(result) != s.expectJSON {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expectJSON, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-13
@@ -6,47 +6,53 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// JsonMap defines a map that is safe for json and db read/write.
|
||||
type JsonMap map[string]any
|
||||
// JSONMap defines a map that is safe for json and db read/write.
|
||||
type JSONMap[T any] map[string]T
|
||||
|
||||
// MarshalJSON implements the [json.Marshaler] interface.
|
||||
func (m JsonMap) MarshalJSON() ([]byte, error) {
|
||||
type alias JsonMap // prevent recursion
|
||||
func (m JSONMap[T]) MarshalJSON() ([]byte, error) {
|
||||
type alias JSONMap[T] // prevent recursion
|
||||
|
||||
// initialize an empty map to ensure that `{}` is returned as json
|
||||
if m == nil {
|
||||
m = JsonMap{}
|
||||
m = JSONMap[T]{}
|
||||
}
|
||||
|
||||
return json.Marshal(alias(m))
|
||||
}
|
||||
|
||||
// Get retrieves a single value from the current JsonMap.
|
||||
// String returns the string representation of the current json map.
|
||||
func (m JSONMap[T]) String() string {
|
||||
v, _ := m.MarshalJSON()
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// Get retrieves a single value from the current JSONMap[T].
|
||||
//
|
||||
// This helper was added primarily to assist the goja integration since custom map types
|
||||
// don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods).
|
||||
func (m JsonMap) Get(key string) any {
|
||||
func (m JSONMap[T]) Get(key string) T {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
// Set sets a single value in the current JsonMap.
|
||||
// Set sets a single value in the current JSONMap[T].
|
||||
//
|
||||
// This helper was added primarily to assist the goja integration since custom map types
|
||||
// don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods).
|
||||
func (m JsonMap) Set(key string, value any) {
|
||||
func (m JSONMap[T]) Set(key string, value T) {
|
||||
m[key] = value
|
||||
}
|
||||
|
||||
// Value implements the [driver.Valuer] interface.
|
||||
func (m JsonMap) Value() (driver.Value, error) {
|
||||
func (m JSONMap[T]) Value() (driver.Value, error) {
|
||||
data, err := json.Marshal(m)
|
||||
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
// Scan implements [sql.Scanner] interface to scan the provided value
|
||||
// into the current `JsonMap` instance.
|
||||
func (m *JsonMap) Scan(value any) error {
|
||||
// into the current JSONMap[T] instance.
|
||||
func (m *JSONMap[T]) Scan(value any) error {
|
||||
var data []byte
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
@@ -56,7 +62,7 @@ func (m *JsonMap) Scan(value any) error {
|
||||
case string:
|
||||
data = []byte(v)
|
||||
default:
|
||||
return fmt.Errorf("failed to unmarshal JsonMap value: %q", value)
|
||||
return fmt.Errorf("failed to unmarshal JSONMap[T] value: %q", value)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
|
||||
@@ -2,54 +2,81 @@ package types_test
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
func TestJsonMapMarshalJSON(t *testing.T) {
|
||||
func TestJSONMapMarshalJSON(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonMap
|
||||
json types.JSONMap[any]
|
||||
expected string
|
||||
}{
|
||||
{nil, "{}"},
|
||||
{types.JsonMap{}, `{}`},
|
||||
{types.JsonMap{"test1": 123, "test2": "lorem"}, `{"test1":123,"test2":"lorem"}`},
|
||||
{types.JsonMap{"test": []int{1, 2, 3}}, `{"test":[1,2,3]}`},
|
||||
{types.JSONMap[any]{}, `{}`},
|
||||
{types.JSONMap[any]{"test1": 123, "test2": "lorem"}, `{"test1":123,"test2":"lorem"}`},
|
||||
{types.JSONMap[any]{"test": []int{1, 2, 3}}, `{"test":[1,2,3]}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
if string(result) != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %s", i, s.expected, string(result))
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(result) != s.expected {
|
||||
t.Fatalf("Expected\n%s\ngot\n%s", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonMapGet(t *testing.T) {
|
||||
func TestJSONMapMarshalString(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonMap
|
||||
json types.JSONMap[any]
|
||||
expected string
|
||||
}{
|
||||
{nil, "{}"},
|
||||
{types.JSONMap[any]{}, `{}`},
|
||||
{types.JSONMap[any]{"test1": 123, "test2": "lorem"}, `{"test1":123,"test2":"lorem"}`},
|
||||
{types.JSONMap[any]{"test": []int{1, 2, 3}}, `{"test":[1,2,3]}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result := s.json.String()
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected\n%s\ngot\n%s", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONMapGet(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JSONMap[any]
|
||||
key string
|
||||
expected any
|
||||
}{
|
||||
{nil, "test", nil},
|
||||
{types.JsonMap{"test": 123}, "test", 123},
|
||||
{types.JsonMap{"test": 123}, "missing", nil},
|
||||
{types.JSONMap[any]{"test": 123}, "test", 123},
|
||||
{types.JSONMap[any]{"test": 123}, "missing", nil},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result := s.json.Get(s.key)
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expected, result)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.key), func(t *testing.T) {
|
||||
result := s.json.Get(s.key)
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %s, got %#v", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonMapSet(t *testing.T) {
|
||||
func TestJSONMapSet(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
key string
|
||||
value any
|
||||
@@ -60,44 +87,48 @@ func TestJsonMapSet(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
j := types.JsonMap{}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.key), func(t *testing.T) {
|
||||
j := types.JSONMap[any]{}
|
||||
|
||||
j.Set(s.key, s.value)
|
||||
j.Set(s.key, s.value)
|
||||
|
||||
if v := j[s.key]; v != s.value {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.value, v)
|
||||
}
|
||||
if v := j[s.key]; v != s.value {
|
||||
t.Fatalf("Expected %s, got %#v", s.value, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonMapValue(t *testing.T) {
|
||||
func TestJSONMapValue(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonMap
|
||||
json types.JSONMap[any]
|
||||
expected driver.Value
|
||||
}{
|
||||
{nil, `{}`},
|
||||
{types.JsonMap{}, `{}`},
|
||||
{types.JsonMap{"test1": 123, "test2": "lorem"}, `{"test1":123,"test2":"lorem"}`},
|
||||
{types.JsonMap{"test": []int{1, 2, 3}}, `{"test":[1,2,3]}`},
|
||||
{types.JSONMap[any]{}, `{}`},
|
||||
{types.JSONMap[any]{"test1": 123, "test2": "lorem"}, `{"test1":123,"test2":"lorem"}`},
|
||||
{types.JSONMap[any]{"test": []int{1, 2, 3}}, `{"test":[1,2,3]}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expected, result)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.expected), func(t *testing.T) {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %s, got %#v", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonArrayMapScan(t *testing.T) {
|
||||
func TestJSONArrayMapScan(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
value any
|
||||
expectError bool
|
||||
expectJson string
|
||||
expectJSON string
|
||||
}{
|
||||
{``, false, `{}`},
|
||||
{nil, false, `{}`},
|
||||
@@ -114,19 +145,20 @@ func TestJsonArrayMapScan(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
arr := types.JsonMap{}
|
||||
scanErr := arr.Scan(s.value)
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.value), func(t *testing.T) {
|
||||
arr := types.JSONMap[any]{}
|
||||
scanErr := arr.Scan(s.value)
|
||||
|
||||
hasErr := scanErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Errorf("(%d) Expected %v, got %v (%v)", i, s.expectError, hasErr, scanErr)
|
||||
continue
|
||||
}
|
||||
hasErr := scanErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Fatalf("Expected %v, got %v (%v)", s.expectError, hasErr, scanErr)
|
||||
}
|
||||
|
||||
result, _ := arr.MarshalJSON()
|
||||
result, _ := arr.MarshalJSON()
|
||||
|
||||
if string(result) != s.expectJson {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expectJson, string(result))
|
||||
}
|
||||
if string(result) != s.expectJSON {
|
||||
t.Fatalf("Expected %s, got %s", s.expectJSON, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+17
-16
@@ -6,24 +6,25 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// JsonRaw defines a json value type that is safe for db read/write.
|
||||
type JsonRaw []byte
|
||||
// JSONRaw defines a json value type that is safe for db read/write.
|
||||
type JSONRaw []byte
|
||||
|
||||
// ParseJsonRaw creates a new JsonRaw instance from the provided value
|
||||
// (could be JsonRaw, int, float, string, []byte, etc.).
|
||||
func ParseJsonRaw(value any) (JsonRaw, error) {
|
||||
result := JsonRaw{}
|
||||
// ParseJSONRaw creates a new JSONRaw instance from the provided value
|
||||
// (could be JSONRaw, int, float, string, []byte, etc.).
|
||||
func ParseJSONRaw(value any) (JSONRaw, error) {
|
||||
result := JSONRaw{}
|
||||
err := result.Scan(value)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// String returns the current JsonRaw instance as a json encoded string.
|
||||
func (j JsonRaw) String() string {
|
||||
return string(j)
|
||||
// String returns the current JSONRaw instance as a json encoded string.
|
||||
func (j JSONRaw) String() string {
|
||||
raw, _ := j.MarshalJSON()
|
||||
return string(raw)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the [json.Marshaler] interface.
|
||||
func (j JsonRaw) MarshalJSON() ([]byte, error) {
|
||||
func (j JSONRaw) MarshalJSON() ([]byte, error) {
|
||||
if len(j) == 0 {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
@@ -32,9 +33,9 @@ func (j JsonRaw) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the [json.Unmarshaler] interface.
|
||||
func (j *JsonRaw) UnmarshalJSON(b []byte) error {
|
||||
func (j *JSONRaw) UnmarshalJSON(b []byte) error {
|
||||
if j == nil {
|
||||
return errors.New("JsonRaw: UnmarshalJSON on nil pointer")
|
||||
return errors.New("JSONRaw: UnmarshalJSON on nil pointer")
|
||||
}
|
||||
|
||||
*j = append((*j)[0:0], b...)
|
||||
@@ -43,7 +44,7 @@ func (j *JsonRaw) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
// Value implements the [driver.Valuer] interface.
|
||||
func (j JsonRaw) Value() (driver.Value, error) {
|
||||
func (j JSONRaw) Value() (driver.Value, error) {
|
||||
if len(j) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -52,8 +53,8 @@ func (j JsonRaw) Value() (driver.Value, error) {
|
||||
}
|
||||
|
||||
// Scan implements [sql.Scanner] interface to scan the provided value
|
||||
// into the current JsonRaw instance.
|
||||
func (j *JsonRaw) Scan(value any) error {
|
||||
// into the current JSONRaw instance.
|
||||
func (j *JSONRaw) Scan(value any) error {
|
||||
var data []byte
|
||||
|
||||
switch v := value.(type) {
|
||||
@@ -67,7 +68,7 @@ func (j *JsonRaw) Scan(value any) error {
|
||||
if v != "" {
|
||||
data = []byte(v)
|
||||
}
|
||||
case JsonRaw:
|
||||
case JSONRaw:
|
||||
if len(v) != 0 {
|
||||
data = []byte(v)
|
||||
}
|
||||
|
||||
@@ -2,21 +2,22 @@ package types_test
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
func TestParseJsonRaw(t *testing.T) {
|
||||
func TestParseJSONRaw(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
value any
|
||||
expectError bool
|
||||
expectJson string
|
||||
expectJSON string
|
||||
}{
|
||||
{nil, false, `null`},
|
||||
{``, false, `null`},
|
||||
{[]byte{}, false, `null`},
|
||||
{types.JsonRaw{}, false, `null`},
|
||||
{types.JSONRaw{}, false, `null`},
|
||||
{`{}`, false, `{}`},
|
||||
{`[]`, false, `[]`},
|
||||
{123, false, `123`},
|
||||
@@ -30,70 +31,75 @@ func TestParseJsonRaw(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
raw, parseErr := types.ParseJsonRaw(s.value)
|
||||
hasErr := parseErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Errorf("(%d) Expected %v, got %v (%v)", i, s.expectError, hasErr, parseErr)
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.value), func(t *testing.T) {
|
||||
raw, parseErr := types.ParseJSONRaw(s.value)
|
||||
|
||||
result, _ := raw.MarshalJSON()
|
||||
hasErr := parseErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Fatalf("Expected %v, got %v (%v)", s.expectError, hasErr, parseErr)
|
||||
}
|
||||
|
||||
if string(result) != s.expectJson {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expectJson, string(result))
|
||||
}
|
||||
result, _ := raw.MarshalJSON()
|
||||
|
||||
if string(result) != s.expectJSON {
|
||||
t.Fatalf("Expected %s, got %s", s.expectJSON, string(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonRawString(t *testing.T) {
|
||||
func TestJSONRawString(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonRaw
|
||||
expected string
|
||||
}{
|
||||
{nil, ``},
|
||||
{types.JsonRaw{}, ``},
|
||||
{types.JsonRaw([]byte(`123`)), `123`},
|
||||
{types.JsonRaw(`{"demo":123}`), `{"demo":123}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result := s.json.String()
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonRawMarshalJSON(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonRaw
|
||||
json types.JSONRaw
|
||||
expected string
|
||||
}{
|
||||
{nil, `null`},
|
||||
{types.JsonRaw{}, `null`},
|
||||
{types.JsonRaw([]byte(`123`)), `123`},
|
||||
{types.JsonRaw(`{"demo":123}`), `{"demo":123}`},
|
||||
{types.JSONRaw{}, `null`},
|
||||
{types.JSONRaw([]byte(`123`)), `123`},
|
||||
{types.JSONRaw(`{"demo":123}`), `{"demo":123}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if string(result) != s.expected {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expected, string(result))
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.expected), func(t *testing.T) {
|
||||
result := s.json.String()
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonRawUnmarshalJSON(t *testing.T) {
|
||||
func TestJSONRawMarshalJSON(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JSONRaw
|
||||
expected string
|
||||
}{
|
||||
{nil, `null`},
|
||||
{types.JSONRaw{}, `null`},
|
||||
{types.JSONRaw([]byte(`123`)), `123`},
|
||||
{types.JSONRaw(`{"demo":123}`), `{"demo":123}`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.expected), func(t *testing.T) {
|
||||
result, err := s.json.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(result) != s.expected {
|
||||
t.Fatalf("Expected %q, got %q", s.expected, string(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONRawUnmarshalJSON(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json []byte
|
||||
expectString string
|
||||
}{
|
||||
{nil, ""},
|
||||
{nil, `null`},
|
||||
{[]byte{0, 1, 2}, "\x00\x01\x02"},
|
||||
{[]byte("123"), "123"},
|
||||
{[]byte("test"), "test"},
|
||||
@@ -101,53 +107,57 @@ func TestJsonRawUnmarshalJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
raw := types.JsonRaw{}
|
||||
err := raw.UnmarshalJSON(s.json)
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%s", i, s.expectString), func(t *testing.T) {
|
||||
raw := types.JSONRaw{}
|
||||
|
||||
if raw.String() != s.expectString {
|
||||
t.Errorf("(%d) Expected %q, got %q", i, s.expectString, raw.String())
|
||||
}
|
||||
err := raw.UnmarshalJSON(s.json)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if raw.String() != s.expectString {
|
||||
t.Fatalf("Expected %q, got %q", s.expectString, raw.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonRawValue(t *testing.T) {
|
||||
func TestJSONRawValue(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
json types.JsonRaw
|
||||
json types.JSONRaw
|
||||
expected driver.Value
|
||||
}{
|
||||
{nil, nil},
|
||||
{types.JsonRaw{}, nil},
|
||||
{types.JsonRaw(``), nil},
|
||||
{types.JsonRaw(`test`), `test`},
|
||||
{types.JSONRaw{}, nil},
|
||||
{types.JSONRaw(``), nil},
|
||||
{types.JSONRaw(`test`), `test`},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Errorf("(%d) %v", i, err)
|
||||
continue
|
||||
}
|
||||
if result != s.expected {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expected, result)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.json), func(t *testing.T) {
|
||||
result, err := s.json.Value()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result != s.expected {
|
||||
t.Fatalf("Expected %s, got %v", s.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonRawScan(t *testing.T) {
|
||||
func TestJSONRawScan(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
value any
|
||||
expectError bool
|
||||
expectJson string
|
||||
expectJSON string
|
||||
}{
|
||||
{nil, false, `null`},
|
||||
{``, false, `null`},
|
||||
{[]byte{}, false, `null`},
|
||||
{types.JsonRaw{}, false, `null`},
|
||||
{types.JsonRaw(`test`), false, `test`},
|
||||
{types.JSONRaw{}, false, `null`},
|
||||
{types.JSONRaw(`test`), false, `test`},
|
||||
{`{}`, false, `{}`},
|
||||
{`[]`, false, `[]`},
|
||||
{123, false, `123`},
|
||||
@@ -161,18 +171,19 @@ func TestJsonRawScan(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
raw := types.JsonRaw{}
|
||||
scanErr := raw.Scan(s.value)
|
||||
hasErr := scanErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Errorf("(%d) Expected %v, got %v (%v)", i, s.expectError, hasErr, scanErr)
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d_%#v", i, s.value), func(t *testing.T) {
|
||||
raw := types.JSONRaw{}
|
||||
scanErr := raw.Scan(s.value)
|
||||
hasErr := scanErr != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Fatalf("Expected %v, got %v (%v)", s.expectError, hasErr, scanErr)
|
||||
}
|
||||
|
||||
result, _ := raw.MarshalJSON()
|
||||
result, _ := raw.MarshalJSON()
|
||||
|
||||
if string(result) != s.expectJson {
|
||||
t.Errorf("(%d) Expected %s, got %v", i, s.expectJson, string(result))
|
||||
}
|
||||
if string(result) != s.expectJSON {
|
||||
t.Fatalf("Expected %s, got %v", s.expectJSON, string(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user