github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/datum/datum.go (about) 1 // Copyright 2023 zGraph Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package datum 16 17 import ( 18 "errors" 19 "fmt" 20 "regexp" 21 "strconv" 22 "time" 23 24 "github.com/cockroachdb/apd/v3" 25 "github.com/vescale/zgraph/types" 26 ) 27 28 const Null = dNull(0) 29 30 type Datum interface { 31 Type() types.T 32 String() string 33 isDatum() 34 } 35 36 func (dNull) isDatum() {} 37 func (dBool) isDatum() {} 38 func (dInt) isDatum() {} 39 func (dFloat) isDatum() {} 40 func (dString) isDatum() {} 41 func (dBytes) isDatum() {} 42 func (dDecimal) isDatum() {} 43 func (*Date) isDatum() {} 44 func (*Time) isDatum() {} 45 func (*TimeTZ) isDatum() {} 46 func (*Timestamp) isDatum() {} 47 func (*TimestampTZ) isDatum() {} 48 func (*Interval) isDatum() {} 49 func (*Vertex) isDatum() {} 50 func (*Edge) isDatum() {} 51 52 type Row []Datum 53 54 type dNull int 55 56 func (dNull) Type() types.T { return types.Unknown } 57 func (dNull) String() string { return "NULL" } 58 59 type dBool bool 60 61 func (dBool) Type() types.T { 62 return types.Bool 63 } 64 65 func (d dBool) String() string { 66 if d { 67 return "TRUE" 68 } else { 69 return "FALSE" 70 } 71 } 72 73 func NewBool(b bool) Datum { 74 return dBool(b) 75 } 76 77 func AsBool(d Datum) bool { 78 v, err := TryAsBool(d) 79 if err != nil { 80 panic(err) 81 } 82 return v 83 } 84 85 func TryAsBool(d Datum) (bool, error) { 86 switch v := d.(type) { 87 case dBool: 88 return bool(v), nil 89 case dString: 90 return strconv.ParseBool(string(v)) 91 default: 92 return false, fmt.Errorf("cannot convert %T to bool", d) 93 } 94 } 95 96 type dInt int64 97 98 func (dInt) Type() types.T { 99 return types.Int 100 } 101 102 func (d dInt) String() string { 103 return strconv.FormatInt(int64(d), 10) 104 } 105 106 func NewInt(i int64) Datum { 107 return dInt(i) 108 } 109 110 func AsInt(d Datum) int64 { 111 v, err := TryAsInt(d) 112 if err != nil { 113 panic(err) 114 } 115 return v 116 } 117 118 func TryAsInt(d Datum) (int64, error) { 119 switch v := d.(type) { 120 case dInt: 121 return int64(v), nil 122 default: 123 return 0, fmt.Errorf("cannot convert %T to int", d) 124 } 125 } 126 127 type dFloat float64 128 129 func (dFloat) Type() types.T { 130 return types.Float 131 } 132 133 func (d dFloat) String() string { 134 return strconv.FormatFloat(float64(d), 'g', -1, 64) 135 } 136 137 func NewFloat(f float64) Datum { 138 return dFloat(f) 139 } 140 141 func AsFloat(d Datum) float64 { 142 v, err := TryAsFloat(d) 143 if err != nil { 144 panic(err) 145 } 146 return v 147 } 148 149 func TryAsFloat(d Datum) (float64, error) { 150 switch v := d.(type) { 151 case dFloat: 152 return float64(v), nil 153 default: 154 return 0, fmt.Errorf("cannot convert %T to float", d) 155 } 156 } 157 158 type dString string 159 160 func (dString) Type() types.T { 161 return types.String 162 } 163 164 func (d dString) String() string { 165 return string(d) 166 } 167 168 func NewString(s string) Datum { 169 return dString(s) 170 } 171 172 func AsString(d Datum) string { 173 v, err := TryAsString(d) 174 if err != nil { 175 panic(err) 176 } 177 return v 178 } 179 180 func TryAsString(d Datum) (string, error) { 181 switch v := d.(type) { 182 case dString: 183 return string(v), nil 184 case dBytes: 185 return string(v), nil 186 default: 187 return "", fmt.Errorf("cannot convert %T to string", d) 188 } 189 } 190 191 type dBytes []byte 192 193 func (dBytes) Type() types.T { 194 return types.Bytes 195 } 196 197 func (d dBytes) String() string { 198 return string(d) 199 } 200 201 func NewBytes(b []byte) Datum { 202 return dBytes(b) 203 } 204 205 func AsBytes(d Datum) []byte { 206 v, err := TryAsBytes(d) 207 if err != nil { 208 panic(err) 209 } 210 return v 211 } 212 213 func TryAsBytes(d Datum) ([]byte, error) { 214 switch v := d.(type) { 215 case dBytes: 216 return v, nil 217 case dString: 218 return []byte(v), nil 219 default: 220 return nil, fmt.Errorf("cannot convert %T to bytes", d) 221 } 222 } 223 224 type dDecimal struct { 225 *apd.Decimal 226 } 227 228 func (dDecimal) Type() types.T { 229 return types.Decimal 230 } 231 232 func (d dDecimal) String() string { 233 return d.Decimal.Text('g') 234 } 235 236 func NewDecimal(d *apd.Decimal) Datum { 237 return dDecimal{d} 238 } 239 240 func ParseDecimal(s string) (Datum, error) { 241 d := &apd.Decimal{} 242 _, _, err := d.SetString(s) 243 if err != nil { 244 return nil, err 245 } 246 return NewDecimal(d), nil 247 } 248 249 func AsDecimal(d Datum) *apd.Decimal { 250 v, err := TryAsDecimal(d) 251 if err != nil { 252 panic(err) 253 } 254 return v 255 } 256 257 func TryAsDecimal(d Datum) (*apd.Decimal, error) { 258 switch v := d.(type) { 259 case dDecimal: 260 return v.Decimal, nil 261 default: 262 return nil, fmt.Errorf("cannot convert %T to decimal", d) 263 } 264 } 265 266 const ( 267 secondsPerDay = 24 * 60 * 60 268 dateLayout = "2006-01-02" 269 ) 270 271 type Date struct { 272 days int32 // days since unix epoch 273 } 274 275 func (*Date) Type() types.T { 276 return types.Date 277 } 278 279 func (d *Date) String() string { 280 return time.Unix(int64(d.days)*secondsPerDay, 0).Format(dateLayout) 281 } 282 283 func (d *Date) UnixEpochDays() int32 { 284 return d.days 285 } 286 287 func NewDateFromUnixEpochDays(days int32) *Date { 288 return &Date{days: days} 289 } 290 291 func ParseDate(s string) (*Date, error) { 292 t, err := time.Parse(dateLayout, s) 293 if err != nil { 294 return nil, err 295 } 296 return &Date{days: int32(t.Unix() / secondsPerDay)}, nil 297 } 298 299 func AsDate(d Datum) *Date { 300 v, err := TryAsDate(d) 301 if err != nil { 302 panic(err) 303 } 304 return v 305 } 306 307 func TryAsDate(d Datum) (*Date, error) { 308 switch v := d.(type) { 309 case *Date: 310 return v, nil 311 default: 312 return nil, fmt.Errorf("cannot convert %T to date", d) 313 } 314 } 315 316 const ( 317 secondsPerHour = 60 * 60 318 secondsPerMinute = 60 319 minutesPerHour = 60 320 ) 321 322 type TimeOfDay int32 // seconds since midnight 323 324 func (t *TimeOfDay) Hour() int { 325 return int(*t) / secondsPerHour 326 } 327 328 func (t *TimeOfDay) Minute() int { 329 return (int(*t) % secondsPerHour) / secondsPerMinute 330 } 331 332 func (t *TimeOfDay) Second() int { 333 return int(*t) % secondsPerMinute 334 } 335 336 type Time struct { 337 TimeOfDay 338 } 339 340 func (*Time) Type() types.T { 341 return types.Time 342 } 343 344 func (t *Time) String() string { 345 return fmt.Sprintf("%02d:%02d:%02d", t.Hour(), t.Minute(), t.Second()) 346 } 347 348 func NewTime(t TimeOfDay) *Time { 349 return &Time{TimeOfDay: t} 350 } 351 352 var timeFormatRegex = regexp.MustCompile(`^(\d{2}):(\d{2}):(\d{2})$`) 353 354 func ParseTime(s string) (*Time, error) { 355 m := timeFormatRegex.FindStringSubmatch(s) 356 if len(m) != 4 { 357 return nil, fmt.Errorf("could not parse %q as Time", s) 358 } 359 hour, _ := strconv.Atoi(m[1]) 360 minute, _ := strconv.Atoi(m[2]) 361 second, _ := strconv.Atoi(m[3]) 362 if hour > 23 { 363 return nil, errors.New("time hour out of range") 364 } 365 if minute > 59 { 366 return nil, errors.New("time minute out of range") 367 } 368 if second > 59 { 369 return nil, errors.New("time second out of range") 370 } 371 return &Time{TimeOfDay: TimeOfDay(hour*secondsPerHour + minute*secondsPerMinute + second)}, nil 372 } 373 374 func AsTime(d Datum) *Time { 375 v, err := TryAsTime(d) 376 if err != nil { 377 panic(err) 378 } 379 return v 380 } 381 382 func TryAsTime(d Datum) (*Time, error) { 383 switch v := d.(type) { 384 case *Time: 385 return v, nil 386 default: 387 return nil, fmt.Errorf("cannot convert %T to time", d) 388 } 389 } 390 391 type TimeTZ struct { 392 TimeOfDay 393 offsetMinutes int32 394 } 395 396 func (t *TimeTZ) Type() types.T { 397 return types.TimeTZ 398 } 399 400 func (t *TimeTZ) String() string { 401 offsetHour := t.offsetMinutes / minutesPerHour 402 offsetMinute := t.offsetMinutes % minutesPerHour 403 if t.offsetMinutes >= 0 { 404 return fmt.Sprintf("%02d:%02d:%02d+%02d:%02d", t.Hour(), t.Minute(), t.Second(), offsetHour, offsetMinute) 405 } else { 406 return fmt.Sprintf("%02d:%02d:%02d%03d:%02d", t.Hour(), t.Minute(), t.Second(), offsetHour, offsetMinute) 407 } 408 } 409 410 var timeTZFormatRegex = regexp.MustCompile(`^(\d{2}):(\d{2}):(\d{2})([+-]\d{2}):(\d{2})$`) 411 412 func ParseTimeTZ(s string) (*TimeTZ, error) { 413 m := timeTZFormatRegex.FindStringSubmatch(s) 414 if len(m) != 6 { 415 return nil, fmt.Errorf("could not parse %s as TimeTZ", s) 416 } 417 hour, _ := strconv.Atoi(m[1]) 418 minute, _ := strconv.Atoi(m[2]) 419 second, _ := strconv.Atoi(m[3]) 420 if hour > 23 { 421 return nil, errors.New("time hour out of range") 422 } 423 if minute > 59 { 424 return nil, errors.New("time minute out of range") 425 } 426 if second > 59 { 427 return nil, errors.New("time second out of range") 428 } 429 offsetHour, _ := strconv.Atoi(m[4]) 430 offsetMinute, _ := strconv.Atoi(m[5]) 431 if offsetHour > 12 { 432 return nil, errors.New("time zone offset hour out of range") 433 } 434 if offsetMinute > 59 { 435 return nil, errors.New("time zone offset minute out of range") 436 } 437 return &TimeTZ{ 438 TimeOfDay: TimeOfDay(hour*secondsPerHour + minute*secondsPerMinute + second), 439 offsetMinutes: int32(offsetHour*minutesPerHour + offsetMinute), 440 }, nil 441 } 442 443 func AsTimeTZ(d Datum) *TimeTZ { 444 v, err := TryAsTimeTZ(d) 445 if err != nil { 446 panic(err) 447 } 448 return v 449 } 450 451 func TryAsTimeTZ(d Datum) (*TimeTZ, error) { 452 switch v := d.(type) { 453 case *TimeTZ: 454 return v, nil 455 default: 456 return nil, fmt.Errorf("cannot convert %T to time with time zone", d) 457 } 458 } 459 460 func ParseTimeOrTimeTZ(s string) (*Time, *TimeTZ, error) { 461 t, err := ParseTime(s) 462 if err == nil { 463 return t, nil, nil 464 } 465 ttz, err := ParseTimeTZ(s) 466 if err == nil { 467 return nil, ttz, nil 468 } 469 return nil, nil, fmt.Errorf("could not parse %q as Time or TimeTZ", s) 470 } 471 472 const timestampLayout = "2006-01-02 15:04:05" 473 474 type Timestamp struct { 475 time.Time 476 } 477 478 func (t *Timestamp) Type() types.T { 479 return types.Timestamp 480 } 481 482 func (t *Timestamp) String() string { 483 return t.UTC().Format(timestampLayout) 484 } 485 486 func ParseTimestamp(s string) (*Timestamp, error) { 487 t, err := time.Parse(timestampLayout, s) 488 if err != nil { 489 return nil, err 490 } 491 return &Timestamp{Time: t}, nil 492 } 493 494 func AsTimestamp(d Datum) *Timestamp { 495 v, err := TryAsTimestamp(d) 496 if err != nil { 497 panic(err) 498 } 499 return v 500 } 501 502 func TryAsTimestamp(d Datum) (*Timestamp, error) { 503 switch v := d.(type) { 504 case *Timestamp: 505 return v, nil 506 default: 507 return nil, fmt.Errorf("cannot convert %T to timestamp", d) 508 } 509 } 510 511 const timestampTZLayout = "2006-01-02 15:04:05-07:00" 512 513 type TimestampTZ struct { 514 time.Time 515 } 516 517 func (t *TimestampTZ) Type() types.T { 518 return types.TimestampTZ 519 } 520 521 func (t *TimestampTZ) String() string { 522 return t.Format(timestampTZLayout) 523 } 524 525 func ParseTimestampTZ(s string) (*TimestampTZ, error) { 526 t, err := time.Parse(timestampTZLayout, s) 527 if err != nil { 528 return nil, err 529 } 530 return &TimestampTZ{Time: t}, nil 531 } 532 533 func AsTimestampTZ(d Datum) *TimestampTZ { 534 v, err := TryAsTimestampTZ(d) 535 if err != nil { 536 panic(err) 537 } 538 return v 539 } 540 541 func TryAsTimestampTZ(d Datum) (*TimestampTZ, error) { 542 switch v := d.(type) { 543 case *TimestampTZ: 544 return v, nil 545 default: 546 return nil, fmt.Errorf("cannot convert %T to timestamp with time zone", d) 547 } 548 } 549 550 func ParseTimestampOrTimestampTZ(s string) (*Timestamp, *TimestampTZ, error) { 551 t, err := ParseTimestamp(s) 552 if err == nil { 553 return t, nil, nil 554 } 555 ttz, err := ParseTimestampTZ(s) 556 if err == nil { 557 return nil, ttz, nil 558 } 559 return nil, nil, fmt.Errorf("could not parse %q as Timestamp or TimestampTZ", s) 560 } 561 562 type IntervalUnit uint8 563 564 const ( 565 IntervalUnitYear IntervalUnit = iota 566 IntervalUnitMonth 567 IntervalUnitDay 568 IntervalUnitHour 569 IntervalUnitMinute 570 IntervalUnitSecond 571 ) 572 573 type Interval struct { 574 months int64 575 days int64 576 seconds int64 577 } 578 579 func (i *Interval) Type() types.T { 580 return types.Interval 581 } 582 583 func (i *Interval) String() string { 584 if i.months != 0 { 585 if i.months%12 == 0 { 586 return fmt.Sprintf("%d YEAR", i.months/12) 587 } else { 588 return fmt.Sprintf("%d MONTH", i.months) 589 } 590 } else if i.days != 0 { 591 return fmt.Sprintf("%d DAY", i.days) 592 } else { 593 if i.seconds%3600 == 0 { 594 return fmt.Sprintf("%d HOUR", i.seconds/3600) 595 } else if i.seconds%60 == 0 { 596 return fmt.Sprintf("%d MINUTE", i.seconds/60) 597 } else { 598 return fmt.Sprintf("%d SECOND", i.seconds) 599 } 600 } 601 } 602 603 func NewInterval(dur int64, unit IntervalUnit) *Interval { 604 switch unit { 605 case IntervalUnitYear: 606 return &Interval{months: dur * 12} 607 case IntervalUnitMonth: 608 return &Interval{months: dur} 609 case IntervalUnitDay: 610 return &Interval{days: dur} 611 case IntervalUnitHour: 612 return &Interval{seconds: dur * 3600} 613 case IntervalUnitMinute: 614 return &Interval{seconds: dur * 60} 615 case IntervalUnitSecond: 616 return &Interval{seconds: dur} 617 default: 618 panic(fmt.Sprintf("unknown interval unit %d", unit)) 619 } 620 } 621 622 func AsInterval(d Datum) *Interval { 623 v, err := TryAsInterval(d) 624 if err != nil { 625 panic(err) 626 } 627 return v 628 } 629 630 func TryAsInterval(d Datum) (*Interval, error) { 631 switch v := d.(type) { 632 case *Interval: 633 return v, nil 634 default: 635 return nil, fmt.Errorf("cannot convert %T to interval", d) 636 } 637 } 638 639 type Vertex struct { 640 ID int64 641 Labels []string 642 Props map[string]Datum 643 } 644 645 func (v *Vertex) Type() types.T { 646 return types.Vertex 647 } 648 649 func (v *Vertex) String() string { 650 return fmt.Sprintf("VERTEX(%d)", v.ID) 651 } 652 653 func AsVertex(d Datum) *Vertex { 654 v, err := TryAsVertex(d) 655 if err != nil { 656 panic(err) 657 } 658 return v 659 } 660 661 func TryAsVertex(d Datum) (*Vertex, error) { 662 switch v := d.(type) { 663 case *Vertex: 664 return v, nil 665 default: 666 return nil, fmt.Errorf("cannot convert %T to vertex", d) 667 } 668 } 669 670 type Edge struct { 671 SrcID int64 672 DstID int64 673 Labels []string 674 Props map[string]Datum 675 } 676 677 func (e *Edge) Type() types.T { 678 return types.Edge 679 } 680 681 func (e *Edge) String() string { 682 return fmt.Sprintf("EDGE(%d, %d)", e.SrcID, e.DstID) 683 } 684 685 func AsEdge(d Datum) *Edge { 686 v, err := TryAsEdge(d) 687 if err != nil { 688 panic(err) 689 } 690 return v 691 } 692 693 func TryAsEdge(d Datum) (*Edge, error) { 694 switch v := d.(type) { 695 case *Edge: 696 return v, nil 697 default: 698 return nil, fmt.Errorf("cannot convert %T to edge", d) 699 } 700 }