github.com/RevenueMonster/sqlike@v1.0.6/types/key.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"database/sql/driver"
     7  	"encoding"
     8  	"encoding/base64"
     9  	"encoding/gob"
    10  	"encoding/json"
    11  	"fmt"
    12  	"io"
    13  	"math/rand"
    14  	"net/url"
    15  	"os"
    16  	"strconv"
    17  	"strings"
    18  	"time"
    19  
    20  	"errors"
    21  
    22  	pb "github.com/RevenueMonster/sqlike/protobuf"
    23  	"github.com/RevenueMonster/sqlike/reflext"
    24  	sqldriver "github.com/RevenueMonster/sqlike/sql/driver"
    25  	"github.com/RevenueMonster/sqlike/sqlike/columns"
    26  	"github.com/RevenueMonster/sqlike/util"
    27  	"github.com/segmentio/ksuid"
    28  	"go.mongodb.org/mongo-driver/bson"
    29  	"go.mongodb.org/mongo-driver/bson/bsontype"
    30  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    31  	"google.golang.org/protobuf/proto"
    32  )
    33  
    34  const keyEnv = "SQLIKE_NAMESPACE"
    35  
    36  // Writer :
    37  type writer interface {
    38  	io.Writer
    39  	WriteString(string) (int, error)
    40  	WriteByte(byte) error
    41  }
    42  
    43  // Key :
    44  type Key struct {
    45  	Namespace string
    46  	Kind      string
    47  	IntID     int64
    48  	NameID    string
    49  	Parent    *Key
    50  }
    51  
    52  var (
    53  	_ fmt.GoStringer           = (*Key)(nil)
    54  	_ driver.Valuer            = (*Key)(nil)
    55  	_ sql.Scanner              = (*Key)(nil)
    56  	_ fmt.Stringer             = (*Key)(nil)
    57  	_ encoding.TextMarshaler   = (*Key)(nil)
    58  	_ encoding.TextUnmarshaler = (*Key)(nil)
    59  	_ json.Marshaler           = (*Key)(nil)
    60  	_ json.Unmarshaler         = (*Key)(nil)
    61  	_ bson.ValueMarshaler      = (*Key)(nil)
    62  	_ bson.ValueUnmarshaler    = (*Key)(nil)
    63  )
    64  
    65  // DataType :
    66  func (k Key) DataType(t sqldriver.Info, sf reflext.StructFielder) columns.Column {
    67  	tag := sf.Tag()
    68  	size, charset, collate := "512", "latin1", "latin1_bin"
    69  	if v, ok := tag.LookUp("charset"); ok {
    70  		charset = v
    71  	}
    72  	if v, ok := tag.LookUp("collate"); ok {
    73  		collate = v
    74  	}
    75  	if v, ok := tag.LookUp("size"); ok {
    76  		size = v
    77  	}
    78  
    79  	return columns.Column{
    80  		Name:      sf.Name(),
    81  		DataType:  "VARCHAR",
    82  		Type:      "VARCHAR(" + size + ")",
    83  		Nullable:  reflext.IsNullable(sf.Type()),
    84  		Charset:   &charset,
    85  		Collation: &collate,
    86  	}
    87  }
    88  
    89  // ID : is a safe method to retrieve `IntID` or `NameID` value
    90  func (k *Key) ID() string {
    91  	if k == nil {
    92  		return ""
    93  	}
    94  	if k.NameID != "" {
    95  		return k.NameID
    96  	}
    97  	return strconv.FormatInt(k.IntID, 10)
    98  }
    99  
   100  // Root :
   101  func (k *Key) Root() *Key {
   102  	for {
   103  		if k.Parent == nil {
   104  			return k
   105  		}
   106  		k = k.Parent
   107  	}
   108  }
   109  
   110  // Clone :
   111  func (k *Key) Clone() *Key {
   112  	return copyKey(k)
   113  }
   114  
   115  func copyKey(k *Key) *Key {
   116  	if k == nil {
   117  		return nil
   118  	}
   119  	nk := new(Key)
   120  	nk.Namespace = k.Namespace
   121  	nk.Kind = k.Kind
   122  	nk.NameID = k.NameID
   123  	nk.IntID = k.IntID
   124  	nk.Parent = copyKey(k.Parent)
   125  	return nk
   126  }
   127  
   128  // Value :
   129  func (k Key) Value() (driver.Value, error) {
   130  	if k.Incomplete() {
   131  		return nil, nil // database shouldn't store value ",0", it's meaningless
   132  	}
   133  	blr := util.AcquireString()
   134  	defer util.ReleaseString(blr)
   135  	marshal(&k, blr, true)
   136  	return blr.String(), nil
   137  }
   138  
   139  // Scan :
   140  func (k *Key) Scan(it interface{}) error {
   141  	switch vi := it.(type) {
   142  	case []byte:
   143  		if err := k.unmarshal(string(vi)); err != nil {
   144  			return err
   145  		}
   146  	case string:
   147  		if err := k.unmarshal(vi); err != nil {
   148  			return err
   149  		}
   150  	}
   151  	return nil
   152  }
   153  
   154  // Incomplete : is a safe method to check key is nil or empty
   155  func (k *Key) Incomplete() bool {
   156  	if k == nil {
   157  		return true
   158  	}
   159  	return k.NameID == "" && k.IntID == 0
   160  }
   161  
   162  // // valid returns whether the key is valid.
   163  // func (k *Key) IsZero() bool {
   164  // 	if k == nil {
   165  // 		return false
   166  // 	}
   167  // 	for ; k != nil; k = k.Parent {
   168  // 		if k.Kind == "" {
   169  // 			return false
   170  // 		}
   171  // 		if k.NameID != "" && k.IntID != 0 {
   172  // 			return false
   173  // 		}
   174  // 		if k.Parent != nil {
   175  // 			if k.Parent.Incomplete() {
   176  // 				return false
   177  // 			}
   178  // 			if k.Parent.Namespace != k.Namespace {
   179  // 				return false
   180  // 			}
   181  // 		}
   182  // 	}
   183  // 	return true
   184  // }
   185  
   186  // Equal reports whether two keys are equal. Two keys are equal if they are
   187  // both nil, or if their kinds, IDs, names, namespaces and parents are equal.
   188  func (k *Key) Equal(o *Key) bool {
   189  	for {
   190  		if k == nil || o == nil {
   191  			return k == o // if either is nil, both must be nil
   192  		}
   193  		if k.Namespace != o.Namespace || k.NameID != o.NameID || k.IntID != o.IntID || k.Kind != o.Kind {
   194  			return false
   195  		}
   196  		if k.Parent == nil && o.Parent == nil {
   197  			return true
   198  		}
   199  		k = k.Parent
   200  		o = o.Parent
   201  	}
   202  }
   203  
   204  // MarshalText :
   205  func (k Key) MarshalText() ([]byte, error) {
   206  	buf := new(bytes.Buffer)
   207  	marshal(&k, buf, true)
   208  	return buf.Bytes(), nil
   209  }
   210  
   211  // MarshalBinary :
   212  func (k Key) MarshalBinary() ([]byte, error) {
   213  	if k.Incomplete() {
   214  		return []byte(`null`), nil
   215  	}
   216  	return []byte(`"` + k.Encode() + `"`), nil
   217  }
   218  
   219  // MarshalJSON :
   220  func (k Key) MarshalJSON() ([]byte, error) {
   221  	if k.Incomplete() {
   222  		return []byte(`null`), nil
   223  	}
   224  	return []byte(`"` + k.Encode() + `"`), nil
   225  }
   226  
   227  // MarshalJSONB :
   228  func (k Key) MarshalJSONB() ([]byte, error) {
   229  	if k.Incomplete() {
   230  		return []byte(`null`), nil
   231  	}
   232  	buf := new(bytes.Buffer)
   233  	buf.WriteRune('"')
   234  	marshal(&k, buf, true)
   235  	buf.WriteRune('"')
   236  	return buf.Bytes(), nil
   237  }
   238  
   239  // UnmarshalBinary :
   240  func (k *Key) UnmarshalBinary(b []byte) error {
   241  	str := string(b)
   242  	if str == "null" {
   243  		return nil
   244  	}
   245  	key, err := DecodeKey(str)
   246  	if err != nil {
   247  		return err
   248  	}
   249  	*k = *key
   250  	return nil
   251  }
   252  
   253  // UnmarshalText :
   254  func (k *Key) UnmarshalText(b []byte) error {
   255  	str := string(b)
   256  	if str == "null" {
   257  		return nil
   258  	}
   259  	key, err := DecodeKey(str)
   260  	if err != nil {
   261  		return err
   262  	}
   263  	*k = *key
   264  	return nil
   265  }
   266  
   267  // UnmarshalJSON :
   268  func (k *Key) UnmarshalJSON(b []byte) error {
   269  	length := len(b)
   270  	if length < 2 {
   271  		return errors.New("types: invalid key json value")
   272  	}
   273  	str := string(b)
   274  	if str == "null" {
   275  		return nil
   276  	}
   277  	str = string(b[1 : length-1])
   278  	key, err := DecodeKey(str)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	*k = *key
   283  	return nil
   284  }
   285  
   286  // UnmarshalJSONB :
   287  func (k *Key) UnmarshalJSONB(b []byte) error {
   288  	length := len(b)
   289  	if length < 2 {
   290  		return errors.New("types: invalid key json value")
   291  	}
   292  	str := string(b)
   293  	if str == "null" {
   294  		return nil
   295  	}
   296  	str = string(b[1 : length-1])
   297  	return k.unmarshal(str)
   298  }
   299  
   300  // MarshalBSONValue :
   301  func (k Key) MarshalBSONValue() (bsontype.Type, []byte, error) {
   302  	if k.Incomplete() {
   303  		return bsontype.Null, nil, nil
   304  	}
   305  	return bsontype.String, bsoncore.AppendString(nil, k.String()), nil
   306  }
   307  
   308  // UnmarshalBSONValue :
   309  func (k *Key) UnmarshalBSONValue(t bsontype.Type, b []byte) error {
   310  	if k == nil {
   311  		return errors.New("types: invalid key value <nil>")
   312  	}
   313  	if t == bsontype.Null {
   314  		return nil
   315  	}
   316  	v, _, ok := bsoncore.ReadString(b)
   317  	if !ok {
   318  		return errors.New("types: invalid bson string value")
   319  	}
   320  	return k.unmarshal(v)
   321  }
   322  
   323  func (k Key) MarshalGQL(w io.Writer) {
   324  	if k.Incomplete() {
   325  		w.Write([]byte(`null`))
   326  		return
   327  	}
   328  	w.Write([]byte(`"` + k.Encode() + `"`))
   329  }
   330  
   331  func (k *Key) UnmarshalGQL(it interface{}) error {
   332  	switch vi := it.(type) {
   333  	case *Key:
   334  		*k = *vi
   335  	case []byte:
   336  		return k.UnmarshalJSON(vi)
   337  	case string:
   338  		return k.UnmarshalJSON([]byte(vi))
   339  	case nil:
   340  	default:
   341  		return fmt.Errorf("sqlike: %T is not a Key", it)
   342  	}
   343  	return nil
   344  }
   345  
   346  // GoString returns a string representation the raw string of key (without encoding).
   347  func (k Key) GoString() string {
   348  	b := bytes.NewBuffer(make([]byte, 0, 512))
   349  	marshal(&k, b, false)
   350  	return b.String()
   351  }
   352  
   353  // String returns a string representation of the key.
   354  func (k Key) String() string {
   355  	b := bytes.NewBuffer(make([]byte, 0, 512))
   356  	marshal(&k, b, true)
   357  	return b.String()
   358  }
   359  
   360  // marshal marshals the key's string representation to the buffer.
   361  func marshal(k *Key, w writer, escape bool) {
   362  	if k.Parent != nil {
   363  		marshal(k.Parent, w, escape)
   364  		w.WriteByte('/')
   365  	}
   366  	w.WriteString(k.Kind)
   367  	w.WriteByte(',')
   368  	if k.NameID != "" {
   369  		w.WriteByte('\'')
   370  		if escape {
   371  			w.WriteString(url.PathEscape(k.NameID))
   372  		} else {
   373  			w.WriteString(k.NameID)
   374  		}
   375  		w.WriteByte('\'')
   376  	} else {
   377  		w.WriteString(strconv.FormatInt(k.IntID, 10))
   378  	}
   379  }
   380  
   381  func (k *Key) unmarshal(str string) error {
   382  	if str == "null" {
   383  		k = nil
   384  		return nil
   385  	}
   386  
   387  	var (
   388  		idx    int
   389  		path   string
   390  		length int
   391  		paths  []string
   392  		value  string
   393  		err    error
   394  	)
   395  
   396  	for {
   397  		idx = strings.LastIndex(str, "/")
   398  		path = str
   399  		if idx > -1 {
   400  			path = str[idx+1:]
   401  		}
   402  		paths = strings.Split(path, ",")
   403  		if len(paths) != 2 {
   404  			return errors.New("invalid key path")
   405  		}
   406  		k.Kind = paths[0]
   407  		value = paths[1]
   408  		length = len(value)
   409  		if length < 1 {
   410  			return errors.New("invalid key string")
   411  		}
   412  		if length > 2 && value[0] == '\'' && value[length-1] == '\'' {
   413  			value = value[1 : length-1]
   414  			value, _ = url.PathUnescape(value)
   415  			k.NameID = value
   416  		} else {
   417  			k.IntID, err = strconv.ParseInt(value, 10, 64)
   418  			if err != nil {
   419  				return err
   420  			}
   421  		}
   422  
   423  		if idx > -1 {
   424  			str = str[:idx]
   425  			if len(str) < 1 {
   426  				return nil
   427  			}
   428  		} else {
   429  			return nil
   430  		}
   431  
   432  		if k.Parent == nil {
   433  			k.Parent = new(Key)
   434  		}
   435  		k = k.Parent
   436  	}
   437  }
   438  
   439  type gobKey struct {
   440  	Namespace string
   441  	AppID     string
   442  	Kind      string
   443  	StringID  string
   444  	IntID     int64
   445  	Parent    *gobKey
   446  }
   447  
   448  func keyToGobKey(k *Key) *gobKey {
   449  	if k == nil {
   450  		return nil
   451  	}
   452  	return &gobKey{
   453  		Kind:      k.Kind,
   454  		StringID:  k.NameID,
   455  		IntID:     k.IntID,
   456  		Parent:    keyToGobKey(k.Parent),
   457  		Namespace: k.Namespace,
   458  	}
   459  }
   460  
   461  func gobKeyToKey(gk *gobKey) *Key {
   462  	if gk == nil {
   463  		return nil
   464  	}
   465  	return &Key{
   466  		Kind:      gk.Kind,
   467  		IntID:     gk.IntID,
   468  		NameID:    gk.StringID,
   469  		Parent:    gobKeyToKey(gk.Parent),
   470  		Namespace: gk.Namespace,
   471  	}
   472  }
   473  
   474  // Encode returns an opaque representation of the key
   475  // suitable for use in HTML and URLs.
   476  // This is compatible with the Python and Java runtimes.
   477  func (k Key) Encode() string {
   478  	pk := keyToProto(&k)
   479  	b, err := proto.Marshal(pk)
   480  	if err != nil {
   481  		panic(err)
   482  	}
   483  	// Trailing padding is stripped.
   484  	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
   485  }
   486  
   487  // ParseKey :
   488  func ParseKey(value string) (*Key, error) {
   489  	k := new(Key)
   490  	if err := k.unmarshal(value); err != nil {
   491  		return nil, err
   492  	}
   493  	return k, nil
   494  }
   495  
   496  // DecodeKey decodes a key from the opaque representation returned by Encode.
   497  func DecodeKey(encoded string) (*Key, error) {
   498  	// Re-add padding.
   499  	if m := len(encoded) % 4; m != 0 {
   500  		encoded += strings.Repeat("=", 4-m)
   501  	}
   502  
   503  	b, err := base64.URLEncoding.DecodeString(encoded)
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  
   508  	k := new(pb.Key)
   509  	if err := proto.Unmarshal(b, k); err != nil {
   510  		return nil, err
   511  	}
   512  
   513  	return protoToKey(k), nil
   514  }
   515  
   516  // GobEncode marshals the key into a sequence of bytes
   517  // using an encoding/gob.Encoder.
   518  func (k Key) GobEncode() ([]byte, error) {
   519  	buf := new(bytes.Buffer)
   520  	if err := gob.NewEncoder(buf).Encode(keyToGobKey(&k)); err != nil {
   521  		return nil, err
   522  	}
   523  	return buf.Bytes(), nil
   524  }
   525  
   526  // GobDecode unmarshals a sequence of bytes using an encoding/gob.Decoder.
   527  func (k *Key) GobDecode(buf []byte) error {
   528  	gk := new(gobKey)
   529  	if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil {
   530  		return err
   531  	}
   532  	*k = *gobKeyToKey(gk)
   533  	return nil
   534  }
   535  
   536  func keyToProto(k *Key) *pb.Key {
   537  	if k == nil {
   538  		return nil
   539  	}
   540  
   541  	return &pb.Key{
   542  		Namespace: k.Namespace,
   543  		Kind:      k.Kind,
   544  		NameID:    k.NameID,
   545  		IntID:     k.IntID,
   546  		Parent:    keyToProto(k.Parent),
   547  	}
   548  }
   549  
   550  func protoToKey(pk *pb.Key) *Key {
   551  	if pk == nil {
   552  		return nil
   553  	}
   554  
   555  	return &Key{
   556  		Namespace: pk.Namespace,
   557  		Kind:      pk.Kind,
   558  		NameID:    pk.NameID,
   559  		IntID:     pk.IntID,
   560  		Parent:    protoToKey(pk.Parent),
   561  	}
   562  }
   563  
   564  // NameKey creates a new key with a name.
   565  // The supplied kind cannot be empty.
   566  // The supplied parent must either be a complete key or nil.
   567  // The namespace of the new key is empty.
   568  func NameKey(kind, name string, parent *Key) *Key {
   569  	return &Key{
   570  		Namespace: os.Getenv(keyEnv),
   571  		Kind:      kind,
   572  		NameID:    name,
   573  		Parent:    parent,
   574  	}
   575  }
   576  
   577  // IDKey creates a new key with an ID.
   578  // The supplied kind cannot be empty.
   579  // The supplied parent must either be a complete key or nil.
   580  // The namespace of the new key is empty.
   581  func IDKey(kind string, id int64, parent *Key) *Key {
   582  	return &Key{
   583  		Namespace: os.Getenv(keyEnv),
   584  		Kind:      kind,
   585  		IntID:     id,
   586  		Parent:    parent,
   587  	}
   588  }
   589  
   590  const (
   591  	minSeed = int64(100000000)
   592  	maxSeed = int64(999999999)
   593  )
   594  
   595  // NewIDKey :
   596  func NewIDKey(kind string, parent *Key) *Key {
   597  	rand.Seed(time.Now().UnixNano())
   598  	strID := strconv.FormatInt(time.Now().Unix(), 10) + strconv.FormatInt(rand.Int63n(maxSeed-minSeed)+minSeed, 10)
   599  	id, err := strconv.ParseInt(strID, 10, 64)
   600  	if err != nil {
   601  		panic(err)
   602  	}
   603  
   604  	return &Key{
   605  		Namespace: os.Getenv(keyEnv),
   606  		Kind:      kind,
   607  		IntID:     id,
   608  		Parent:    parent,
   609  	}
   610  }
   611  
   612  // NewNameKey :
   613  func NewNameKey(kind string, parent *Key) *Key {
   614  	return &Key{
   615  		Namespace: os.Getenv(keyEnv),
   616  		Kind:      kind,
   617  		NameID:    ksuid.New().String(),
   618  		Parent:    parent,
   619  	}
   620  }