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  }