mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-06 14:26:22 +00:00
Common Sql Types
This commit is contained in:
parent
c9b9f75b06
commit
b0b3ae662b
673
pkg/common/sql_types.go
Normal file
673
pkg/common/sql_types.go
Normal file
@ -0,0 +1,673 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func tryParseDT(str string) (time.Time, error) {
|
||||
var lasterror error
|
||||
tryFormats := []string{time.RFC3339,
|
||||
"2006-01-02T15:04:05.000-0700",
|
||||
"2006-01-02T15:04:05.000",
|
||||
"06-01-02T15:04:05.000",
|
||||
"2006-01-02T15:04:05",
|
||||
"2006-01-02 15:04:05",
|
||||
"02/01/2006",
|
||||
"02-01-2006",
|
||||
"2006-01-02",
|
||||
"15:04:05.000",
|
||||
"15:04:05",
|
||||
"15:04"}
|
||||
|
||||
for _, f := range tryFormats {
|
||||
tx, err := time.Parse(f, str)
|
||||
if err == nil {
|
||||
return tx, nil
|
||||
} else {
|
||||
lasterror = err
|
||||
}
|
||||
}
|
||||
|
||||
return time.Now(), lasterror
|
||||
}
|
||||
|
||||
func ToJSONDT(dt time.Time) string {
|
||||
return dt.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// SqlInt16 - A Int16 that supports SQL string
|
||||
type SqlInt16 int16
|
||||
|
||||
// Scan -
|
||||
func (n *SqlInt16) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*n = 0
|
||||
return nil
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
*n = SqlInt16(v)
|
||||
case int32:
|
||||
*n = SqlInt16(v)
|
||||
case int64:
|
||||
*n = SqlInt16(v)
|
||||
default:
|
||||
i, _ := strconv.ParseInt(fmt.Sprintf("%v", v), 10, 64)
|
||||
*n = SqlInt16(i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value -
|
||||
func (n SqlInt16) Value() (driver.Value, error) {
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return int64(n), nil
|
||||
}
|
||||
|
||||
// String - Override String format of ZNullInt32
|
||||
func (n SqlInt16) String() string {
|
||||
tmstr := fmt.Sprintf("%d", n)
|
||||
return tmstr
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Overre JidSON format of ZNullInt32
|
||||
func (n *SqlInt16) UnmarshalJSON(b []byte) error {
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
|
||||
n64, err := strconv.ParseInt(s, 10, 64)
|
||||
if err == nil {
|
||||
*n = SqlInt16(n64)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (n SqlInt16) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%d", n)), nil
|
||||
}
|
||||
|
||||
// SqlInt32 - A int32 that supports SQL string
|
||||
type SqlInt32 int32
|
||||
|
||||
// Scan -
|
||||
func (n *SqlInt32) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*n = 0
|
||||
return nil
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
*n = SqlInt32(v)
|
||||
case int32:
|
||||
*n = SqlInt32(v)
|
||||
case int64:
|
||||
*n = SqlInt32(v)
|
||||
default:
|
||||
i, _ := strconv.ParseInt(fmt.Sprintf("%v", v), 10, 64)
|
||||
*n = SqlInt32(i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value -
|
||||
func (n SqlInt32) Value() (driver.Value, error) {
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return int64(n), nil
|
||||
}
|
||||
|
||||
// String - Override String format of ZNullInt32
|
||||
func (n SqlInt32) String() string {
|
||||
tmstr := fmt.Sprintf("%d", n)
|
||||
return tmstr
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Overre JidSON format of ZNullInt32
|
||||
func (n *SqlInt32) UnmarshalJSON(b []byte) error {
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
|
||||
n64, err := strconv.ParseInt(s, 10, 64)
|
||||
if err == nil {
|
||||
*n = SqlInt32(n64)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (n SqlInt32) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%d", n)), nil
|
||||
}
|
||||
|
||||
// SqlInt64 - A int64 that supports SQL string
|
||||
type SqlInt64 int64
|
||||
|
||||
// Scan -
|
||||
func (n *SqlInt64) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*n = 0
|
||||
return nil
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
*n = SqlInt64(v)
|
||||
case int32:
|
||||
*n = SqlInt64(v)
|
||||
case uint32:
|
||||
*n = SqlInt64(v)
|
||||
case int64:
|
||||
*n = SqlInt64(v)
|
||||
case uint64:
|
||||
*n = SqlInt64(v)
|
||||
default:
|
||||
i, _ := strconv.ParseInt(fmt.Sprintf("%v", v), 10, 64)
|
||||
*n = SqlInt64(i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value -
|
||||
func (n SqlInt64) Value() (driver.Value, error) {
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return int64(n), nil
|
||||
}
|
||||
|
||||
// String - Override String format of ZNullInt32
|
||||
func (n SqlInt64) String() string {
|
||||
tmstr := fmt.Sprintf("%d", n)
|
||||
return tmstr
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Overre JidSON format of ZNullInt32
|
||||
func (n *SqlInt64) UnmarshalJSON(b []byte) error {
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
|
||||
n64, err := strconv.ParseInt(s, 10, 64)
|
||||
if err == nil {
|
||||
*n = SqlInt64(n64)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (n SqlInt64) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%d", n)), nil
|
||||
}
|
||||
|
||||
// SqlTimeStamp - Implementation of SqlTimeStamp with some interfaces.
|
||||
type SqlTimeStamp time.Time
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (t SqlTimeStamp) MarshalJSON() ([]byte, error) {
|
||||
if time.Time(t).IsZero() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
if time.Time(t).Before(time.Date(0001, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
tmstr := time.Time(t).Format("2006-01-02T15:04:05")
|
||||
if tmstr == "0001-01-01T00:00:00" {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("\"%s\"", tmstr)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Override JSON format of time
|
||||
func (t *SqlTimeStamp) UnmarshalJSON(b []byte) error {
|
||||
var err error
|
||||
|
||||
if b == nil {
|
||||
t = &SqlTimeStamp{}
|
||||
return nil
|
||||
}
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
if s == "null" || s == "" || s == "0" ||
|
||||
s == "0001-01-01T00:00:00" || s == "0001-01-01" {
|
||||
t = &SqlTimeStamp{}
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, err := tryParseDT(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = SqlTimeStamp(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
// Value - SQL Value of custom date
|
||||
func (t SqlTimeStamp) Value() (driver.Value, error) {
|
||||
if t.GetTime().IsZero() || t.GetTime().Before(time.Date(0002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return nil, nil
|
||||
}
|
||||
tmstr := time.Time(t).Format("2006-01-02T15:04:05")
|
||||
if tmstr <= "0001-01-01" || tmstr == "" {
|
||||
empty := time.Time{}
|
||||
return empty, nil
|
||||
}
|
||||
|
||||
return tmstr, nil
|
||||
}
|
||||
|
||||
// Scan - Scan custom date from sql
|
||||
func (t *SqlTimeStamp) Scan(value interface{}) error {
|
||||
tm, ok := value.(time.Time)
|
||||
if ok {
|
||||
*t = SqlTimeStamp(tm)
|
||||
return nil
|
||||
}
|
||||
|
||||
str, ok := value.(string)
|
||||
if ok {
|
||||
tx, err := tryParseDT(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = SqlTimeStamp(tx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String - Override String format of time
|
||||
func (t SqlTimeStamp) String() string {
|
||||
return fmt.Sprintf("%s", time.Time(t).Format("2006-01-02T15:04:05"))
|
||||
}
|
||||
|
||||
// GetTime - Returns Time
|
||||
func (t SqlTimeStamp) GetTime() time.Time {
|
||||
return time.Time(t)
|
||||
}
|
||||
|
||||
// SetTime - Returns Time
|
||||
func (t *SqlTimeStamp) SetTime(pTime time.Time) {
|
||||
*t = SqlTimeStamp(pTime)
|
||||
}
|
||||
|
||||
// Format - Formats the time
|
||||
func (t SqlTimeStamp) Format(layout string) string {
|
||||
return fmt.Sprintf("%s", time.Time(t).Format(layout))
|
||||
}
|
||||
|
||||
func SqlTimeStampNow() SqlTimeStamp {
|
||||
tx := time.Now()
|
||||
|
||||
return SqlTimeStamp(tx)
|
||||
}
|
||||
|
||||
// SqlFloat64 - SQL Int
|
||||
type SqlFloat64 sql.NullFloat64
|
||||
|
||||
// Scan -
|
||||
func (n *SqlFloat64) Scan(value interface{}) error {
|
||||
newval := sql.NullFloat64{Float64: 0, Valid: false}
|
||||
if value == nil {
|
||||
newval.Valid = false
|
||||
*n = SqlFloat64(newval)
|
||||
return nil
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case float64:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case float32:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case int64:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case int32:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case uint16:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case uint64:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
case uint32:
|
||||
newval.Float64 = float64(v)
|
||||
newval.Valid = true
|
||||
default:
|
||||
i, err := strconv.ParseInt(fmt.Sprintf("%v", v), 10, 64)
|
||||
newval.Float64 = float64(i)
|
||||
if err == nil {
|
||||
newval.Valid = false
|
||||
}
|
||||
}
|
||||
|
||||
*n = SqlFloat64(newval)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value -
|
||||
func (n SqlFloat64) Value() (driver.Value, error) {
|
||||
if !n.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return float64(n.Float64), nil
|
||||
}
|
||||
|
||||
// String -
|
||||
func (n SqlFloat64) String() string {
|
||||
if !n.Valid {
|
||||
return ""
|
||||
}
|
||||
tmstr := fmt.Sprintf("%f", n.Float64)
|
||||
return tmstr
|
||||
}
|
||||
|
||||
// UnmarshalJSON -
|
||||
func (n *SqlFloat64) UnmarshalJSON(b []byte) error {
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
invalid := (s == "null" || s == "" || len(s) < 2) || (strings.Contains(s, "{") || strings.Contains(s, "["))
|
||||
if invalid {
|
||||
return nil
|
||||
}
|
||||
|
||||
nval, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*n = SqlFloat64(sql.NullFloat64{Valid: true, Float64: float64(nval)})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (n SqlFloat64) MarshalJSON() ([]byte, error) {
|
||||
if !n.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("%f", n.Float64)), nil
|
||||
}
|
||||
|
||||
// SqlDate - Implementation of SqlTime with some interfaces.
|
||||
type SqlDate time.Time
|
||||
|
||||
// UnmarshalJSON - Override JSON format of time
|
||||
func (t *SqlDate) UnmarshalJSON(b []byte) error {
|
||||
var err error
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
if s == "null" || s == "" || s == "0" ||
|
||||
strings.HasPrefix(s, "0001-01-01T00:00:00") ||
|
||||
s == "0001-01-01" {
|
||||
t = &SqlDate{}
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, err := tryParseDT(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = SqlDate(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (t SqlDate) MarshalJSON() ([]byte, error) {
|
||||
tmstr := time.Time(t).Format("2006-01-02") //time.RFC3339
|
||||
if strings.HasPrefix(tmstr, "0001-01-01") {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("\"%s\"", tmstr)), nil
|
||||
}
|
||||
|
||||
// Value - SQL Value of custom date
|
||||
func (t SqlDate) Value() (driver.Value, error) {
|
||||
var s time.Time
|
||||
tmstr := time.Time(t).Format("2006-01-02")
|
||||
if strings.HasPrefix(tmstr, "0001-01-01") || tmstr <= "0001-01-01" {
|
||||
return nil, nil
|
||||
}
|
||||
s = time.Time(t)
|
||||
|
||||
return s.Format("2006-01-02"), nil
|
||||
}
|
||||
|
||||
// Scan - Scan custom date from sql
|
||||
func (t *SqlDate) Scan(value interface{}) error {
|
||||
tm, ok := value.(time.Time)
|
||||
if ok {
|
||||
*t = SqlDate(tm)
|
||||
return nil
|
||||
}
|
||||
|
||||
str, ok := value.(string)
|
||||
if ok {
|
||||
tx, err := tryParseDT(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = SqlDate(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64 - Override date format in unix epoch
|
||||
func (t SqlDate) Int64() int64 {
|
||||
return time.Time(t).Unix()
|
||||
}
|
||||
|
||||
// String - Override String format of time
|
||||
func (t SqlDate) String() string {
|
||||
tmstr := time.Time(t).Format("2006-01-02") //time.RFC3339
|
||||
if strings.HasPrefix(tmstr, "0001-01-01") || strings.HasPrefix(tmstr, "1800-12-31") {
|
||||
return "0"
|
||||
}
|
||||
return tmstr
|
||||
}
|
||||
|
||||
func SqlDateNow() SqlDate {
|
||||
tx := time.Now()
|
||||
return SqlDate(tx)
|
||||
}
|
||||
|
||||
// ////////////////////// SqlTime /////////////////////////
|
||||
// SqlTime - Implementation of SqlTime with some interfaces.
|
||||
type SqlTime time.Time
|
||||
|
||||
// Int64 - Override Time format in unix epoch
|
||||
func (t SqlTime) Int64() int64 {
|
||||
return time.Time(t).Unix()
|
||||
}
|
||||
|
||||
// String - Override String format of time
|
||||
func (t SqlTime) String() string {
|
||||
return time.Time(t).Format("15:04:05")
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Override JSON format of time
|
||||
func (t *SqlTime) UnmarshalJSON(b []byte) error {
|
||||
var err error
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
if s == "null" || s == "" || s == "0" ||
|
||||
s == "0001-01-01T00:00:00" || s == "00:00:00" {
|
||||
*t = SqlTime{}
|
||||
return nil
|
||||
}
|
||||
tx := time.Time{}
|
||||
tx, err = tryParseDT(s)
|
||||
*t = SqlTime(tx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Format - Format Function
|
||||
func (t SqlTime) Format(form string) string {
|
||||
tmstr := time.Time(t).Format(form)
|
||||
return tmstr
|
||||
}
|
||||
|
||||
// Scan - Scan custom date from sql
|
||||
func (t *SqlTime) Scan(value interface{}) error {
|
||||
tm, ok := value.(time.Time)
|
||||
if ok {
|
||||
*t = SqlTime(tm)
|
||||
return nil
|
||||
}
|
||||
|
||||
str, ok := value.(string)
|
||||
if ok {
|
||||
tx, err := tryParseDT(str)
|
||||
*t = SqlTime(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value - SQL Value of custom date
|
||||
func (t SqlTime) Value() (driver.Value, error) {
|
||||
|
||||
s := time.Time(t)
|
||||
st := s.Format("15:04:05")
|
||||
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (t SqlTime) MarshalJSON() ([]byte, error) {
|
||||
tmstr := time.Time(t).Format("15:04:05")
|
||||
if tmstr == "0001-01-01T00:00:00" || tmstr == "00:00:00" {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("\"%s\"", tmstr)), nil
|
||||
}
|
||||
|
||||
func SqlTimeNow() SqlTime {
|
||||
tx := time.Now()
|
||||
return SqlTime(tx)
|
||||
}
|
||||
|
||||
// SqlJSONB - Nullable JSONB String
|
||||
type SqlJSONB []byte
|
||||
|
||||
// Scan - Implements sql.Scanner for reading JSONB from database
|
||||
func (n *SqlJSONB) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*n = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
*n = SqlJSONB([]byte(v))
|
||||
case []byte:
|
||||
*n = SqlJSONB(v)
|
||||
default:
|
||||
// For other types, marshal to JSON
|
||||
dat, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal value to JSON: %v", err)
|
||||
}
|
||||
*n = SqlJSONB(dat)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value - Implements driver.Valuer for writing JSONB to database
|
||||
func (n SqlJSONB) Value() (driver.Value, error) {
|
||||
if len(n) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Validate that it's valid JSON before returning
|
||||
var js interface{}
|
||||
if err := json.Unmarshal(n, &js); err != nil {
|
||||
return nil, fmt.Errorf("invalid JSON: %v", err)
|
||||
}
|
||||
|
||||
// Return as string for PostgreSQL JSONB/JSON columns
|
||||
return string(n), nil
|
||||
}
|
||||
|
||||
func (n SqlJSONB) AsMap() (map[string]any, error) {
|
||||
if len(n) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Validate that it's valid JSON before returning
|
||||
js := make(map[string]any)
|
||||
if err := json.Unmarshal(n, &js); err != nil {
|
||||
return nil, fmt.Errorf("invalid JSON: %v", err)
|
||||
}
|
||||
return js, nil
|
||||
}
|
||||
|
||||
func (n SqlJSONB) AsSlice() ([]any, error) {
|
||||
if len(n) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Validate that it's valid JSON before returning
|
||||
js := make([]any, 0)
|
||||
if err := json.Unmarshal(n, &js); err != nil {
|
||||
return nil, fmt.Errorf("invalid JSON: %v", err)
|
||||
}
|
||||
return js, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON - Override JSON
|
||||
func (n *SqlJSONB) UnmarshalJSON(b []byte) error {
|
||||
|
||||
s := strings.Trim(strings.Trim(string(b), " "), "\"")
|
||||
invalid := (s == "null" || s == "" || len(s) < 2) || !(strings.Contains(s, "{") || strings.Contains(s, "["))
|
||||
if invalid {
|
||||
s = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
*n = []byte(s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON - Override JSON format of time
|
||||
func (n SqlJSONB) MarshalJSON() ([]byte, error) {
|
||||
if n == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
var obj interface{}
|
||||
err := json.Unmarshal(n, &obj)
|
||||
if err != nil {
|
||||
//fmt.Printf("Invalid JSON %v", err)
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
// dat, err := json.MarshalIndent(obj, " ", " ")
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("failed to convert to JSON: %v", err)
|
||||
// }
|
||||
dat := n
|
||||
|
||||
return dat, nil
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user