github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/testdata.go (about)

     1  // Copyright 2020 Dolthub, Inc.
     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 sqle
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"reflect"
    21  	"time"
    22  
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/google/uuid"
    25  
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/row"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo"
    30  	"github.com/dolthub/dolt/go/store/types"
    31  )
    32  
    33  // This file collects useful test table definitions and functions for SQL tests to use. It primarily defines a table
    34  // name, schema, and some sample rows to use in tests, as well as functions for creating and seeding a test database,
    35  // transforming row results, and so on.
    36  
    37  const (
    38  	IdTag = iota + 200
    39  	FirstNameTag
    40  	LastNameTag
    41  	IsMarriedTag
    42  	AgeTag
    43  	emptyTag
    44  	RatingTag
    45  	UuidTag
    46  	NumEpisodesTag
    47  	firstUnusedTag // keep at end
    48  )
    49  
    50  const (
    51  	EpisodeIdTag = iota + 300
    52  	EpNameTag
    53  	EpAirDateTag
    54  	EpRatingTag
    55  )
    56  
    57  const (
    58  	AppCharacterTag = iota + 400
    59  	AppEpTag
    60  	AppCommentsTag
    61  )
    62  
    63  const (
    64  	HomerId = iota
    65  	MargeId
    66  	BartId
    67  	LisaId
    68  	MoeId
    69  	BarneyId
    70  )
    71  
    72  var PeopleTestSchema = createPeopleTestSchema()
    73  var PeopleTableName = "people"
    74  
    75  var EpisodesTestSchema = createEpisodesTestSchema()
    76  var EpisodesTableName = "episodes"
    77  
    78  var AppearancesTestSchema = createAppearancesTestSchema()
    79  var AppearancesTableName = "appearances"
    80  
    81  func createPeopleTestSchema() schema.Schema {
    82  	colColl := schema.NewColCollection(
    83  		schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
    84  		schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
    85  		schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
    86  		schema.NewColumn("is_married", IsMarriedTag, types.IntKind, false),
    87  		schema.NewColumn("age", AgeTag, types.IntKind, false),
    88  		schema.NewColumn("rating", RatingTag, types.FloatKind, false),
    89  		schema.NewColumn("uuid", UuidTag, types.StringKind, false),
    90  		schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
    91  	)
    92  	sch := schema.MustSchemaFromCols(colColl)
    93  	return sch
    94  }
    95  
    96  func createEpisodesTestSchema() schema.Schema {
    97  	colColl := schema.NewColCollection(
    98  		schema.NewColumn("id", EpisodeIdTag, types.IntKind, true, schema.NotNullConstraint{}),
    99  		schema.NewColumn("name", EpNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   100  		newColumnWithTypeInfo("air_date", EpAirDateTag, typeinfo.DatetimeType, false),
   101  		schema.NewColumn("rating", EpRatingTag, types.FloatKind, false),
   102  	)
   103  	sch := schema.MustSchemaFromCols(colColl)
   104  	return sch
   105  }
   106  
   107  func createAppearancesTestSchema() schema.Schema {
   108  	colColl := schema.NewColCollection(
   109  		schema.NewColumn("character_id", AppCharacterTag, types.IntKind, true, schema.NotNullConstraint{}),
   110  		schema.NewColumn("episode_id", AppEpTag, types.IntKind, true, schema.NotNullConstraint{}),
   111  		schema.NewColumn("comments", AppCommentsTag, types.StringKind, false),
   112  	)
   113  	sch := schema.MustSchemaFromCols(colColl)
   114  	return sch
   115  }
   116  
   117  func newColumnWithTypeInfo(name string, tag uint64, info typeinfo.TypeInfo, partOfPk bool, constraints ...schema.ColConstraint) schema.Column {
   118  	col, err := schema.NewColumnWithTypeInfo(name, tag, info, partOfPk, "", false, "", constraints...)
   119  	if err != nil {
   120  		panic(fmt.Sprintf("unexpected error creating column: %s", err.Error()))
   121  	}
   122  	return col
   123  }
   124  
   125  func NewPeopleRow(id int, first, last string, isMarried bool, age int, rating float64) row.Row {
   126  	isMarriedVal := types.Int(0)
   127  	if isMarried {
   128  		isMarriedVal = types.Int(1)
   129  	}
   130  
   131  	vals := row.TaggedValues{
   132  		IdTag:        types.Int(id),
   133  		FirstNameTag: types.String(first),
   134  		LastNameTag:  types.String(last),
   135  		IsMarriedTag: isMarriedVal,
   136  		AgeTag:       types.Int(age),
   137  		RatingTag:    types.Float(rating),
   138  	}
   139  
   140  	r, err := row.New(types.Format_Default, PeopleTestSchema, vals)
   141  
   142  	if err != nil {
   143  		panic(err)
   144  	}
   145  
   146  	return r
   147  }
   148  
   149  func newEpsRow2(id int, name string, airdate string, rating float64) row.Row {
   150  	vals := row.TaggedValues{
   151  		EpisodeIdTag: types.Int(id),
   152  		EpNameTag:    types.String(name),
   153  		EpAirDateTag: types.Timestamp(DatetimeStrToTimestamp(airdate)),
   154  		EpRatingTag:  types.Float(rating),
   155  	}
   156  
   157  	r, err := row.New(types.Format_Default, EpisodesTestSchema, vals)
   158  
   159  	if err != nil {
   160  		panic(err)
   161  	}
   162  
   163  	return r
   164  }
   165  
   166  func DatetimeStrToTimestamp(datetime string) time.Time {
   167  	time, err := time.Parse("2006-01-02 15:04:05", datetime)
   168  	if err != nil {
   169  		panic(fmt.Sprintf("unable to parse datetime %s", datetime))
   170  	}
   171  	return time
   172  }
   173  
   174  func newAppsRow2(charId, epId int, comment string) row.Row {
   175  	vals := row.TaggedValues{
   176  		AppCharacterTag: types.Int(charId),
   177  		AppEpTag:        types.Int(epId),
   178  		AppCommentsTag:  types.String(comment),
   179  	}
   180  
   181  	r, err := row.New(types.Format_Default, AppearancesTestSchema, vals)
   182  
   183  	if err != nil {
   184  		panic(err)
   185  	}
   186  
   187  	return r
   188  }
   189  
   190  // Most rows don't have these optional fields set, as they aren't needed for basic testing
   191  func NewPeopleRowWithOptionalFields(id int, first, last string, isMarried bool, age int, rating float64, uid uuid.UUID, numEpisodes uint64) row.Row {
   192  	isMarriedVal := types.Int(0)
   193  	if isMarried {
   194  		isMarriedVal = types.Int(1)
   195  	}
   196  
   197  	vals := row.TaggedValues{
   198  		IdTag:          types.Int(id),
   199  		FirstNameTag:   types.String(first),
   200  		LastNameTag:    types.String(last),
   201  		IsMarriedTag:   isMarriedVal,
   202  		AgeTag:         types.Int(age),
   203  		RatingTag:      types.Float(rating),
   204  		UuidTag:        types.String(uid.String()),
   205  		NumEpisodesTag: types.Uint(numEpisodes),
   206  	}
   207  
   208  	r, err := row.New(types.Format_Default, PeopleTestSchema, vals)
   209  
   210  	if err != nil {
   211  		panic(err)
   212  	}
   213  
   214  	return r
   215  }
   216  
   217  // 6 characters
   218  var Homer = NewPeopleRow(HomerId, "Homer", "Simpson", true, 40, 8.5)
   219  var Marge = NewPeopleRowWithOptionalFields(MargeId, "Marge", "Simpson", true, 38, 8, uuid.MustParse("00000000-0000-0000-0000-000000000001"), 111)
   220  var Bart = NewPeopleRowWithOptionalFields(BartId, "Bart", "Simpson", false, 10, 9, uuid.MustParse("00000000-0000-0000-0000-000000000002"), 222)
   221  var Lisa = NewPeopleRowWithOptionalFields(LisaId, "Lisa", "Simpson", false, 8, 10, uuid.MustParse("00000000-0000-0000-0000-000000000003"), 333)
   222  var Moe = NewPeopleRowWithOptionalFields(MoeId, "Moe", "Szyslak", false, 48, 6.5, uuid.MustParse("00000000-0000-0000-0000-000000000004"), 444)
   223  var Barney = NewPeopleRowWithOptionalFields(BarneyId, "Barney", "Gumble", false, 40, 4, uuid.MustParse("00000000-0000-0000-0000-000000000005"), 555)
   224  var AllPeopleRows = Rs(Homer, Marge, Bart, Lisa, Moe, Barney)
   225  
   226  // Actually the first 4 episodes of the show
   227  var Ep1 = newEpsRow2(1, "Simpsons Roasting On an Open Fire", "1989-12-18 03:00:00", 8.0)
   228  var Ep2 = newEpsRow2(2, "Bart the Genius", "1990-01-15 03:00:00", 9.0)
   229  var Ep3 = newEpsRow2(3, "Homer's Odyssey", "1990-01-22 03:00:00", 7.0)
   230  var Ep4 = newEpsRow2(4, "There's No Disgrace Like Home", "1990-01-29 03:00:00", 8.5)
   231  var AllEpsRows = Rs(Ep1, Ep2, Ep3, Ep4)
   232  
   233  // These are made up, not the actual show data
   234  var app1 = newAppsRow2(HomerId, 1, "Homer is great in this one")
   235  var app2 = newAppsRow2(MargeId, 1, "Marge is here too")
   236  var app3 = newAppsRow2(HomerId, 2, "Homer is great in this one too")
   237  var app4 = newAppsRow2(BartId, 2, "This episode is named after Bart")
   238  var app5 = newAppsRow2(LisaId, 2, "Lisa is here too")
   239  var app6 = newAppsRow2(MoeId, 2, "I think there's a prank call scene")
   240  var app7 = newAppsRow2(HomerId, 3, "Homer is in every episode")
   241  var app8 = newAppsRow2(MargeId, 3, "Marge shows up a lot too")
   242  var app9 = newAppsRow2(LisaId, 3, "Lisa is the best Simpson")
   243  var app10 = newAppsRow2(BarneyId, 3, "I'm making this all up")
   244  
   245  // nobody in episode 4, that one was terrible
   246  // Unlike the other tables, you can't count on the order of these rows matching the insertion order.
   247  var AllAppsRows = Rs(app1, app2, app3, app4, app5, app6, app7, app8, app9, app10)
   248  
   249  // Convenience func to avoid the boilerplate of typing []row.Row{} all the time
   250  func Rs(rows ...row.Row) []row.Row {
   251  	if rows == nil {
   252  		return make([]row.Row, 0)
   253  	}
   254  	return rows
   255  }
   256  
   257  // Mutates the row given with pairs of {tag,value} given in the varargs param. Converts built-in types to noms types.
   258  func MutateRow(sch schema.Schema, r row.Row, tagsAndVals ...interface{}) row.Row {
   259  	if len(tagsAndVals)%2 != 0 {
   260  		panic("expected pairs of tags and values")
   261  	}
   262  
   263  	var mutated row.Row = r
   264  	var err error
   265  
   266  	for i := 0; i < len(tagsAndVals); i += 2 {
   267  		tag := tagsAndVals[i].(int)
   268  		val := tagsAndVals[i+1]
   269  		var nomsVal types.Value
   270  		if val != nil {
   271  			switch v := val.(type) {
   272  			case uint64:
   273  				nomsVal = types.Uint(v)
   274  			case int:
   275  				nomsVal = types.Int(v)
   276  			case int32:
   277  				nomsVal = types.Int(v)
   278  			case int64:
   279  				nomsVal = types.Int(v)
   280  			case float32:
   281  				nomsVal = types.Float(v)
   282  			case float64:
   283  				nomsVal = types.Float(v)
   284  			case string:
   285  				nomsVal = types.String(v)
   286  			case uuid.UUID:
   287  				nomsVal = types.String(v.String())
   288  			case bool:
   289  				nomsVal = types.Int(0)
   290  				if v {
   291  					nomsVal = types.Int(1)
   292  				}
   293  			case time.Time:
   294  				nomsVal = types.Timestamp(v)
   295  			default:
   296  				panic("Unhandled type " + reflect.TypeOf(val).String())
   297  			}
   298  		} else {
   299  			nomsVal = nil
   300  		}
   301  
   302  		mutated, err = mutated.SetColVal(uint64(tag), nomsVal, sch)
   303  		if err != nil {
   304  			panic(err.Error())
   305  		}
   306  	}
   307  
   308  	return mutated
   309  }
   310  
   311  func GetAllRows(root doltdb.RootValue, tableName string) ([]sql.Row, error) {
   312  	ctx := context.Background()
   313  	table, _, err := root.GetTable(ctx, doltdb.TableName{Name: tableName})
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  
   318  	rowIdx, err := table.GetRowData(ctx)
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  
   323  	sch, err := table.GetSchema(ctx)
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  
   328  	return SqlRowsFromDurableIndex(rowIdx, sch)
   329  }