github.com/RevenueMonster/sqlike@v1.0.6/examples/find.go (about)

     1  package examples
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"sort"
     7  	"strconv"
     8  	"testing"
     9  	"time"
    10  
    11  	"cloud.google.com/go/civil"
    12  	"github.com/RevenueMonster/sqlike/sql/expr"
    13  	"github.com/RevenueMonster/sqlike/sqlike"
    14  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    15  	"github.com/RevenueMonster/sqlike/sqlike/options"
    16  	"github.com/RevenueMonster/sqlike/types"
    17  	"github.com/google/uuid"
    18  	"github.com/stretchr/testify/require"
    19  	"golang.org/x/text/language"
    20  )
    21  
    22  // FindExamples :
    23  func FindExamples(ctx context.Context, t *testing.T, db *sqlike.Database) {
    24  	var (
    25  		// result sql.Result
    26  		result *sqlike.Result
    27  		ns     normalStruct
    28  		err    error
    29  	)
    30  
    31  	emoji := `๐Ÿค•`
    32  	long := `ใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐใฏ็ด ๆ™ดใ‚‰ใ—ใ„ๅŠ›ใงใ™ใ€‚
    33  	ใ‚„ใ‚‰ใชใ„ใฎใฏใ‚‚ใฃใŸใ„ใชใ„ใ€‚
    34  	ๆ‚ฉใ‚“ใงใ„ใ‚‹ใชใ‚‰ใ€Progateใงใ‚„ใฃใฆใฟใ‚ˆใ†ใ€‚
    35  	็„กๆ–™ใงๅง‹ใ‚ใ‚‰ใ‚Œใ‚‹ใ€ๅˆๅฟƒ่€…ๅ‘ใ‘ๅญฆ็ฟ’ใ‚ตใ‚คใƒˆใ€‚
    36  	`
    37  
    38  	uid, _ := uuid.Parse("e7977246-910a-11e9-844d-6c96cfd87a51")
    39  	ts, _ := time.Parse("2006-01-02 15:04:05", "2008-01-28 10:25:33")
    40  	b := []byte(`abcd1234`)
    41  	jsonRaw := json.RawMessage(`{"test":"hello world"}`)
    42  	lang := language.Japanese
    43  	langs := []language.Tag{
    44  		language.AmericanEnglish,
    45  		language.BrazilianPortuguese,
    46  		language.Malay,
    47  		language.ModernStandardArabic,
    48  		language.Korean,
    49  		language.Japanese,
    50  	}
    51  	virtualColumn := "virtual column"
    52  	numMap := map[string]int{
    53  		"one":    1,
    54  		"three":  3,
    55  		"eleven": 11,
    56  	}
    57  
    58  	table := db.Table("NormalStruct")
    59  
    60  	// insert record before find
    61  	{
    62  		now := time.Now()
    63  		ns = normalStruct{}
    64  		ns.ID = uid
    65  		ns.Emoji = emoji
    66  		ns.Byte = b
    67  		ns.LongStr = long
    68  		ns.TinyInt = -88
    69  		ns.SmallInt = -16829
    70  		ns.BigInt = -1298738901289381212
    71  		ns.Uint = 1683904243
    72  		ns.SmallUint = 188
    73  		ns.MediumUint = 121373123
    74  		ns.BigUint = 1298738901289381212
    75  		ns.Float32 = 10.6789
    76  		ns.Float64 = 19833.6789
    77  		ns.JSONRaw = jsonRaw
    78  		ns.Enum = Failed
    79  		ns.Map = make(map[string]int)
    80  		ns.Map["one"] = 1
    81  		ns.Map["three"] = 3
    82  		ns.Map["eleven"] = 11
    83  		ns.Struct.VirtualStr = virtualColumn
    84  		ns.Date = civil.DateOf(now)
    85  		ns.DateTime = ts
    86  		ns.Timestamp = ts
    87  		ns.Language = lang
    88  		ns.Languages = langs
    89  		ns.Set = append(ns.Set, "A", "A", "B")
    90  		ns.CreatedAt = now
    91  		ns.UpdatedAt = now
    92  
    93  		_, err = table.InsertOne(
    94  			ctx, &ns,
    95  		)
    96  		require.NoError(t, err)
    97  	}
    98  
    99  	// Find one record by primary key
   100  	{
   101  		ns = normalStruct{}
   102  		result := table.FindOne(
   103  			ctx,
   104  			actions.FindOne().
   105  				Where(
   106  					expr.Equal("$Key", uid),
   107  				),
   108  			options.FindOne().SetDebug(true),
   109  		)
   110  
   111  		err = result.Decode(&ns)
   112  		require.NoError(t, err)
   113  		require.Equal(t, uid, ns.ID)
   114  		require.Equal(t, emoji, ns.Emoji)
   115  		require.Equal(t, long, ns.LongStr)
   116  		require.Equal(t, ts, ns.Timestamp)
   117  		require.Equal(t, b, ns.Byte)
   118  		require.Equal(t, int8(-88), ns.TinyInt)
   119  		require.Equal(t, int16(-16829), ns.SmallInt)
   120  		require.Equal(t, int64(-1298738901289381212), ns.BigInt)
   121  		require.Equal(t, uint(1683904243), ns.Uint)
   122  		require.Equal(t, uint16(188), ns.SmallUint)
   123  		require.Equal(t, uint32(121373123), ns.MediumUint)
   124  		require.Equal(t, uint64(1298738901289381212), ns.BigUint)
   125  		require.Equal(t, float32(10.6789), ns.Float32)
   126  		require.Equal(t, float64(19833.6789), ns.Float64)
   127  		require.Equal(t, Enum("FAILED"), ns.Enum)
   128  		require.Equal(t, virtualColumn, ns.Struct.VirtualStr)
   129  
   130  		require.Nil(t, ns.Struct.NestedNullInt)
   131  		require.Nil(t, ns.Struct.Key)
   132  		require.Nil(t, ns.PtrUUID)
   133  		var nilKey *types.Key
   134  		require.Equal(t, nilKey, ns.Struct.Key)
   135  		require.True(t, ns.Struct.Key == nil)
   136  		require.True(t, ns.Struct.Key == nilKey)
   137  
   138  		require.Equal(t, numMap, ns.Map)
   139  		require.Equal(t, lang, ns.Language)
   140  		require.Equal(t, langs, ns.Languages)
   141  		require.ElementsMatch(t, types.Set{"A", "B"}, ns.Set)
   142  		require.Equal(t, json.RawMessage(`{"test":"hello world"}`), ns.JSONRaw)
   143  
   144  		columns := []string{
   145  			"$Key", "Key", "PtrUUID", "Date",
   146  			"SID", "Emoji", "FullText", "LongStr", "CustomStrType",
   147  			"EmptyByte", "Byte", "Bool",
   148  			"Int", "TinyInt", "SmallInt", "MediumInt", "BigInt",
   149  			"Uint", "TinyUint", "SmallUint", "MediumUint", "BigUint",
   150  			"Float32", "Float64", "UFloat32",
   151  			"EmptyStruct", "Struct", "VirtualColumn",
   152  			"Struct.StoredStr", "JSONRaw", "Map",
   153  			"DateTime", "Timestamp", "Location", "Language", "Languages",
   154  			"Currency", "Currencies",
   155  			"Enum", "Set",
   156  			"CreatedAt", "UpdatedAt",
   157  		}
   158  		cols := result.Columns()
   159  		sort.Strings(columns)
   160  		sort.Strings(cols)
   161  		require.True(t, len(cols) > 0)
   162  		require.ElementsMatch(t, columns, cols)
   163  	}
   164  
   165  	// Find one with scan
   166  	{
   167  		var i struct {
   168  			skip      string
   169  			count     uint
   170  			id        *string
   171  			emoji     string
   172  			customStr string
   173  			boolean   bool
   174  			jsonRaw   json.RawMessage
   175  			numMap    map[string]int
   176  		}
   177  		ns = normalStruct{}
   178  
   179  		/*
   180  			SELECT
   181  				COUNT(`$Key`) AS `c`
   182  			FROM `sqlike`.`NormalStruct`
   183  			WHERE
   184  				`$Key` = "e7977246-910a-11e9-844d-6c96cfd87a51"
   185  			LIMIT 1;
   186  		*/
   187  		// Scan with unmatched number of fields
   188  		err = table.FindOne(
   189  			ctx,
   190  			actions.FindOne().
   191  				Select(
   192  					expr.As(expr.Count("$Key"), "c"),
   193  				).
   194  				Where(
   195  					expr.Equal("$Key", uid),
   196  				),
   197  			options.FindOne().SetDebug(true),
   198  		).Scan(&i.count, i.skip, &i.id, &i.emoji)
   199  		require.NoError(t, err)
   200  		require.True(t, i.count > 0)
   201  
   202  		/*
   203  			SELECT
   204  				`$Key`,`Emoji`,`CustomStrType`,`Bool`,`JSONRaw`,`Map`,`Language`
   205  			FROM `sqlike`.`NormalStruct`
   206  			WHERE
   207  				`$Key` = "e7977246-910a-11e9-844d-6c96cfd87a51"
   208  			LIMIT 1;
   209  		*/
   210  		// Scan with fields
   211  		err = table.FindOne(
   212  			ctx,
   213  			actions.FindOne().
   214  				Select(
   215  					"$Key", "Emoji", "CustomStrType", "Bool",
   216  					"JSONRaw", "Map", "Language",
   217  				).
   218  				Where(
   219  					expr.Equal("$Key", uid),
   220  				),
   221  			options.FindOne().SetDebug(true),
   222  		).Scan(&i.id, &i.emoji, &i.customStr, &i.boolean, &i.jsonRaw, &i.numMap)
   223  		require.NoError(t, err)
   224  		require.NotNil(t, i.id)
   225  		require.Equal(t, uid.String(), *i.id)
   226  		require.Equal(t, emoji, i.emoji)
   227  		require.Equal(t, jsonRaw, i.jsonRaw)
   228  		require.Equal(t, numMap, i.numMap)
   229  
   230  		// Scan error
   231  		err = table.FindOne(
   232  			ctx,
   233  			actions.FindOne().
   234  				Select(
   235  					"$Key",
   236  				).
   237  				Where(
   238  					expr.Equal("$Key", uid),
   239  				),
   240  			options.FindOne().SetDebug(true),
   241  		).Scan(i.skip)
   242  		require.Error(t, err)
   243  	}
   244  
   245  	// Find one record by primary key
   246  	{
   247  		/*
   248  			SELECT * FROM `sqlike`.`NormalStruct`
   249  			WHERE
   250  				`$Key` = "1000"
   251  			LIMIT 1;
   252  		*/
   253  		ns = normalStruct{}
   254  		err = table.FindOne(
   255  			ctx,
   256  			actions.FindOne().
   257  				Where(
   258  					expr.Equal("$Key", "1000"),
   259  				),
   260  		).Decode(&ns)
   261  		require.Equal(t, err, sqlike.ErrNoRows)
   262  
   263  	}
   264  
   265  	// Find multiple records by where condition
   266  	{
   267  		/*
   268  			SELECT * FROM `sqlike`.`NormalStruct`
   269  			WHERE
   270  				(
   271  					`TinyInt` BETWEEN 1 AND 100 AND
   272  					`Enum` IN ("SUCCESS","FAILED","UNKNOWN")
   273  				)
   274  			LIMIT 100;
   275  		*/
   276  		ns = normalStruct{}
   277  		nss := []normalStruct{}
   278  		result, err = table.Find(
   279  			ctx,
   280  			actions.Find().
   281  				Where(
   282  					expr.Between("TinyInt", 1, 100),
   283  					expr.In("Enum", []Enum{
   284  						Success,
   285  						Failed,
   286  						Unknown,
   287  					}),
   288  				),
   289  			options.Find().SetDebug(true),
   290  		)
   291  		require.NoError(t, err)
   292  		err = result.All(&nss)
   293  		require.NoError(t, err)
   294  
   295  	}
   296  
   297  	// Find with scan slice
   298  	{
   299  		/*
   300  			SELECT `Emoji` FROM `sqlike`.`NormalStruct` LIMIT 100;
   301  		*/
   302  		ns = normalStruct{}
   303  		result, err = table.Find(
   304  			ctx,
   305  			actions.Find().Select("Emoji"),
   306  		)
   307  		require.NoError(t, err)
   308  		var emojis []string
   309  		err = result.ScanSlice(&emojis)
   310  		require.NoError(t, err)
   311  		require.ElementsMatch(t, []string{
   312  			`๐Ÿค•`,
   313  			`๐Ÿฅถ ๐Ÿ˜ฑ ๐Ÿ˜จ ๐Ÿ˜ฐ`,
   314  			`๐Ÿ˜€ ๐Ÿ˜ ๐Ÿ˜‚ ๐Ÿคฃ ๐Ÿ˜ƒ ๐Ÿ˜„ ๐Ÿ˜… ๐Ÿ˜† ๐Ÿ˜‰ ๐Ÿ˜Š`,
   315  			`๐Ÿ˜€ ๐Ÿ˜ ๐Ÿ˜‚ ๐Ÿคฃ ๐Ÿ˜ƒ ๐Ÿ˜„ ๐Ÿ˜… ๐Ÿ˜† ๐Ÿ˜‰ ๐Ÿ˜Š`,
   316  			`๐Ÿ˜€ ๐Ÿ˜ ๐Ÿ˜‚ ๐Ÿคฃ ๐Ÿ˜ƒ ๐Ÿ˜„ ๐Ÿ˜… ๐Ÿ˜† ๐Ÿ˜‰ ๐Ÿ˜Š`,
   317  			`๐Ÿค•`,
   318  		}, emojis)
   319  	}
   320  
   321  	// Find with subquery
   322  	{
   323  		/*
   324  			SELECT * FROM `sqlike`.`NormalStruct`
   325  			WHERE (
   326  				`$Key` IN (
   327  					SELECT `$Key` FROM `sqlike`.`NormalStruct`
   328  					WHERE `Tinyint` BETWEEN 1 AND 100
   329  					ORDER BY `Timestamp` DESC
   330  				) AND
   331  				EXISTS (SELECT 1 FROM `sqlike`.`NormalStruct`)
   332  			)
   333  			ORDER BY FIELD(`Enum`,"SUCCESS","FAILED","UNKNOWN")
   334  			LIMIT 100;
   335  		*/
   336  		ns = normalStruct{}
   337  		result, err = table.Find(
   338  			ctx,
   339  			actions.Find().
   340  				Where(
   341  					expr.In("$Key", actions.Find().
   342  						Select("$Key").
   343  						From("sqlike", "NormalStruct").
   344  						Where(
   345  							expr.Between("Tinyint", 1, 100),
   346  						).
   347  						OrderBy(
   348  							expr.Desc("Timestamp"),
   349  						),
   350  					),
   351  					expr.Exists(
   352  						actions.Find().
   353  							Select(expr.Raw("1")).
   354  							From("sqlike", "NormalStruct"),
   355  					),
   356  				).
   357  				OrderBy(
   358  					expr.Field("Enum", []Enum{
   359  						Success,
   360  						Failed,
   361  						Unknown,
   362  					}),
   363  				),
   364  			options.Find().SetDebug(true),
   365  		)
   366  		require.NoError(t, err)
   367  		nss := []normalStruct{}
   368  
   369  		err = result.All(&nss)
   370  		require.NoError(t, err)
   371  	}
   372  
   373  	// Query with Like expression
   374  	{
   375  		/*
   376  			SELECT * FROM `sqlike`.`NormalStruct`
   377  			WHERE `FullText` LIKE "Hal\\%o\\%()#$\\\\\\%^&\\_%"
   378  			LIMIT 1;
   379  		*/
   380  		symbol := "Hal%o%()#$\\%^&_"
   381  		ns = normalStruct{}
   382  		err = table.FindOne(
   383  			ctx,
   384  			actions.FindOne().
   385  				Where(
   386  					expr.Or(
   387  						expr.Like("FullText", symbol+"%"),
   388  						expr.Like("FullText", expr.Raw(strconv.Quote("%"+symbol+"%"))),
   389  					),
   390  				),
   391  			options.FindOne().SetDebug(true),
   392  		).Decode(&ns)
   393  		require.NoError(t, err)
   394  		require.Equal(t, symbol, ns.FullText)
   395  	}
   396  
   397  	// Aggregation
   398  	{
   399  		/*
   400  			SELECT
   401  				`Enum` AS `A`,
   402  				COUNT(`$Key`) AS `B`,
   403  				AVG(`MediumInt`),
   404  				COALESCE(SUM(`SmallInt`),0) AS `C`,
   405  				MAX(`BigInt`),
   406  				MIN(`BigInt`) AS `D`
   407  			FROM `sqlike`.`NormalStruct`
   408  			GROUP BY
   409  				`Enum`,
   410  				`$Key`
   411  			ORDER BY `$Key` DESC;
   412  		*/
   413  		ns = normalStruct{}
   414  		result, err = table.Find(
   415  			ctx,
   416  			actions.Find().
   417  				Select(
   418  					expr.As("Enum", "A"),
   419  					expr.As(expr.Count("$Key"), "B"),
   420  					expr.Average("MediumInt"),
   421  					expr.As(expr.Sum("SmallInt"), "C"),
   422  					expr.Max("BigInt"),
   423  					expr.As(expr.Min("BigInt"), "D"),
   424  				).
   425  				GroupBy(
   426  					"Enum",
   427  					"$Key",
   428  				).
   429  				OrderBy(
   430  					expr.Desc("$Key"),
   431  				),
   432  			options.Find().
   433  				SetDebug(true).
   434  				SetNoLimit(true),
   435  		)
   436  		require.NoError(t, err)
   437  		require.ElementsMatch(t,
   438  			[]string{
   439  				"A", "B", "AVG(`MediumInt`)",
   440  				"C", "MAX(`BigInt`)", "D",
   441  			}, result.Columns(),
   442  		)
   443  	}
   444  
   445  	{
   446  		table := db.Table("GeneratedStruct")
   447  
   448  		first := newGeneratedStruct()
   449  		cols := []*generatedStruct{
   450  			first,
   451  			newGeneratedStruct(),
   452  		}
   453  		_, err = table.Insert(
   454  			ctx,
   455  			&cols,
   456  			options.Insert().SetDebug(true),
   457  		)
   458  		require.NoError(t, err)
   459  		require.Empty(t, first.ID)
   460  
   461  		var result generatedStruct
   462  
   463  		err = table.FindOne(
   464  			ctx,
   465  			actions.FindOne().
   466  				Where(
   467  					expr.Equal("NestedID", first.Nested.ID),
   468  				),
   469  			options.FindOne().SetDebug(true),
   470  		).Decode(&result)
   471  		require.NoError(t, err)
   472  		require.Equal(t, first.Nested.ID, result.ID)
   473  		require.True(t, result.Amount > 0)
   474  	}
   475  
   476  }
   477  
   478  // FindErrorExamples :
   479  func FindErrorExamples(ctx context.Context, t *testing.T, db *sqlike.Database) {
   480  	var (
   481  		err error
   482  	)
   483  
   484  	{
   485  		_, err = db.Table("unknown_table").Find(
   486  			ctx,
   487  			nil,
   488  			options.Find().SetDebug(true),
   489  		)
   490  		require.Error(t, err)
   491  
   492  		err = db.Table("NormalStruct").FindOne(
   493  			ctx,
   494  			nil,
   495  			options.FindOne().SetDebug(true),
   496  		).Decode(nil)
   497  		require.Error(t, err)
   498  	}
   499  }