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 }