Add support for blob expressions.
This commit is contained in:
parent
26e478dc7e
commit
c94216ab0e
37 changed files with 1296 additions and 81 deletions
|
|
@ -180,11 +180,15 @@ func getSqlBuilderColumnType(columnMetaData metadata.Column) string {
|
||||||
return "Timez"
|
return "Timez"
|
||||||
case "interval":
|
case "interval":
|
||||||
return "Interval"
|
return "Interval"
|
||||||
case "user-defined", "enum", "text", "character", "character varying", "bytea", "uuid",
|
case "user-defined", "enum", "text", "character", "character varying", "uuid",
|
||||||
"tsvector", "bit", "bit varying", "money", "json", "jsonb", "xml", "point", "line", "ARRAY",
|
"tsvector", "bit", "bit varying", "money", "json", "jsonb", "xml", "point", "line", "ARRAY",
|
||||||
"char", "varchar", "nvarchar", "binary", "varbinary", "bpchar", "varbit",
|
"char", "varchar", "nvarchar", "bpchar", "varbit",
|
||||||
"tinyblob", "blob", "mediumblob", "longblob", "tinytext", "mediumtext", "longtext": // MySQL
|
"tinytext", "mediumtext", "longtext": // MySQL
|
||||||
return "String"
|
return "String"
|
||||||
|
case "bytea": // postgres
|
||||||
|
return "Bytea"
|
||||||
|
case "binary", "varbinary", "tinyblob", "mediumblob", "longblob", "blob": // mysql and sqlite
|
||||||
|
return "Blob"
|
||||||
case "real", "numeric", "decimal", "double precision", "float", "float4", "float8",
|
case "real", "numeric", "decimal", "double precision", "float", "float4", "float8",
|
||||||
"double": // MySQL
|
"double": // MySQL
|
||||||
return "Float"
|
return "Float"
|
||||||
|
|
|
||||||
103
internal/jet/blob_expression.go
Normal file
103
internal/jet/blob_expression.go
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
package jet
|
||||||
|
|
||||||
|
// BlobExpression interface
|
||||||
|
type BlobExpression interface {
|
||||||
|
Expression
|
||||||
|
|
||||||
|
isStringOrBlob()
|
||||||
|
|
||||||
|
EQ(rhs BlobExpression) BoolExpression
|
||||||
|
NOT_EQ(rhs BlobExpression) BoolExpression
|
||||||
|
IS_DISTINCT_FROM(rhs BlobExpression) BoolExpression
|
||||||
|
IS_NOT_DISTINCT_FROM(rhs BlobExpression) BoolExpression
|
||||||
|
|
||||||
|
LT(rhs BlobExpression) BoolExpression
|
||||||
|
LT_EQ(rhs BlobExpression) BoolExpression
|
||||||
|
GT(rhs BlobExpression) BoolExpression
|
||||||
|
GT_EQ(rhs BlobExpression) BoolExpression
|
||||||
|
BETWEEN(min, max BlobExpression) BoolExpression
|
||||||
|
NOT_BETWEEN(min, max BlobExpression) BoolExpression
|
||||||
|
|
||||||
|
CONCAT(rhs BlobExpression) BlobExpression
|
||||||
|
|
||||||
|
LIKE(pattern BlobExpression) BoolExpression
|
||||||
|
NOT_LIKE(pattern BlobExpression) BoolExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
type blobInterfaceImpl struct {
|
||||||
|
parent BlobExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) isStringOrBlob() {}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) EQ(rhs BlobExpression) BoolExpression {
|
||||||
|
return Eq(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) NOT_EQ(rhs BlobExpression) BoolExpression {
|
||||||
|
return NotEq(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) IS_DISTINCT_FROM(rhs BlobExpression) BoolExpression {
|
||||||
|
return IsDistinctFrom(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs BlobExpression) BoolExpression {
|
||||||
|
return IsNotDistinctFrom(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) GT(rhs BlobExpression) BoolExpression {
|
||||||
|
return Gt(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) GT_EQ(rhs BlobExpression) BoolExpression {
|
||||||
|
return GtEq(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) LT(rhs BlobExpression) BoolExpression {
|
||||||
|
return Lt(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) LT_EQ(rhs BlobExpression) BoolExpression {
|
||||||
|
return LtEq(s.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) BETWEEN(min, max BlobExpression) BoolExpression {
|
||||||
|
return NewBetweenOperatorExpression(s.parent, min, max, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) NOT_BETWEEN(min, max BlobExpression) BoolExpression {
|
||||||
|
return NewBetweenOperatorExpression(s.parent, min, max, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) CONCAT(rhs BlobExpression) BlobExpression {
|
||||||
|
return BlobExp(newBinaryStringOperatorExpression(s.parent, rhs, StringConcatOperator))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) LIKE(pattern BlobExpression) BoolExpression {
|
||||||
|
return newBinaryBoolOperatorExpression(s.parent, pattern, "LIKE")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobInterfaceImpl) NOT_LIKE(pattern BlobExpression) BoolExpression {
|
||||||
|
return newBinaryBoolOperatorExpression(s.parent, pattern, "NOT LIKE")
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------//
|
||||||
|
|
||||||
|
type blobExpressionWrapper struct {
|
||||||
|
blobInterfaceImpl
|
||||||
|
Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBlobExpressionWrap(expression Expression) BlobExpression {
|
||||||
|
blobExpressionWrap := blobExpressionWrapper{Expression: expression}
|
||||||
|
blobExpressionWrap.blobInterfaceImpl.parent = &blobExpressionWrap
|
||||||
|
return &blobExpressionWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlobExp is blob expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as blob expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
func BlobExp(expression Expression) BlobExpression {
|
||||||
|
return newBlobExpressionWrap(expression)
|
||||||
|
}
|
||||||
|
|
@ -122,7 +122,7 @@ func IntegerColumn(name string) ColumnInteger {
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
// ColumnString is interface for SQL text, character, character varying
|
// ColumnString is interface for SQL text, character, character varying
|
||||||
// bytea, uuid columns and enums types.
|
// uuid columns and enums types.
|
||||||
type ColumnString interface {
|
type ColumnString interface {
|
||||||
StringExpression
|
StringExpression
|
||||||
Column
|
Column
|
||||||
|
|
@ -163,6 +163,47 @@ func StringColumn(name string) ColumnString {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnBlob is interface for binary data types (bytea, binary, blob, etc...)
|
||||||
|
type ColumnBlob interface {
|
||||||
|
BlobExpression
|
||||||
|
Column
|
||||||
|
|
||||||
|
From(subQuery SelectTable) ColumnBlob
|
||||||
|
SET(blob BlobExpression) ColumnAssigment
|
||||||
|
}
|
||||||
|
|
||||||
|
type blobColumnImpl struct {
|
||||||
|
blobInterfaceImpl
|
||||||
|
|
||||||
|
ColumnExpressionImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *blobColumnImpl) From(subQuery SelectTable) ColumnBlob {
|
||||||
|
newBlobColumn := BlobColumn(i.name)
|
||||||
|
newBlobColumn.setTableName(i.tableName)
|
||||||
|
newBlobColumn.setSubQuery(subQuery)
|
||||||
|
|
||||||
|
return newBlobColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *blobColumnImpl) SET(blobExp BlobExpression) ColumnAssigment {
|
||||||
|
return columnAssigmentImpl{
|
||||||
|
column: i,
|
||||||
|
expression: blobExp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlobColumn creates named blob column.
|
||||||
|
func BlobColumn(name string) ColumnBlob {
|
||||||
|
blobColumn := &blobColumnImpl{}
|
||||||
|
blobColumn.blobInterfaceImpl.parent = blobColumn
|
||||||
|
blobColumn.ColumnExpressionImpl = NewColumnImpl(name, "", blobColumn)
|
||||||
|
|
||||||
|
return blobColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------//
|
||||||
|
|
||||||
// ColumnTime is interface for SQL time column.
|
// ColumnTime is interface for SQL time column.
|
||||||
type ColumnTime interface {
|
type ColumnTime interface {
|
||||||
TimeExpression
|
TimeExpression
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// Dialect interface
|
// Dialect interface
|
||||||
type Dialect interface {
|
type Dialect interface {
|
||||||
|
|
@ -11,6 +13,7 @@ type Dialect interface {
|
||||||
AliasQuoteChar() byte
|
AliasQuoteChar() byte
|
||||||
IdentifierQuoteChar() byte
|
IdentifierQuoteChar() byte
|
||||||
ArgumentPlaceholder() QueryPlaceholderFunc
|
ArgumentPlaceholder() QueryPlaceholderFunc
|
||||||
|
ArgumentToString(value any) (string, bool)
|
||||||
IsReservedWord(name string) bool
|
IsReservedWord(name string) bool
|
||||||
SerializeOrderBy() func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
SerializeOrderBy() func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||||
ValuesDefaultColumnName(index int) string
|
ValuesDefaultColumnName(index int) string
|
||||||
|
|
@ -34,6 +37,7 @@ type DialectParams struct {
|
||||||
AliasQuoteChar byte
|
AliasQuoteChar byte
|
||||||
IdentifierQuoteChar byte
|
IdentifierQuoteChar byte
|
||||||
ArgumentPlaceholder QueryPlaceholderFunc
|
ArgumentPlaceholder QueryPlaceholderFunc
|
||||||
|
ArgumentToString func(value any) (string, bool)
|
||||||
ReservedWords []string
|
ReservedWords []string
|
||||||
SerializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
SerializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||||
ValuesDefaultColumnName func(index int) string
|
ValuesDefaultColumnName func(index int) string
|
||||||
|
|
@ -49,6 +53,7 @@ func NewDialect(params DialectParams) Dialect {
|
||||||
aliasQuoteChar: params.AliasQuoteChar,
|
aliasQuoteChar: params.AliasQuoteChar,
|
||||||
identifierQuoteChar: params.IdentifierQuoteChar,
|
identifierQuoteChar: params.IdentifierQuoteChar,
|
||||||
argumentPlaceholder: params.ArgumentPlaceholder,
|
argumentPlaceholder: params.ArgumentPlaceholder,
|
||||||
|
argumentToString: params.ArgumentToString,
|
||||||
reservedWords: arrayOfStringsToMapOfStrings(params.ReservedWords),
|
reservedWords: arrayOfStringsToMapOfStrings(params.ReservedWords),
|
||||||
serializeOrderBy: params.SerializeOrderBy,
|
serializeOrderBy: params.SerializeOrderBy,
|
||||||
valuesDefaultColumnName: params.ValuesDefaultColumnName,
|
valuesDefaultColumnName: params.ValuesDefaultColumnName,
|
||||||
|
|
@ -63,6 +68,7 @@ type dialectImpl struct {
|
||||||
aliasQuoteChar byte
|
aliasQuoteChar byte
|
||||||
identifierQuoteChar byte
|
identifierQuoteChar byte
|
||||||
argumentPlaceholder QueryPlaceholderFunc
|
argumentPlaceholder QueryPlaceholderFunc
|
||||||
|
argumentToString func(value any) (string, bool)
|
||||||
reservedWords map[string]bool
|
reservedWords map[string]bool
|
||||||
serializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
serializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||||
valuesDefaultColumnName func(index int) string
|
valuesDefaultColumnName func(index int) string
|
||||||
|
|
@ -102,6 +108,10 @@ func (d *dialectImpl) ArgumentPlaceholder() QueryPlaceholderFunc {
|
||||||
return d.argumentPlaceholder
|
return d.argumentPlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dialectImpl) ArgumentToString(value any) (string, bool) {
|
||||||
|
return d.argumentToString(value)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dialectImpl) IsReservedWord(name string) bool {
|
func (d *dialectImpl) IsReservedWord(name string) bool {
|
||||||
_, isReservedWord := d.reservedWords[strings.ToLower(name)]
|
_, isReservedWord := d.reservedWords[strings.ToLower(name)]
|
||||||
return isReservedWord
|
return isReservedWord
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ func newExpressionListOperator(operator string, expressions ...Expression) *expr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBoolExpressionListOperator(operator string, expressions ...BoolExpression) BoolExpression {
|
func newBoolExpressionListOperator(operator string, expressions ...BoolExpression) BoolExpression {
|
||||||
return BoolExp(newExpressionListOperator(operator, BoolExpressionListToExpressionList(expressions)...))
|
return BoolExp(newExpressionListOperator(operator, ToExpressionList(expressions)...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (elo *expressionListOperator) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
func (elo *expressionListOperator) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||||
|
|
|
||||||
|
|
@ -255,18 +255,30 @@ func leadLagImpl(name string, expr Expression, offsetAndDefault ...interface{})
|
||||||
|
|
||||||
//------------ String functions ------------------//
|
//------------ String functions ------------------//
|
||||||
|
|
||||||
|
// HEX function takes an input and returns its equivalent hexadecimal representation
|
||||||
|
func HEX(expression Expression) StringExpression {
|
||||||
|
return StringExp(Func("HEX", expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNHEX for a string argument str, UNHEX(str) interprets each pair of characters in the argument
|
||||||
|
// as a hexadecimal number and converts it to the byte represented by the number.
|
||||||
|
// The return value is a binary string.
|
||||||
|
func UNHEX(expression StringExpression) BlobExpression {
|
||||||
|
return BlobExp(Func("UNHEX", expression))
|
||||||
|
}
|
||||||
|
|
||||||
// BIT_LENGTH returns number of bits in string expression
|
// BIT_LENGTH returns number of bits in string expression
|
||||||
func BIT_LENGTH(stringExpression StringExpression) IntegerExpression {
|
func BIT_LENGTH(stringExpression StringOrBlobExpression) IntegerExpression {
|
||||||
return newIntegerFunc("BIT_LENGTH", stringExpression)
|
return newIntegerFunc("BIT_LENGTH", stringExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHAR_LENGTH returns number of characters in string expression
|
// CHAR_LENGTH returns number of characters in string expression
|
||||||
func CHAR_LENGTH(stringExpression StringExpression) IntegerExpression {
|
func CHAR_LENGTH(stringExpression StringOrBlobExpression) IntegerExpression {
|
||||||
return newIntegerFunc("CHAR_LENGTH", stringExpression)
|
return newIntegerFunc("CHAR_LENGTH", stringExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OCTET_LENGTH returns number of bytes in string expression
|
// OCTET_LENGTH returns number of bytes in string expression
|
||||||
func OCTET_LENGTH(stringExpression StringExpression) IntegerExpression {
|
func OCTET_LENGTH(stringExpression StringOrBlobExpression) IntegerExpression {
|
||||||
return newIntegerFunc("OCTET_LENGTH", stringExpression)
|
return newIntegerFunc("OCTET_LENGTH", stringExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,7 +294,7 @@ func UPPER(stringExpression StringExpression) StringExpression {
|
||||||
|
|
||||||
// BTRIM removes the longest string consisting only of characters
|
// BTRIM removes the longest string consisting only of characters
|
||||||
// in characters (a space by default) from the start and end of string
|
// in characters (a space by default) from the start and end of string
|
||||||
func BTRIM(stringExpression StringExpression, trimChars ...StringExpression) StringExpression {
|
func BTRIM(stringExpression StringOrBlobExpression, trimChars ...StringOrBlobExpression) StringExpression {
|
||||||
if len(trimChars) > 0 {
|
if len(trimChars) > 0 {
|
||||||
return NewStringFunc("BTRIM", stringExpression, trimChars[0])
|
return NewStringFunc("BTRIM", stringExpression, trimChars[0])
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +303,7 @@ func BTRIM(stringExpression StringExpression, trimChars ...StringExpression) Str
|
||||||
|
|
||||||
// LTRIM removes the longest string containing only characters
|
// LTRIM removes the longest string containing only characters
|
||||||
// from characters (a space by default) from the start of string
|
// from characters (a space by default) from the start of string
|
||||||
func LTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
func LTRIM(str StringOrBlobExpression, trimChars ...StringOrBlobExpression) StringExpression {
|
||||||
if len(trimChars) > 0 {
|
if len(trimChars) > 0 {
|
||||||
return NewStringFunc("LTRIM", str, trimChars[0])
|
return NewStringFunc("LTRIM", str, trimChars[0])
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +312,7 @@ func LTRIM(str StringExpression, trimChars ...StringExpression) StringExpression
|
||||||
|
|
||||||
// RTRIM removes the longest string containing only characters
|
// RTRIM removes the longest string containing only characters
|
||||||
// from characters (a space by default) from the end of string
|
// from characters (a space by default) from the end of string
|
||||||
func RTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
func RTRIM(str StringOrBlobExpression, trimChars ...StringOrBlobExpression) StringExpression {
|
||||||
if len(trimChars) > 0 {
|
if len(trimChars) > 0 {
|
||||||
return NewStringFunc("RTRIM", str, trimChars[0])
|
return NewStringFunc("RTRIM", str, trimChars[0])
|
||||||
}
|
}
|
||||||
|
|
@ -324,32 +336,32 @@ func CONCAT_WS(separator Expression, expressions ...Expression) StringExpression
|
||||||
|
|
||||||
// CONVERT converts string to dest_encoding. The original encoding is
|
// CONVERT converts string to dest_encoding. The original encoding is
|
||||||
// specified by src_encoding. The string must be valid in this encoding.
|
// specified by src_encoding. The string must be valid in this encoding.
|
||||||
func CONVERT(str StringExpression, srcEncoding StringExpression, destEncoding StringExpression) StringExpression {
|
func CONVERT(str BlobExpression, srcEncoding StringExpression, destEncoding StringExpression) BlobExpression {
|
||||||
return NewStringFunc("CONVERT", str, srcEncoding, destEncoding)
|
return BlobExp(Func("CONVERT", str, srcEncoding, destEncoding))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONVERT_FROM converts string to the database encoding. The original
|
// CONVERT_FROM converts string to the database encoding. The original
|
||||||
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
||||||
func CONVERT_FROM(str StringExpression, srcEncoding StringExpression) StringExpression {
|
func CONVERT_FROM(str BlobExpression, srcEncoding StringExpression) StringExpression {
|
||||||
return NewStringFunc("CONVERT_FROM", str, srcEncoding)
|
return NewStringFunc("CONVERT_FROM", str, srcEncoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONVERT_TO converts string to dest_encoding.
|
// CONVERT_TO converts string to dest_encoding.
|
||||||
func CONVERT_TO(str StringExpression, toEncoding StringExpression) StringExpression {
|
func CONVERT_TO(str StringExpression, toEncoding StringExpression) BlobExpression {
|
||||||
return NewStringFunc("CONVERT_TO", str, toEncoding)
|
return BlobExp(Func("CONVERT_TO", str, toEncoding))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ENCODE encodes binary data into a textual representation.
|
// ENCODE encodes binary data into a textual representation.
|
||||||
// Supported formats are: base64, hex, escape. escape converts zero bytes and
|
// Supported formats are: base64, hex, escape. escape converts zero bytes and
|
||||||
// high-bit-set bytes to octal sequences (\nnn) and doubles backslashes.
|
// high-bit-set bytes to octal sequences (\nnn) and doubles backslashes.
|
||||||
func ENCODE(data StringExpression, format StringExpression) StringExpression {
|
func ENCODE(data BlobExpression, format StringExpression) StringExpression {
|
||||||
return NewStringFunc("ENCODE", data, format)
|
return StringExp(Func("ENCODE", data, format))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DECODE decodes binary data from textual representation in string.
|
// DECODE decodes binary data from textual representation in string.
|
||||||
// Options for format are same as in encode.
|
// Options for format are same as in encode.
|
||||||
func DECODE(data StringExpression, format StringExpression) StringExpression {
|
func DECODE(data StringExpression, format StringExpression) BlobExpression {
|
||||||
return NewStringFunc("DECODE", data, format)
|
return BlobExp(Func("DECODE", data, format))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
||||||
|
|
@ -379,11 +391,11 @@ func RIGHT(str StringExpression, n IntegerExpression) StringExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LENGTH returns number of characters in string with a given encoding
|
// LENGTH returns number of characters in string with a given encoding
|
||||||
func LENGTH(str StringExpression, encoding ...StringExpression) StringExpression {
|
func LENGTH(str StringOrBlobExpression, encoding ...StringExpression) IntegerExpression {
|
||||||
if len(encoding) > 0 {
|
if len(encoding) > 0 {
|
||||||
return NewStringFunc("LENGTH", str, encoding[0])
|
return IntExp(Func("LENGTH", str, encoding[0]))
|
||||||
}
|
}
|
||||||
return NewStringFunc("LENGTH", str)
|
return IntExp(Func("LENGTH", str))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LPAD fills up the string to length length by prepending the characters
|
// LPAD fills up the string to length length by prepending the characters
|
||||||
|
|
@ -407,8 +419,13 @@ func RPAD(str StringExpression, length IntegerExpression, text ...StringExpressi
|
||||||
return NewStringFunc("RPAD", str, length)
|
return NewStringFunc("RPAD", str, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BIT_COUNT returns the number of bits set in the binary string (also known as “popcount”).
|
||||||
|
func BIT_COUNT(bytes BlobExpression) IntegerExpression {
|
||||||
|
return IntExp(Func("BIT_COUNT", bytes))
|
||||||
|
}
|
||||||
|
|
||||||
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
||||||
func MD5(stringExpression StringExpression) StringExpression {
|
func MD5(stringExpression StringOrBlobExpression) StringExpression {
|
||||||
return NewStringFunc("MD5", stringExpression)
|
return NewStringFunc("MD5", stringExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,7 +451,7 @@ func STRPOS(str, substring StringExpression) IntegerExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUBSTR extracts substring
|
// SUBSTR extracts substring
|
||||||
func SUBSTR(str StringExpression, from IntegerExpression, count ...IntegerExpression) StringExpression {
|
func SUBSTR(str StringOrBlobExpression, from IntegerExpression, count ...IntegerExpression) StringExpression {
|
||||||
if len(count) > 0 {
|
if len(count) > 0 {
|
||||||
return NewStringFunc("SUBSTR", str, from, count[0])
|
return NewStringFunc("SUBSTR", str, from, count[0])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -468,6 +468,11 @@ func RawDate(raw string, namedArgs ...map[string]interface{}) DateExpression {
|
||||||
return DateExp(Raw(raw, namedArgs...))
|
return DateExp(Raw(raw, namedArgs...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RawBlob is raw query helper that for blob expressions
|
||||||
|
func RawBlob(raw string, namedArgs ...map[string]interface{}) BlobExpression {
|
||||||
|
return BlobExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
// RawRange helper that for range expressions
|
// RawRange helper that for range expressions
|
||||||
func RawRange[T Expression](raw string, namedArgs ...map[string]interface{}) Range[T] {
|
func RawRange[T Expression](raw string, namedArgs ...map[string]interface{}) Range[T] {
|
||||||
return RangeExp[T](Raw(raw, namedArgs...))
|
return RangeExp[T](Raw(raw, namedArgs...))
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ func (s *SQLBuilder) finalize() (string, []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLBuilder) insertConstantArgument(arg interface{}) {
|
func (s *SQLBuilder) insertConstantArgument(arg interface{}) {
|
||||||
s.WriteString(argToString(arg))
|
s.WriteString(s.argToString(arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) {
|
func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) {
|
||||||
|
|
@ -200,7 +200,7 @@ func (s *SQLBuilder) insertRawQuery(raw string, namedArg map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Debug {
|
if s.Debug {
|
||||||
placeholder = argToString(namedArgumentPos.Value)
|
placeholder = s.argToString(namedArgumentPos.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
raw = strings.Replace(raw, namedArgumentPos.Name, placeholder, toReplace)
|
raw = strings.Replace(raw, namedArgumentPos.Name, placeholder, toReplace)
|
||||||
|
|
@ -209,11 +209,17 @@ func (s *SQLBuilder) insertRawQuery(raw string, namedArg map[string]interface{})
|
||||||
s.WriteString(raw)
|
s.WriteString(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func argToString(value interface{}) string {
|
func (s *SQLBuilder) argToString(value interface{}) string {
|
||||||
if is.Nil(value) {
|
if is.Nil(value) {
|
||||||
return "NULL"
|
return "NULL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strVal, ok := s.Dialect.ArgumentToString(value)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return strVal
|
||||||
|
}
|
||||||
|
|
||||||
switch bindVal := value.(type) {
|
switch bindVal := value.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
if bindVal {
|
if bindVal {
|
||||||
|
|
@ -250,7 +256,7 @@ func argToString(value interface{}) string {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
return argToString(val)
|
return s.argToString(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(fmt.Sprintf("jet: %s type can not be used as SQL query parameter", reflect.TypeOf(value).String()))
|
panic(fmt.Sprintf("jet: %s type can not be used as SQL query parameter", reflect.TypeOf(value).String()))
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package jet
|
||||||
// StringExpression interface
|
// StringExpression interface
|
||||||
type StringExpression interface {
|
type StringExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
isStringOrBlob()
|
||||||
|
|
||||||
EQ(rhs StringExpression) BoolExpression
|
EQ(rhs StringExpression) BoolExpression
|
||||||
NOT_EQ(rhs StringExpression) BoolExpression
|
NOT_EQ(rhs StringExpression) BoolExpression
|
||||||
|
|
@ -29,6 +30,8 @@ type stringInterfaceImpl struct {
|
||||||
parent StringExpression
|
parent StringExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stringInterfaceImpl) isStringOrBlob() {}
|
||||||
|
|
||||||
func (s *stringInterfaceImpl) EQ(rhs StringExpression) BoolExpression {
|
func (s *stringInterfaceImpl) EQ(rhs StringExpression) BoolExpression {
|
||||||
return Eq(s.parent, rhs)
|
return Eq(s.parent, rhs)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
internal/jet/string_or_blob_expression.go
Normal file
8
internal/jet/string_or_blob_expression.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package jet
|
||||||
|
|
||||||
|
// StringOrBlobExpression is common interface for all string and blob expressions
|
||||||
|
type StringOrBlobExpression interface {
|
||||||
|
Expression
|
||||||
|
|
||||||
|
isStringOrBlob()
|
||||||
|
}
|
||||||
|
|
@ -132,8 +132,8 @@ func ExpressionListToSerializerList(expressions []Expression) []Serializer {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoolExpressionListToExpressionList converts list of bool expressions to list of expressions
|
// ToExpressionList converts list of any expressions to list of expressions
|
||||||
func BoolExpressionListToExpressionList(expressions []BoolExpression) []Expression {
|
func ToExpressionList[T Expression](expressions []T) []Expression {
|
||||||
var ret []Expression
|
var ret []Expression
|
||||||
|
|
||||||
for _, expression := range expressions {
|
for _, expression := range expressions {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package is
|
package is
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
// Nil check if v is nil
|
// Nil check if v is nil
|
||||||
func Nil(v interface{}) bool {
|
func Nil(v interface{}) bool {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,6 @@ func (c *cast) AS_TIME() TimeExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_BINARY casts expression as BINARY type
|
// AS_BINARY casts expression as BINARY type
|
||||||
func (c *cast) AS_BINARY() StringExpression {
|
func (c *cast) AS_BINARY() BlobExpression {
|
||||||
return StringExp(c.AS("BINARY"))
|
return BlobExp(c.AS("BINARY"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ type ColumnString = jet.ColumnString
|
||||||
// StringColumn creates named string column.
|
// StringColumn creates named string column.
|
||||||
var StringColumn = jet.StringColumn
|
var StringColumn = jet.StringColumn
|
||||||
|
|
||||||
|
// ColumnBlob is interface for blob columns.
|
||||||
|
type ColumnBlob = jet.ColumnBlob
|
||||||
|
|
||||||
|
// BlobColumn creates named blob column.
|
||||||
|
var BlobColumn = jet.BlobColumn
|
||||||
|
|
||||||
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
||||||
type ColumnInteger = jet.ColumnInteger
|
type ColumnInteger = jet.ColumnInteger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mysql
|
package mysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-jet/jet/v2/internal/jet"
|
"github.com/go-jet/jet/v2/internal/jet"
|
||||||
)
|
)
|
||||||
|
|
@ -27,6 +28,7 @@ func newDialect() jet.Dialect {
|
||||||
ArgumentPlaceholder: func(int) string {
|
ArgumentPlaceholder: func(int) string {
|
||||||
return "?"
|
return "?"
|
||||||
},
|
},
|
||||||
|
ArgumentToString: argumentToString,
|
||||||
ReservedWords: reservedWords,
|
ReservedWords: reservedWords,
|
||||||
SerializeOrderBy: serializeOrderBy,
|
SerializeOrderBy: serializeOrderBy,
|
||||||
ValuesDefaultColumnName: func(index int) string {
|
ValuesDefaultColumnName: func(index int) string {
|
||||||
|
|
@ -37,6 +39,15 @@ func newDialect() jet.Dialect {
|
||||||
return jet.NewDialect(mySQLDialectParams)
|
return jet.NewDialect(mySQLDialectParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func argumentToString(value any) (string, bool) {
|
||||||
|
switch bindVal := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return fmt.Sprintf("X'%s'", hex.EncodeToString(bindVal)), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
func mysqlBitXor(expressions ...jet.Serializer) jet.SerializerFunc {
|
func mysqlBitXor(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||||
if len(expressions) < 2 {
|
if len(expressions) < 2 {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ type BoolExpression = jet.BoolExpression
|
||||||
// StringExpression interface
|
// StringExpression interface
|
||||||
type StringExpression = jet.StringExpression
|
type StringExpression = jet.StringExpression
|
||||||
|
|
||||||
|
// BlobExpression interface
|
||||||
|
type BlobExpression = jet.BlobExpression
|
||||||
|
|
||||||
// IntegerExpression interface
|
// IntegerExpression interface
|
||||||
type IntegerExpression = jet.IntegerExpression
|
type IntegerExpression = jet.IntegerExpression
|
||||||
|
|
||||||
|
|
@ -43,6 +46,11 @@ var BoolExp = jet.BoolExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var StringExp = jet.StringExp
|
var StringExp = jet.StringExp
|
||||||
|
|
||||||
|
// BlobExp is blob expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as blob expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
var BlobExp = jet.BlobExp
|
||||||
|
|
||||||
// IntExp is int expression wrapper around arbitrary expression.
|
// IntExp is int expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as int expression.
|
// Allows go compiler to see any expression as int expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
@ -100,6 +108,7 @@ var (
|
||||||
RawTime = jet.RawTime
|
RawTime = jet.RawTime
|
||||||
RawTimestamp = jet.RawTimestamp
|
RawTimestamp = jet.RawTimestamp
|
||||||
RawDate = jet.RawDate
|
RawDate = jet.RawDate
|
||||||
|
RawBlob = jet.RawBlob
|
||||||
)
|
)
|
||||||
|
|
||||||
// Func can be used to call custom or unsupported database functions.
|
// Func can be used to call custom or unsupported database functions.
|
||||||
|
|
|
||||||
|
|
@ -149,9 +149,12 @@ var NTH_VALUE = jet.NTH_VALUE
|
||||||
//--------------------- String functions ------------------//
|
//--------------------- String functions ------------------//
|
||||||
|
|
||||||
// HEX function in MySQL takes an input and returns its equivalent hexadecimal representation
|
// HEX function in MySQL takes an input and returns its equivalent hexadecimal representation
|
||||||
func HEX(expression Expression) StringExpression {
|
var HEX = jet.HEX
|
||||||
return StringExp(Func("HEX", expression))
|
|
||||||
}
|
// UNHEX for a string argument str, UNHEX(str) interprets each pair of characters in the argument
|
||||||
|
// as a hexadecimal number and converts it to the byte represented by the number.
|
||||||
|
// The return value is a binary string.
|
||||||
|
var UNHEX = jet.UNHEX
|
||||||
|
|
||||||
// BIT_LENGTH returns number of bits in string expression
|
// BIT_LENGTH returns number of bits in string expression
|
||||||
var BIT_LENGTH = jet.BIT_LENGTH
|
var BIT_LENGTH = jet.BIT_LENGTH
|
||||||
|
|
@ -162,6 +165,23 @@ var CHAR_LENGTH = jet.CHAR_LENGTH
|
||||||
// OCTET_LENGTH returns number of bytes in string expression
|
// OCTET_LENGTH returns number of bytes in string expression
|
||||||
var OCTET_LENGTH = jet.OCTET_LENGTH
|
var OCTET_LENGTH = jet.OCTET_LENGTH
|
||||||
|
|
||||||
|
// ELT returns the Nth element of the list of strings: str1 if N = 1, str2 if N = 2, and so on.
|
||||||
|
// Returns NULL if N is less than 1, greater than the number of arguments, or NULL.
|
||||||
|
func ELT(n IntegerExpression, list ...StringExpression) StringExpression {
|
||||||
|
args := []Expression{n}
|
||||||
|
args = append(args, jet.ToExpressionList(list)...)
|
||||||
|
|
||||||
|
return StringExp(Func("ELT", args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIELD returns the index (position) of str in the str1, str2, str3, ... list. Returns 0 if str is not found.
|
||||||
|
func FIELD(str StringExpression, list ...StringExpression) StringExpression {
|
||||||
|
args := []Expression{str}
|
||||||
|
args = append(args, jet.ToExpressionList(list)...)
|
||||||
|
|
||||||
|
return StringExp(Func("FIELD", args...))
|
||||||
|
}
|
||||||
|
|
||||||
// LOWER returns string expression in lower case
|
// LOWER returns string expression in lower case
|
||||||
var LOWER = jet.LOWER
|
var LOWER = jet.LOWER
|
||||||
|
|
||||||
|
|
@ -183,7 +203,35 @@ var CONCAT = jet.CONCAT
|
||||||
var CONCAT_WS = jet.CONCAT_WS
|
var CONCAT_WS = jet.CONCAT_WS
|
||||||
|
|
||||||
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
||||||
var FORMAT = jet.FORMAT
|
func FORMAT(number jet.NumericExpression, decimals IntegerExpression, optionalLocale ...StringExpression) StringExpression {
|
||||||
|
if len(optionalLocale) > 0 {
|
||||||
|
return StringExp(Func("FORMAT", number, decimals, optionalLocale[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringExp(Func("FORMAT", number, decimals))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_BASE64 converts the string argument to base-64 encoded form and returns the
|
||||||
|
// result as a character string with the connection character set and collation.
|
||||||
|
func TO_BASE64(data jet.StringOrBlobExpression) StringExpression {
|
||||||
|
return StringExp(Func("TO_BASE64", data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FROM_BASE64 takes a string encoded with the base-64 encoded rules used by TO_BASE64()
|
||||||
|
// and returns the decoded result as a binary string.
|
||||||
|
func FROM_BASE64(data StringExpression) BlobExpression {
|
||||||
|
return BlobExp(Func("FROM_BASE64", data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHARSET returns the character set of the string argument, or NULL if the argument is NULL.
|
||||||
|
func CHARSET(exp Expression) StringExpression {
|
||||||
|
return StringExp(Func("CHARSET", exp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// COLLATION returns the collation of the string argument.
|
||||||
|
func COLLATION(exp Expression) StringExpression {
|
||||||
|
return StringExp(Func("COLLATION ", exp))
|
||||||
|
}
|
||||||
|
|
||||||
// LEFT returns first n characters in the string.
|
// LEFT returns first n characters in the string.
|
||||||
// When n is negative, return all but last |n| characters.
|
// When n is negative, return all but last |n| characters.
|
||||||
|
|
@ -194,7 +242,7 @@ var LEFT = jet.LEFT
|
||||||
var RIGHT = jet.RIGHT
|
var RIGHT = jet.RIGHT
|
||||||
|
|
||||||
// LENGTH returns number of characters in string with a given encoding
|
// LENGTH returns number of characters in string with a given encoding
|
||||||
func LENGTH(str jet.StringExpression) jet.StringExpression {
|
func LENGTH(str jet.StringOrBlobExpression) jet.IntegerExpression {
|
||||||
return jet.LENGTH(str)
|
return jet.LENGTH(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,11 @@ var String = jet.String
|
||||||
// value can be any uuid type with a String method
|
// value can be any uuid type with a String method
|
||||||
var UUID = jet.UUID
|
var UUID = jet.UUID
|
||||||
|
|
||||||
|
// Blob creates new blob literal expression
|
||||||
|
func Blob(data []byte) BlobExpression {
|
||||||
|
return BlobExp(jet.Literal(data))
|
||||||
|
}
|
||||||
|
|
||||||
// Date creates new date literal
|
// Date creates new date literal
|
||||||
func Date(year int, month time.Month, day int) DateExpression {
|
func Date(year int, month time.Month, day int) DateExpression {
|
||||||
return CAST(jet.Date(year, month, day)).AS_DATE()
|
return CAST(jet.Date(year, month, day)).AS_DATE()
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,9 @@ func (b *cast) AS_DECIMAL() FloatExpression {
|
||||||
return FloatExp(b.AS("decimal"))
|
return FloatExp(b.AS("decimal"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_BYTEA casts expression AS text type
|
// AS_BYTEA casts expression AS bytea type
|
||||||
func (b *cast) AS_BYTEA() StringExpression {
|
func (b *cast) AS_BYTEA() ByteaExpression {
|
||||||
return StringExp(b.AS("bytea"))
|
return ByteaExp(b.AS("bytea"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_TIME casts expression AS date type
|
// AS_TIME casts expression AS date type
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ type ColumnString = jet.ColumnString
|
||||||
// StringColumn creates named string column.
|
// StringColumn creates named string column.
|
||||||
var StringColumn = jet.StringColumn
|
var StringColumn = jet.StringColumn
|
||||||
|
|
||||||
|
// ColumnBytea is interface for bytea columns
|
||||||
|
type ColumnBytea = jet.ColumnBlob
|
||||||
|
|
||||||
|
// ByteaColumn creates new named bytea column.
|
||||||
|
var ByteaColumn = jet.BlobColumn
|
||||||
|
|
||||||
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
||||||
type ColumnInteger = jet.ColumnInteger
|
type ColumnInteger = jet.ColumnInteger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
|
@ -26,6 +27,7 @@ func newDialect() jet.Dialect {
|
||||||
ArgumentPlaceholder: func(ord int) string {
|
ArgumentPlaceholder: func(ord int) string {
|
||||||
return "$" + strconv.Itoa(ord)
|
return "$" + strconv.Itoa(ord)
|
||||||
},
|
},
|
||||||
|
ArgumentToString: argumentToString,
|
||||||
ReservedWords: reservedWords,
|
ReservedWords: reservedWords,
|
||||||
ValuesDefaultColumnName: func(index int) string {
|
ValuesDefaultColumnName: func(index int) string {
|
||||||
return fmt.Sprintf("column%d", index+1)
|
return fmt.Sprintf("column%d", index+1)
|
||||||
|
|
@ -35,6 +37,15 @@ func newDialect() jet.Dialect {
|
||||||
return jet.NewDialect(dialectParams)
|
return jet.NewDialect(dialectParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func argumentToString(value any) (string, bool) {
|
||||||
|
switch bindVal := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return fmt.Sprintf("'\\x%s'", hex.EncodeToString(bindVal)), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
func postgresCAST(expressions ...jet.Serializer) jet.SerializerFunc {
|
func postgresCAST(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||||
if len(expressions) < 2 {
|
if len(expressions) < 2 {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ type BoolExpression = jet.BoolExpression
|
||||||
// StringExpression interface
|
// StringExpression interface
|
||||||
type StringExpression = jet.StringExpression
|
type StringExpression = jet.StringExpression
|
||||||
|
|
||||||
|
type ByteaExpression = jet.BlobExpression
|
||||||
|
|
||||||
// NumericExpression interface
|
// NumericExpression interface
|
||||||
type NumericExpression = jet.NumericExpression
|
type NumericExpression = jet.NumericExpression
|
||||||
|
|
||||||
|
|
@ -82,6 +84,11 @@ var TimeExp = jet.TimeExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var StringExp = jet.StringExp
|
var StringExp = jet.StringExp
|
||||||
|
|
||||||
|
// ByteaExp is blob expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as string expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
var ByteaExp = jet.BlobExp
|
||||||
|
|
||||||
// TimezExp is time with time zone expression wrapper around arbitrary expression.
|
// TimezExp is time with time zone expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as time with time zone expression.
|
// Allows go compiler to see any expression as time with time zone expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
@ -143,6 +150,8 @@ var (
|
||||||
RawTimestamp = jet.RawTimestamp
|
RawTimestamp = jet.RawTimestamp
|
||||||
RawTimestampz = jet.RawTimestampz
|
RawTimestampz = jet.RawTimestampz
|
||||||
RawDate = jet.RawDate
|
RawDate = jet.RawDate
|
||||||
|
RawBytea = jet.RawBlob
|
||||||
|
|
||||||
RawNumRange = jet.RawRange[jet.NumericExpression]
|
RawNumRange = jet.RawRange[jet.NumericExpression]
|
||||||
RawInt4Range = jet.RawRange[jet.Int4Expression]
|
RawInt4Range = jet.RawRange[jet.Int4Expression]
|
||||||
RawInt8Range = jet.RawRange[jet.Int8Expression]
|
RawInt8Range = jet.RawRange[jet.Int8Expression]
|
||||||
|
|
|
||||||
|
|
@ -192,9 +192,27 @@ func CONCAT_WS(separator Expression, expressions ...Expression) StringExpression
|
||||||
return jet.CONCAT_WS(explicitLiteralCast(separator), explicitLiteralCasts(expressions...)...)
|
return jet.CONCAT_WS(explicitLiteralCast(separator), explicitLiteralCasts(expressions...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Character encodings for CONVERT, CONVERT_FROM and CONVERT_TO functions
|
||||||
|
var (
|
||||||
|
UTF8 = String("UTF8")
|
||||||
|
LATIN1 = String("LATIN1")
|
||||||
|
LATIN2 = String("LATIN2")
|
||||||
|
LATIN3 = String("LATIN3")
|
||||||
|
LATIN4 = String("LATIN4")
|
||||||
|
WIN1252 = String("WIN1252")
|
||||||
|
ISO_8859_5 = String("ISO_8859_5")
|
||||||
|
ISO_8859_6 = String("ISO_8859_6")
|
||||||
|
ISO_8859_7 = String("ISO_8859_7")
|
||||||
|
ISO_8859_8 = String("ISO_8859_8")
|
||||||
|
KOI8R = String("KOI8R")
|
||||||
|
KOI8U = String("KOI8U")
|
||||||
|
)
|
||||||
|
|
||||||
// CONVERT converts string to dest_encoding. The original encoding is
|
// CONVERT converts string to dest_encoding. The original encoding is
|
||||||
// specified by src_encoding. The string must be valid in this encoding.
|
// specified by src_encoding. The string must be valid in this encoding.
|
||||||
var CONVERT = jet.CONVERT
|
func CONVERT(str ByteaExpression, srcEncoding StringExpression, destEncoding StringExpression) ByteaExpression {
|
||||||
|
return jet.CONVERT(str, srcEncoding, destEncoding)
|
||||||
|
}
|
||||||
|
|
||||||
// CONVERT_FROM converts string to the database encoding. The original
|
// CONVERT_FROM converts string to the database encoding. The original
|
||||||
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
||||||
|
|
@ -203,6 +221,13 @@ var CONVERT_FROM = jet.CONVERT_FROM
|
||||||
// CONVERT_TO converts string to dest_encoding.
|
// CONVERT_TO converts string to dest_encoding.
|
||||||
var CONVERT_TO = jet.CONVERT_TO
|
var CONVERT_TO = jet.CONVERT_TO
|
||||||
|
|
||||||
|
// ENCODE/DECODE textual formats
|
||||||
|
var (
|
||||||
|
Base64 StringExpression = String("base64")
|
||||||
|
Escape StringExpression = String("escape")
|
||||||
|
Hex StringExpression = String("hex")
|
||||||
|
)
|
||||||
|
|
||||||
// ENCODE encodes binary data into a textual representation.
|
// ENCODE encodes binary data into a textual representation.
|
||||||
// Supported formats are: base64, hex, escape. escape converts zero bytes and
|
// Supported formats are: base64, hex, escape. escape converts zero bytes and
|
||||||
// high-bit-set bytes to octal sequences (\nnn) and doubles backslashes.
|
// high-bit-set bytes to octal sequences (\nnn) and doubles backslashes.
|
||||||
|
|
@ -212,7 +237,7 @@ var ENCODE = jet.ENCODE
|
||||||
// Options for format are same as in encode.
|
// Options for format are same as in encode.
|
||||||
var DECODE = jet.DECODE
|
var DECODE = jet.DECODE
|
||||||
|
|
||||||
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
// FORMAT formats the arguments according to a format string. This function is similar to the C function sprintf.
|
||||||
func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression {
|
func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression {
|
||||||
return jet.FORMAT(formatStr, explicitLiteralCasts(formatArgs...)...)
|
return jet.FORMAT(formatStr, explicitLiteralCasts(formatArgs...)...)
|
||||||
}
|
}
|
||||||
|
|
@ -242,6 +267,49 @@ var LPAD = jet.LPAD
|
||||||
// fill (a space by default). If the string is already longer than length then it is truncated.
|
// fill (a space by default). If the string is already longer than length then it is truncated.
|
||||||
var RPAD = jet.RPAD
|
var RPAD = jet.RPAD
|
||||||
|
|
||||||
|
// BIT_COUNT returns the number of bits set in the binary string (also known as “popcount”).
|
||||||
|
var BIT_COUNT = jet.BIT_COUNT
|
||||||
|
|
||||||
|
// GET_BIT extracts n'th bit from binary string.
|
||||||
|
func GET_BIT(bytes ByteaExpression, n IntegerExpression) IntegerExpression {
|
||||||
|
return IntExp(Func("GET_BIT", bytes, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET_BYTE extracts n'th byte from binary string.
|
||||||
|
func GET_BYTE(bytes ByteaExpression, n IntegerExpression) IntegerExpression {
|
||||||
|
return IntExp(Func("GET_BYTE", bytes, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SET_BIT sets n'th bit in binary string to newvalue.
|
||||||
|
func SET_BIT(bytes ByteaExpression, n IntegerExpression, newValue IntegerExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SET_BIT", bytes, n, newValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SET_BYTE sets n'th byte in binary string to newvalue.
|
||||||
|
func SET_BYTE(bytes ByteaExpression, n IntegerExpression, newValue IntegerExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SET_BYTE", bytes, n, newValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA224 computes the SHA-224 hash of the binary string.
|
||||||
|
func SHA224(bytes ByteaExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SHA224", bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA256 computes the SHA-256 hash of the binary string.
|
||||||
|
func SHA256(bytes ByteaExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SHA256", bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA384 computes the SHA-384 hash of the binary string.
|
||||||
|
func SHA384(bytes ByteaExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SHA384", bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA512 computes the SHA-512 hash of the binary string.
|
||||||
|
func SHA512(bytes ByteaExpression) ByteaExpression {
|
||||||
|
return ByteaExp(Func("SHA512", bytes))
|
||||||
|
}
|
||||||
|
|
||||||
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
||||||
var MD5 = jet.MD5
|
var MD5 = jet.MD5
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ func Json(value interface{}) StringExpression {
|
||||||
var UUID = jet.UUID
|
var UUID = jet.UUID
|
||||||
|
|
||||||
// Bytea creates new bytea literal expression
|
// Bytea creates new bytea literal expression
|
||||||
func Bytea(value interface{}) StringExpression {
|
func Bytea(value interface{}) ByteaExpression {
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
case string, []byte:
|
case string, []byte:
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,6 @@ func (c *cast) AS_REAL() FloatExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_BLOB cast expression to BLOB type
|
// AS_BLOB cast expression to BLOB type
|
||||||
func (c *cast) AS_BLOB() StringExpression {
|
func (c *cast) AS_BLOB() BlobExpression {
|
||||||
return StringExp(c.AS("BLOB"))
|
return BlobExp(c.AS("BLOB"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ type ColumnString = jet.ColumnString
|
||||||
// StringColumn creates named string column.
|
// StringColumn creates named string column.
|
||||||
var StringColumn = jet.StringColumn
|
var StringColumn = jet.StringColumn
|
||||||
|
|
||||||
|
// ColumnBlob is interface for
|
||||||
|
type ColumnBlob = jet.ColumnBlob
|
||||||
|
|
||||||
|
// BlobColumn creates new named blob column
|
||||||
|
var BlobColumn = jet.BlobColumn
|
||||||
|
|
||||||
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
||||||
type ColumnInteger = jet.ColumnInteger
|
type ColumnInteger = jet.ColumnInteger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-jet/jet/v2/internal/jet"
|
"github.com/go-jet/jet/v2/internal/jet"
|
||||||
)
|
)
|
||||||
|
|
@ -23,6 +24,7 @@ func newDialect() jet.Dialect {
|
||||||
ArgumentPlaceholder: func(int) string {
|
ArgumentPlaceholder: func(int) string {
|
||||||
return "?"
|
return "?"
|
||||||
},
|
},
|
||||||
|
ArgumentToString: argumentToString,
|
||||||
ReservedWords: reservedWords2,
|
ReservedWords: reservedWords2,
|
||||||
ValuesDefaultColumnName: func(index int) string {
|
ValuesDefaultColumnName: func(index int) string {
|
||||||
return fmt.Sprintf("column%d", index+1)
|
return fmt.Sprintf("column%d", index+1)
|
||||||
|
|
@ -32,6 +34,15 @@ func newDialect() jet.Dialect {
|
||||||
return jet.NewDialect(mySQLDialectParams)
|
return jet.NewDialect(mySQLDialectParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func argumentToString(value any) (string, bool) {
|
||||||
|
switch bindVal := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
return fmt.Sprintf("X'%s'", hex.EncodeToString(bindVal)), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
func sqliteBitXOR(expressions ...jet.Serializer) jet.SerializerFunc {
|
func sqliteBitXOR(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||||
if len(expressions) < 2 {
|
if len(expressions) < 2 {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ type BoolExpression = jet.BoolExpression
|
||||||
// StringExpression interface
|
// StringExpression interface
|
||||||
type StringExpression = jet.StringExpression
|
type StringExpression = jet.StringExpression
|
||||||
|
|
||||||
|
// BlobExpression interface
|
||||||
|
type BlobExpression = jet.BlobExpression
|
||||||
|
|
||||||
// NumericExpression is shared interface for integer or real expression
|
// NumericExpression is shared interface for integer or real expression
|
||||||
type NumericExpression = jet.NumericExpression
|
type NumericExpression = jet.NumericExpression
|
||||||
|
|
||||||
|
|
@ -46,6 +49,11 @@ var BoolExp = jet.BoolExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var StringExp = jet.StringExp
|
var StringExp = jet.StringExp
|
||||||
|
|
||||||
|
// BlobExp is blob expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as blob expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
var BlobExp = jet.BlobExp
|
||||||
|
|
||||||
// IntExp is int expression wrapper around arbitrary expression.
|
// IntExp is int expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as int expression.
|
// Allows go compiler to see any expression as int expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
|
||||||
|
|
@ -196,11 +196,22 @@ var RTRIM = jet.RTRIM
|
||||||
// return jet.NewStringFunc("RIGHTSTR", str, n)
|
// return jet.NewStringFunc("RIGHTSTR", str, n)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
// HEX function takes an input and returns its equivalent hexadecimal representation
|
||||||
|
var HEX = jet.HEX
|
||||||
|
|
||||||
|
// UNHEX for a string argument str, UNHEX(str) interprets each pair of characters in the argument
|
||||||
|
// as a hexadecimal number and converts it to the byte represented by the number.
|
||||||
|
// The return value is a binary string.
|
||||||
|
var UNHEX = jet.UNHEX
|
||||||
|
|
||||||
// LENGTH returns number of characters in string with a given encoding
|
// LENGTH returns number of characters in string with a given encoding
|
||||||
func LENGTH(str jet.StringExpression) jet.StringExpression {
|
func LENGTH(str jet.StringOrBlobExpression) jet.IntegerExpression {
|
||||||
return jet.LENGTH(str)
|
return jet.LENGTH(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OCTET_LENGTH returns number of bytes in string expression
|
||||||
|
var OCTET_LENGTH = jet.OCTET_LENGTH
|
||||||
|
|
||||||
// LPAD fills up the string to length length by prepending the characters
|
// LPAD fills up the string to length length by prepending the characters
|
||||||
// fill (a space by default). If the string is already longer than length
|
// fill (a space by default). If the string is already longer than length
|
||||||
// then it is truncated (on the right).
|
// then it is truncated (on the right).
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ var Decimal = jet.Decimal
|
||||||
// String creates new string literal expression
|
// String creates new string literal expression
|
||||||
var String = jet.String
|
var String = jet.String
|
||||||
|
|
||||||
|
func Blob(data []byte) BlobExpression {
|
||||||
|
return BlobExp(jet.Literal(data))
|
||||||
|
}
|
||||||
|
|
||||||
// UUID is a helper function to create string literal expression from uuid object
|
// UUID is a helper function to create string literal expression from uuid object
|
||||||
// value can be any uuid type with a String method
|
// value can be any uuid type with a String method
|
||||||
var UUID = jet.UUID
|
var UUID = jet.UUID
|
||||||
|
|
|
||||||
|
|
@ -511,7 +511,8 @@ func TestStringOperators(t *testing.T) {
|
||||||
RTRIM(AllTypes.VarCharPtr),
|
RTRIM(AllTypes.VarCharPtr),
|
||||||
CONCAT(String("string1"), Int(1), Float(11.12)),
|
CONCAT(String("string1"), Int(1), Float(11.12)),
|
||||||
CONCAT_WS(String("string1"), Int(1), Float(11.12)),
|
CONCAT_WS(String("string1"), Int(1), Float(11.12)),
|
||||||
FORMAT(String("Hello %s, %1$s"), String("World")),
|
FORMAT(Int(11), Int(2)),
|
||||||
|
FORMAT(Int(11), Int(2), String("de_DE")),
|
||||||
LEFT(String("abcde"), Int(2)),
|
LEFT(String("abcde"), Int(2)),
|
||||||
RIGHT(String("abcde"), Int(2)),
|
RIGHT(String("abcde"), Int(2)),
|
||||||
LENGTH(String("jose")),
|
LENGTH(String("jose")),
|
||||||
|
|
@ -523,6 +524,12 @@ func TestStringOperators(t *testing.T) {
|
||||||
REVERSE(AllTypes.VarCharPtr),
|
REVERSE(AllTypes.VarCharPtr),
|
||||||
SUBSTR(AllTypes.CharPtr, Int(3)),
|
SUBSTR(AllTypes.CharPtr, Int(3)),
|
||||||
SUBSTR(AllTypes.CharPtr, Int(3), Int(2)),
|
SUBSTR(AllTypes.CharPtr, Int(3), Int(2)),
|
||||||
|
ELT(Int(2), AllTypes.CharPtr, AllTypes.Char, AllTypes.Text),
|
||||||
|
FIELD(AllTypes.Char, AllTypes.VarChar, AllTypes.Text),
|
||||||
|
FROM_BASE64(String("SGVsbG8gV29ybGQ=")),
|
||||||
|
TO_BASE64(String("Hello World")),
|
||||||
|
CHARSET(AllTypes.Char),
|
||||||
|
COLLATION(AllTypes.Text),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sourceIsMariaDB() {
|
if !sourceIsMariaDB() {
|
||||||
|
|
@ -544,6 +551,71 @@ func TestStringOperators(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlob(t *testing.T) {
|
||||||
|
|
||||||
|
var sampleBlob = Blob([]byte{11, 0, 22, 33, 44})
|
||||||
|
var textBlob = Blob([]byte("text blob"))
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
AllTypes.BlobPtr.EQ(sampleBlob),
|
||||||
|
AllTypes.BlobPtr.EQ(AllTypes.BlobPtr),
|
||||||
|
AllTypes.BlobPtr.NOT_EQ(sampleBlob),
|
||||||
|
AllTypes.BlobPtr.GT(textBlob),
|
||||||
|
AllTypes.BlobPtr.GT_EQ(AllTypes.BlobPtr),
|
||||||
|
AllTypes.BlobPtr.LT(AllTypes.BlobPtr),
|
||||||
|
AllTypes.BlobPtr.LT_EQ(sampleBlob),
|
||||||
|
AllTypes.BlobPtr.BETWEEN(Blob([]byte("min")), Blob([]byte("max"))),
|
||||||
|
AllTypes.BlobPtr.NOT_BETWEEN(AllTypes.BlobPtr, AllTypes.BlobPtr),
|
||||||
|
AllTypes.BlobPtr.CONCAT(textBlob),
|
||||||
|
AllTypes.BlobPtr.LIKE(AllTypes.BlobPtr),
|
||||||
|
AllTypes.BlobPtr.NOT_LIKE(sampleBlob),
|
||||||
|
|
||||||
|
BIT_LENGTH(textBlob),
|
||||||
|
LENGTH(sampleBlob),
|
||||||
|
CHAR_LENGTH(AllTypes.BlobPtr),
|
||||||
|
OCTET_LENGTH(textBlob),
|
||||||
|
CONCAT(sampleBlob, Int(1), Float(11.12)),
|
||||||
|
TO_BASE64(sampleBlob),
|
||||||
|
HEX(sampleBlob),
|
||||||
|
UNHEX(String("616B263A")),
|
||||||
|
SUBSTR(AllTypes.BlobPtr, Int(3)),
|
||||||
|
SUBSTR(AllTypes.BlobPtr, Int(3), Int(2)),
|
||||||
|
).FROM(
|
||||||
|
AllTypes,
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
SELECT all_types.blob_ptr = X'0b0016212c',
|
||||||
|
all_types.blob_ptr = all_types.blob_ptr,
|
||||||
|
all_types.blob_ptr != X'0b0016212c',
|
||||||
|
all_types.blob_ptr > X'7465787420626c6f62',
|
||||||
|
all_types.blob_ptr >= all_types.blob_ptr,
|
||||||
|
all_types.blob_ptr < all_types.blob_ptr,
|
||||||
|
all_types.blob_ptr <= X'0b0016212c',
|
||||||
|
all_types.blob_ptr BETWEEN X'6d696e' AND X'6d6178',
|
||||||
|
all_types.blob_ptr NOT BETWEEN all_types.blob_ptr AND all_types.blob_ptr,
|
||||||
|
CONCAT(all_types.blob_ptr, X'7465787420626c6f62'),
|
||||||
|
all_types.blob_ptr LIKE all_types.blob_ptr,
|
||||||
|
all_types.blob_ptr NOT LIKE X'0b0016212c',
|
||||||
|
BIT_LENGTH(X'7465787420626c6f62'),
|
||||||
|
LENGTH(X'0b0016212c'),
|
||||||
|
CHAR_LENGTH(all_types.blob_ptr),
|
||||||
|
OCTET_LENGTH(X'7465787420626c6f62'),
|
||||||
|
CONCAT(X'0b0016212c', 1, 11.12),
|
||||||
|
TO_BASE64(X'0b0016212c'),
|
||||||
|
HEX(X'0b0016212c'),
|
||||||
|
UNHEX('616B263A'),
|
||||||
|
SUBSTR(all_types.blob_ptr, 3),
|
||||||
|
SUBSTR(all_types.blob_ptr, 3, 2)
|
||||||
|
FROM test_sample.all_types;
|
||||||
|
`)
|
||||||
|
|
||||||
|
var dest []struct{}
|
||||||
|
err := stmt.Query(db, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||||
|
|
||||||
func TestTimeExpressions(t *testing.T) {
|
func TestTimeExpressions(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package mysql
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -606,3 +607,394 @@ func UseSchema(schema string) {
|
||||||
StaffList = StaffList.FromSchema(schema)
|
StaffList = StaffList.FromSchema(schema)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func TestGeneratedTestSampleDatabase(t *testing.T) {
|
||||||
|
|
||||||
|
enumDir := filepath.Join(testRoot, "/.gentestdata/mysql/test_sample/enum/")
|
||||||
|
modelDir := filepath.Join(testRoot, "/.gentestdata/mysql/test_sample/model/")
|
||||||
|
tableDir := filepath.Join(testRoot, "/.gentestdata/mysql/test_sample/table/")
|
||||||
|
viewDir := filepath.Join(testRoot, "/.gentestdata/mysql/test_sample/view/")
|
||||||
|
|
||||||
|
testutils.AssertFileNamesEqual(t, enumDir, "all_types_enum.go", "all_types_enum_ptr.go",
|
||||||
|
"all_types_view_enum.go", "all_types_view_enum_ptr.go")
|
||||||
|
testutils.AssertFileContent(t, enumDir+"/all_types_enum.go", allTypesEnum)
|
||||||
|
|
||||||
|
testutils.AssertFileNamesEqual(t, modelDir, "all_types.go", "all_types_enum.go", "all_types_enum_ptr.go",
|
||||||
|
"all_types_view.go", "all_types_view_enum.go", "all_types_view_enum_ptr.go", "link.go", "link2.go",
|
||||||
|
"floats.go", "user.go")
|
||||||
|
|
||||||
|
testutils.AssertFileContent(t, modelDir+"/all_types.go", allTypesModelContent)
|
||||||
|
|
||||||
|
testutils.AssertFileNamesEqual(t, tableDir, "all_types.go",
|
||||||
|
"link.go", "link2.go", "user.go", "floats.go", "table_use_schema.go")
|
||||||
|
testutils.AssertFileContent(t, tableDir+"/all_types.go", allTypesTableContent)
|
||||||
|
|
||||||
|
testutils.AssertFileNamesEqual(t, viewDir, "all_types_view.go", "view_use_schema.go")
|
||||||
|
}
|
||||||
|
|
||||||
|
var allTypesEnum = `
|
||||||
|
//
|
||||||
|
// Code generated by go-jet DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// WARNING: Changes to this file may cause incorrect behavior
|
||||||
|
// and will be lost if the code is regenerated
|
||||||
|
//
|
||||||
|
|
||||||
|
package enum
|
||||||
|
|
||||||
|
import "github.com/go-jet/jet/v2/mysql"
|
||||||
|
|
||||||
|
var AllTypesEnum = &struct {
|
||||||
|
Value1 mysql.StringExpression
|
||||||
|
Value2 mysql.StringExpression
|
||||||
|
Value3 mysql.StringExpression
|
||||||
|
}{
|
||||||
|
Value1: mysql.NewEnumValue("value1"),
|
||||||
|
Value2: mysql.NewEnumValue("value2"),
|
||||||
|
Value3: mysql.NewEnumValue("value3"),
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var allTypesModelContent = `
|
||||||
|
//
|
||||||
|
// Code generated by go-jet DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// WARNING: Changes to this file may cause incorrect behavior
|
||||||
|
// and will be lost if the code is regenerated
|
||||||
|
//
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AllTypes struct {
|
||||||
|
Boolean bool
|
||||||
|
BooleanPtr *bool
|
||||||
|
TinyInt int8
|
||||||
|
UTinyInt uint8
|
||||||
|
SmallInt int16
|
||||||
|
USmallInt uint16
|
||||||
|
MediumInt int32
|
||||||
|
UMediumInt uint32
|
||||||
|
Integer int32
|
||||||
|
UInteger uint32
|
||||||
|
BigInt int64
|
||||||
|
UBigInt uint64
|
||||||
|
TinyIntPtr *int8
|
||||||
|
UTinyIntPtr *uint8
|
||||||
|
SmallIntPtr *int16
|
||||||
|
USmallIntPtr *uint16
|
||||||
|
MediumIntPtr *int32
|
||||||
|
UMediumIntPtr *uint32
|
||||||
|
IntegerPtr *int32
|
||||||
|
UIntegerPtr *uint32
|
||||||
|
BigIntPtr *int64
|
||||||
|
UBigIntPtr *uint64
|
||||||
|
Decimal float64
|
||||||
|
DecimalPtr *float64
|
||||||
|
Numeric float64
|
||||||
|
NumericPtr *float64
|
||||||
|
Float float64
|
||||||
|
FloatPtr *float64
|
||||||
|
Double float64
|
||||||
|
DoublePtr *float64
|
||||||
|
Real float64
|
||||||
|
RealPtr *float64
|
||||||
|
Bit string
|
||||||
|
BitPtr *string
|
||||||
|
Time time.Time
|
||||||
|
TimePtr *time.Time
|
||||||
|
Date time.Time
|
||||||
|
DatePtr *time.Time
|
||||||
|
DateTime time.Time
|
||||||
|
DateTimePtr *time.Time
|
||||||
|
Timestamp time.Time
|
||||||
|
TimestampPtr *time.Time
|
||||||
|
Year int16
|
||||||
|
YearPtr *int16
|
||||||
|
Char string
|
||||||
|
CharPtr *string
|
||||||
|
VarChar string
|
||||||
|
VarCharPtr *string
|
||||||
|
Binary []byte
|
||||||
|
BinaryPtr *[]byte
|
||||||
|
VarBinary []byte
|
||||||
|
VarBinaryPtr *[]byte
|
||||||
|
Blob []byte
|
||||||
|
BlobPtr *[]byte
|
||||||
|
Text string
|
||||||
|
TextPtr *string
|
||||||
|
Enum AllTypesEnum
|
||||||
|
EnumPtr *AllTypesEnumPtr
|
||||||
|
Set string
|
||||||
|
SetPtr *string
|
||||||
|
JSON string
|
||||||
|
JSONPtr *string
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var allTypesTableContent = `
|
||||||
|
//
|
||||||
|
// Code generated by go-jet DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// WARNING: Changes to this file may cause incorrect behavior
|
||||||
|
// and will be lost if the code is regenerated
|
||||||
|
//
|
||||||
|
|
||||||
|
package table
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-jet/jet/v2/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllTypes = newAllTypesTable("test_sample", "all_types", "")
|
||||||
|
|
||||||
|
type allTypesTable struct {
|
||||||
|
mysql.Table
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
Boolean mysql.ColumnBool
|
||||||
|
BooleanPtr mysql.ColumnBool
|
||||||
|
TinyInt mysql.ColumnInteger
|
||||||
|
UTinyInt mysql.ColumnInteger
|
||||||
|
SmallInt mysql.ColumnInteger
|
||||||
|
USmallInt mysql.ColumnInteger
|
||||||
|
MediumInt mysql.ColumnInteger
|
||||||
|
UMediumInt mysql.ColumnInteger
|
||||||
|
Integer mysql.ColumnInteger
|
||||||
|
UInteger mysql.ColumnInteger
|
||||||
|
BigInt mysql.ColumnInteger
|
||||||
|
UBigInt mysql.ColumnInteger
|
||||||
|
TinyIntPtr mysql.ColumnInteger
|
||||||
|
UTinyIntPtr mysql.ColumnInteger
|
||||||
|
SmallIntPtr mysql.ColumnInteger
|
||||||
|
USmallIntPtr mysql.ColumnInteger
|
||||||
|
MediumIntPtr mysql.ColumnInteger
|
||||||
|
UMediumIntPtr mysql.ColumnInteger
|
||||||
|
IntegerPtr mysql.ColumnInteger
|
||||||
|
UIntegerPtr mysql.ColumnInteger
|
||||||
|
BigIntPtr mysql.ColumnInteger
|
||||||
|
UBigIntPtr mysql.ColumnInteger
|
||||||
|
Decimal mysql.ColumnFloat
|
||||||
|
DecimalPtr mysql.ColumnFloat
|
||||||
|
Numeric mysql.ColumnFloat
|
||||||
|
NumericPtr mysql.ColumnFloat
|
||||||
|
Float mysql.ColumnFloat
|
||||||
|
FloatPtr mysql.ColumnFloat
|
||||||
|
Double mysql.ColumnFloat
|
||||||
|
DoublePtr mysql.ColumnFloat
|
||||||
|
Real mysql.ColumnFloat
|
||||||
|
RealPtr mysql.ColumnFloat
|
||||||
|
Bit mysql.ColumnString
|
||||||
|
BitPtr mysql.ColumnString
|
||||||
|
Time mysql.ColumnTime
|
||||||
|
TimePtr mysql.ColumnTime
|
||||||
|
Date mysql.ColumnDate
|
||||||
|
DatePtr mysql.ColumnDate
|
||||||
|
DateTime mysql.ColumnTimestamp
|
||||||
|
DateTimePtr mysql.ColumnTimestamp
|
||||||
|
Timestamp mysql.ColumnTimestamp
|
||||||
|
TimestampPtr mysql.ColumnTimestamp
|
||||||
|
Year mysql.ColumnInteger
|
||||||
|
YearPtr mysql.ColumnInteger
|
||||||
|
Char mysql.ColumnString
|
||||||
|
CharPtr mysql.ColumnString
|
||||||
|
VarChar mysql.ColumnString
|
||||||
|
VarCharPtr mysql.ColumnString
|
||||||
|
Binary mysql.ColumnBlob
|
||||||
|
BinaryPtr mysql.ColumnBlob
|
||||||
|
VarBinary mysql.ColumnBlob
|
||||||
|
VarBinaryPtr mysql.ColumnBlob
|
||||||
|
Blob mysql.ColumnBlob
|
||||||
|
BlobPtr mysql.ColumnBlob
|
||||||
|
Text mysql.ColumnString
|
||||||
|
TextPtr mysql.ColumnString
|
||||||
|
Enum mysql.ColumnString
|
||||||
|
EnumPtr mysql.ColumnString
|
||||||
|
Set mysql.ColumnString
|
||||||
|
SetPtr mysql.ColumnString
|
||||||
|
JSON mysql.ColumnString
|
||||||
|
JSONPtr mysql.ColumnString
|
||||||
|
|
||||||
|
AllColumns mysql.ColumnList
|
||||||
|
MutableColumns mysql.ColumnList
|
||||||
|
DefaultColumns mysql.ColumnList
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllTypesTable struct {
|
||||||
|
allTypesTable
|
||||||
|
|
||||||
|
NEW allTypesTable
|
||||||
|
}
|
||||||
|
|
||||||
|
// AS creates new AllTypesTable with assigned alias
|
||||||
|
func (a AllTypesTable) AS(alias string) *AllTypesTable {
|
||||||
|
return newAllTypesTable(a.SchemaName(), a.TableName(), alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema creates new AllTypesTable with assigned schema name
|
||||||
|
func (a AllTypesTable) FromSchema(schemaName string) *AllTypesTable {
|
||||||
|
return newAllTypesTable(schemaName, a.TableName(), a.Alias())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPrefix creates new AllTypesTable with assigned table prefix
|
||||||
|
func (a AllTypesTable) WithPrefix(prefix string) *AllTypesTable {
|
||||||
|
return newAllTypesTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSuffix creates new AllTypesTable with assigned table suffix
|
||||||
|
func (a AllTypesTable) WithSuffix(suffix string) *AllTypesTable {
|
||||||
|
return newAllTypesTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAllTypesTable(schemaName, tableName, alias string) *AllTypesTable {
|
||||||
|
return &AllTypesTable{
|
||||||
|
allTypesTable: newAllTypesTableImpl(schemaName, tableName, alias),
|
||||||
|
NEW: newAllTypesTableImpl("", "new", ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAllTypesTableImpl(schemaName, tableName, alias string) allTypesTable {
|
||||||
|
var (
|
||||||
|
BooleanColumn = mysql.BoolColumn("boolean")
|
||||||
|
BooleanPtrColumn = mysql.BoolColumn("boolean_ptr")
|
||||||
|
TinyIntColumn = mysql.IntegerColumn("tiny_int")
|
||||||
|
UTinyIntColumn = mysql.IntegerColumn("u_tiny_int")
|
||||||
|
SmallIntColumn = mysql.IntegerColumn("small_int")
|
||||||
|
USmallIntColumn = mysql.IntegerColumn("u_small_int")
|
||||||
|
MediumIntColumn = mysql.IntegerColumn("medium_int")
|
||||||
|
UMediumIntColumn = mysql.IntegerColumn("u_medium_int")
|
||||||
|
IntegerColumn = mysql.IntegerColumn("integer")
|
||||||
|
UIntegerColumn = mysql.IntegerColumn("u_integer")
|
||||||
|
BigIntColumn = mysql.IntegerColumn("big_int")
|
||||||
|
UBigIntColumn = mysql.IntegerColumn("u_big_int")
|
||||||
|
TinyIntPtrColumn = mysql.IntegerColumn("tiny_int_ptr")
|
||||||
|
UTinyIntPtrColumn = mysql.IntegerColumn("u_tiny_int_ptr")
|
||||||
|
SmallIntPtrColumn = mysql.IntegerColumn("small_int_ptr")
|
||||||
|
USmallIntPtrColumn = mysql.IntegerColumn("u_small_int_ptr")
|
||||||
|
MediumIntPtrColumn = mysql.IntegerColumn("medium_int_ptr")
|
||||||
|
UMediumIntPtrColumn = mysql.IntegerColumn("u_medium_int_ptr")
|
||||||
|
IntegerPtrColumn = mysql.IntegerColumn("integer_ptr")
|
||||||
|
UIntegerPtrColumn = mysql.IntegerColumn("u_integer_ptr")
|
||||||
|
BigIntPtrColumn = mysql.IntegerColumn("big_int_ptr")
|
||||||
|
UBigIntPtrColumn = mysql.IntegerColumn("u_big_int_ptr")
|
||||||
|
DecimalColumn = mysql.FloatColumn("decimal")
|
||||||
|
DecimalPtrColumn = mysql.FloatColumn("decimal_ptr")
|
||||||
|
NumericColumn = mysql.FloatColumn("numeric")
|
||||||
|
NumericPtrColumn = mysql.FloatColumn("numeric_ptr")
|
||||||
|
FloatColumn = mysql.FloatColumn("float")
|
||||||
|
FloatPtrColumn = mysql.FloatColumn("float_ptr")
|
||||||
|
DoubleColumn = mysql.FloatColumn("double")
|
||||||
|
DoublePtrColumn = mysql.FloatColumn("double_ptr")
|
||||||
|
RealColumn = mysql.FloatColumn("real")
|
||||||
|
RealPtrColumn = mysql.FloatColumn("real_ptr")
|
||||||
|
BitColumn = mysql.StringColumn("bit")
|
||||||
|
BitPtrColumn = mysql.StringColumn("bit_ptr")
|
||||||
|
TimeColumn = mysql.TimeColumn("time")
|
||||||
|
TimePtrColumn = mysql.TimeColumn("time_ptr")
|
||||||
|
DateColumn = mysql.DateColumn("date")
|
||||||
|
DatePtrColumn = mysql.DateColumn("date_ptr")
|
||||||
|
DateTimeColumn = mysql.TimestampColumn("date_time")
|
||||||
|
DateTimePtrColumn = mysql.TimestampColumn("date_time_ptr")
|
||||||
|
TimestampColumn = mysql.TimestampColumn("timestamp")
|
||||||
|
TimestampPtrColumn = mysql.TimestampColumn("timestamp_ptr")
|
||||||
|
YearColumn = mysql.IntegerColumn("year")
|
||||||
|
YearPtrColumn = mysql.IntegerColumn("year_ptr")
|
||||||
|
CharColumn = mysql.StringColumn("char")
|
||||||
|
CharPtrColumn = mysql.StringColumn("char_ptr")
|
||||||
|
VarCharColumn = mysql.StringColumn("var_char")
|
||||||
|
VarCharPtrColumn = mysql.StringColumn("var_char_ptr")
|
||||||
|
BinaryColumn = mysql.BlobColumn("binary")
|
||||||
|
BinaryPtrColumn = mysql.BlobColumn("binary_ptr")
|
||||||
|
VarBinaryColumn = mysql.BlobColumn("var_binary")
|
||||||
|
VarBinaryPtrColumn = mysql.BlobColumn("var_binary_ptr")
|
||||||
|
BlobColumn = mysql.BlobColumn("blob")
|
||||||
|
BlobPtrColumn = mysql.BlobColumn("blob_ptr")
|
||||||
|
TextColumn = mysql.StringColumn("text")
|
||||||
|
TextPtrColumn = mysql.StringColumn("text_ptr")
|
||||||
|
EnumColumn = mysql.StringColumn("enum")
|
||||||
|
EnumPtrColumn = mysql.StringColumn("enum_ptr")
|
||||||
|
SetColumn = mysql.StringColumn("set")
|
||||||
|
SetPtrColumn = mysql.StringColumn("set_ptr")
|
||||||
|
JSONColumn = mysql.StringColumn("json")
|
||||||
|
JSONPtrColumn = mysql.StringColumn("json_ptr")
|
||||||
|
allColumns = mysql.ColumnList{BooleanColumn, BooleanPtrColumn, TinyIntColumn, UTinyIntColumn, SmallIntColumn, USmallIntColumn, MediumIntColumn, UMediumIntColumn, IntegerColumn, UIntegerColumn, BigIntColumn, UBigIntColumn, TinyIntPtrColumn, UTinyIntPtrColumn, SmallIntPtrColumn, USmallIntPtrColumn, MediumIntPtrColumn, UMediumIntPtrColumn, IntegerPtrColumn, UIntegerPtrColumn, BigIntPtrColumn, UBigIntPtrColumn, DecimalColumn, DecimalPtrColumn, NumericColumn, NumericPtrColumn, FloatColumn, FloatPtrColumn, DoubleColumn, DoublePtrColumn, RealColumn, RealPtrColumn, BitColumn, BitPtrColumn, TimeColumn, TimePtrColumn, DateColumn, DatePtrColumn, DateTimeColumn, DateTimePtrColumn, TimestampColumn, TimestampPtrColumn, YearColumn, YearPtrColumn, CharColumn, CharPtrColumn, VarCharColumn, VarCharPtrColumn, BinaryColumn, BinaryPtrColumn, VarBinaryColumn, VarBinaryPtrColumn, BlobColumn, BlobPtrColumn, TextColumn, TextPtrColumn, EnumColumn, EnumPtrColumn, SetColumn, SetPtrColumn, JSONColumn, JSONPtrColumn}
|
||||||
|
mutableColumns = mysql.ColumnList{BooleanColumn, BooleanPtrColumn, TinyIntColumn, UTinyIntColumn, SmallIntColumn, USmallIntColumn, MediumIntColumn, UMediumIntColumn, IntegerColumn, UIntegerColumn, BigIntColumn, UBigIntColumn, TinyIntPtrColumn, UTinyIntPtrColumn, SmallIntPtrColumn, USmallIntPtrColumn, MediumIntPtrColumn, UMediumIntPtrColumn, IntegerPtrColumn, UIntegerPtrColumn, BigIntPtrColumn, UBigIntPtrColumn, DecimalColumn, DecimalPtrColumn, NumericColumn, NumericPtrColumn, FloatColumn, FloatPtrColumn, DoubleColumn, DoublePtrColumn, RealColumn, RealPtrColumn, BitColumn, BitPtrColumn, TimeColumn, TimePtrColumn, DateColumn, DatePtrColumn, DateTimeColumn, DateTimePtrColumn, TimestampColumn, TimestampPtrColumn, YearColumn, YearPtrColumn, CharColumn, CharPtrColumn, VarCharColumn, VarCharPtrColumn, BinaryColumn, BinaryPtrColumn, VarBinaryColumn, VarBinaryPtrColumn, BlobColumn, BlobPtrColumn, TextColumn, TextPtrColumn, EnumColumn, EnumPtrColumn, SetColumn, SetPtrColumn, JSONColumn, JSONPtrColumn}
|
||||||
|
defaultColumns = mysql.ColumnList{BooleanColumn, TinyIntColumn, UTinyIntColumn, SmallIntColumn, USmallIntColumn, MediumIntColumn, UMediumIntColumn, IntegerColumn, UIntegerColumn, BigIntColumn, UBigIntColumn, DecimalColumn, NumericColumn, FloatColumn, DoubleColumn, RealColumn, BitColumn, TimeColumn, DateColumn, DateTimeColumn, TimestampColumn, YearColumn, CharColumn, VarCharColumn, BinaryColumn, VarBinaryColumn, EnumColumn, SetColumn}
|
||||||
|
)
|
||||||
|
|
||||||
|
return allTypesTable{
|
||||||
|
Table: mysql.NewTable(schemaName, tableName, alias, allColumns...),
|
||||||
|
|
||||||
|
//Columns
|
||||||
|
Boolean: BooleanColumn,
|
||||||
|
BooleanPtr: BooleanPtrColumn,
|
||||||
|
TinyInt: TinyIntColumn,
|
||||||
|
UTinyInt: UTinyIntColumn,
|
||||||
|
SmallInt: SmallIntColumn,
|
||||||
|
USmallInt: USmallIntColumn,
|
||||||
|
MediumInt: MediumIntColumn,
|
||||||
|
UMediumInt: UMediumIntColumn,
|
||||||
|
Integer: IntegerColumn,
|
||||||
|
UInteger: UIntegerColumn,
|
||||||
|
BigInt: BigIntColumn,
|
||||||
|
UBigInt: UBigIntColumn,
|
||||||
|
TinyIntPtr: TinyIntPtrColumn,
|
||||||
|
UTinyIntPtr: UTinyIntPtrColumn,
|
||||||
|
SmallIntPtr: SmallIntPtrColumn,
|
||||||
|
USmallIntPtr: USmallIntPtrColumn,
|
||||||
|
MediumIntPtr: MediumIntPtrColumn,
|
||||||
|
UMediumIntPtr: UMediumIntPtrColumn,
|
||||||
|
IntegerPtr: IntegerPtrColumn,
|
||||||
|
UIntegerPtr: UIntegerPtrColumn,
|
||||||
|
BigIntPtr: BigIntPtrColumn,
|
||||||
|
UBigIntPtr: UBigIntPtrColumn,
|
||||||
|
Decimal: DecimalColumn,
|
||||||
|
DecimalPtr: DecimalPtrColumn,
|
||||||
|
Numeric: NumericColumn,
|
||||||
|
NumericPtr: NumericPtrColumn,
|
||||||
|
Float: FloatColumn,
|
||||||
|
FloatPtr: FloatPtrColumn,
|
||||||
|
Double: DoubleColumn,
|
||||||
|
DoublePtr: DoublePtrColumn,
|
||||||
|
Real: RealColumn,
|
||||||
|
RealPtr: RealPtrColumn,
|
||||||
|
Bit: BitColumn,
|
||||||
|
BitPtr: BitPtrColumn,
|
||||||
|
Time: TimeColumn,
|
||||||
|
TimePtr: TimePtrColumn,
|
||||||
|
Date: DateColumn,
|
||||||
|
DatePtr: DatePtrColumn,
|
||||||
|
DateTime: DateTimeColumn,
|
||||||
|
DateTimePtr: DateTimePtrColumn,
|
||||||
|
Timestamp: TimestampColumn,
|
||||||
|
TimestampPtr: TimestampPtrColumn,
|
||||||
|
Year: YearColumn,
|
||||||
|
YearPtr: YearPtrColumn,
|
||||||
|
Char: CharColumn,
|
||||||
|
CharPtr: CharPtrColumn,
|
||||||
|
VarChar: VarCharColumn,
|
||||||
|
VarCharPtr: VarCharPtrColumn,
|
||||||
|
Binary: BinaryColumn,
|
||||||
|
BinaryPtr: BinaryPtrColumn,
|
||||||
|
VarBinary: VarBinaryColumn,
|
||||||
|
VarBinaryPtr: VarBinaryPtrColumn,
|
||||||
|
Blob: BlobColumn,
|
||||||
|
BlobPtr: BlobPtrColumn,
|
||||||
|
Text: TextColumn,
|
||||||
|
TextPtr: TextPtrColumn,
|
||||||
|
Enum: EnumColumn,
|
||||||
|
EnumPtr: EnumPtrColumn,
|
||||||
|
Set: SetColumn,
|
||||||
|
SetPtr: SetPtrColumn,
|
||||||
|
JSON: JSONColumn,
|
||||||
|
JSONPtr: JSONPtrColumn,
|
||||||
|
|
||||||
|
AllColumns: allColumns,
|
||||||
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
jetmysql "github.com/go-jet/jet/v2/mysql"
|
jetmysql "github.com/go-jet/jet/v2/mysql"
|
||||||
"github.com/go-jet/jet/v2/stmtcache"
|
"github.com/go-jet/jet/v2/stmtcache"
|
||||||
"github.com/go-jet/jet/v2/tests/dbconfig"
|
"github.com/go-jet/jet/v2/tests/dbconfig"
|
||||||
|
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -21,12 +22,14 @@ var db *stmtcache.DB
|
||||||
|
|
||||||
var source string
|
var source string
|
||||||
var withStatementCaching bool
|
var withStatementCaching bool
|
||||||
|
var testRoot string
|
||||||
|
|
||||||
const MariaDB = "MariaDB"
|
const MariaDB = "MariaDB"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
source = os.Getenv("MY_SQL_SOURCE")
|
source = os.Getenv("MY_SQL_SOURCE")
|
||||||
withStatementCaching = os.Getenv("JET_TESTS_WITH_STMT_CACHE") == "true"
|
withStatementCaching = os.Getenv("JET_TESTS_WITH_STMT_CACHE") == "true"
|
||||||
|
testRoot = repo.GetTestsDirPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
func sourceIsMariaDB() bool {
|
func sourceIsMariaDB() bool {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"github.com/go-jet/jet/v2/internal/utils/ptr"
|
"github.com/go-jet/jet/v2/internal/utils/ptr"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
|
@ -485,6 +486,7 @@ func TestExpressionCast(t *testing.T) {
|
||||||
CAST(String("1999-01-08 04:05:06")).AS_TIMESTAMP(),
|
CAST(String("1999-01-08 04:05:06")).AS_TIMESTAMP(),
|
||||||
CAST(String("1999-01-08 04:05:06+01:00")).AS_TIMESTAMPZ(),
|
CAST(String("1999-01-08 04:05:06+01:00")).AS_TIMESTAMPZ(),
|
||||||
CAST(String("04:05:06")).AS_INTERVAL(),
|
CAST(String("04:05:06")).AS_INTERVAL(),
|
||||||
|
CAST(String("some text")).AS_BYTEA().EQ(Bytea([]byte("some text"))),
|
||||||
|
|
||||||
func() ProjectionList {
|
func() ProjectionList {
|
||||||
if sourceIsCockroachDB() {
|
if sourceIsCockroachDB() {
|
||||||
|
|
@ -538,7 +540,6 @@ func TestStringOperators(t *testing.T) {
|
||||||
AllTypes.Text.BETWEEN(String("min"), String("max")),
|
AllTypes.Text.BETWEEN(String("min"), String("max")),
|
||||||
AllTypes.Text.NOT_BETWEEN(AllTypes.VarChar, AllTypes.CharPtr),
|
AllTypes.Text.NOT_BETWEEN(AllTypes.VarChar, AllTypes.CharPtr),
|
||||||
AllTypes.Text.CONCAT(String("text2")),
|
AllTypes.Text.CONCAT(String("text2")),
|
||||||
AllTypes.Text.CONCAT(Int(11)),
|
|
||||||
AllTypes.Text.LIKE(String("abc")),
|
AllTypes.Text.LIKE(String("abc")),
|
||||||
AllTypes.Text.NOT_LIKE(String("_b_")),
|
AllTypes.Text.NOT_LIKE(String("_b_")),
|
||||||
AllTypes.Text.REGEXP_LIKE(String("^t")),
|
AllTypes.Text.REGEXP_LIKE(String("^t")),
|
||||||
|
|
@ -569,18 +570,18 @@ func TestStringOperators(t *testing.T) {
|
||||||
CONCAT(AllTypes.VarCharPtr, AllTypes.VarCharPtr, String("aaa"), Int(1)),
|
CONCAT(AllTypes.VarCharPtr, AllTypes.VarCharPtr, String("aaa"), Int(1)),
|
||||||
CONCAT(Bool(false), Int(1), Float(22.2), String("test test")),
|
CONCAT(Bool(false), Int(1), Float(22.2), String("test test")),
|
||||||
CONCAT_WS(String("string1"), Int(1), Float(11.22), String("bytea"), Bool(false)), //Float(11.12)),
|
CONCAT_WS(String("string1"), Int(1), Float(11.22), String("bytea"), Bool(false)), //Float(11.12)),
|
||||||
CONVERT(Bytea("bytea"), String("UTF8"), String("LATIN1")),
|
CONVERT(Bytea("bytea"), UTF8, LATIN1),
|
||||||
CONVERT(AllTypes.Bytea, String("UTF8"), String("LATIN1")),
|
CONVERT(AllTypes.Bytea, UTF8, LATIN1),
|
||||||
CONVERT_FROM(Bytea("text_in_utf8"), String("UTF8")),
|
CONVERT_FROM(Bytea("text_in_utf8"), UTF8),
|
||||||
CONVERT_TO(String("text_in_utf8"), String("UTF8")),
|
CONVERT_TO(String("text_in_utf8"), UTF8),
|
||||||
ENCODE(Bytea("123\000\001"), String("base64")),
|
ENCODE(Bytea("some text"), Escape),
|
||||||
DECODE(String("MTIzAAE="), String("base64")),
|
DECODE(String("MTIzAAE="), Base64),
|
||||||
FORMAT(String("Hello %s, %1$s"), String("World")),
|
FORMAT(String("Hello %s, %1$s"), String("World")),
|
||||||
INITCAP(String("hi THOMAS")),
|
INITCAP(String("hi THOMAS")),
|
||||||
LEFT(String("abcde"), Int(2)),
|
LEFT(String("abcde"), Int(2)),
|
||||||
RIGHT(String("abcde"), Int(2)),
|
RIGHT(String("abcde"), Int(2)),
|
||||||
LENGTH(Bytea("jose")),
|
LENGTH(Bytea("jose")),
|
||||||
LENGTH(Bytea("jose"), String("UTF8")),
|
LENGTH(Bytea("jose"), UTF8),
|
||||||
LPAD(String("Hi"), Int(5)),
|
LPAD(String("Hi"), Int(5)),
|
||||||
LPAD(String("Hi"), Int(5), String("xy")),
|
LPAD(String("Hi"), Int(5), String("xy")),
|
||||||
RPAD(String("Hi"), Int(5)),
|
RPAD(String("Hi"), Int(5)),
|
||||||
|
|
@ -601,6 +602,155 @@ func TestStringOperators(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlob(t *testing.T) {
|
||||||
|
|
||||||
|
var sampleBlob = Bytea([]byte{11, 0, 22, 33, 44})
|
||||||
|
var textBlob = Bytea([]byte("text blob"))
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
AllTypes.Bytea.EQ(sampleBlob),
|
||||||
|
AllTypes.Bytea.EQ(AllTypes.ByteaPtr),
|
||||||
|
AllTypes.Bytea.NOT_EQ(sampleBlob),
|
||||||
|
AllTypes.Bytea.GT(textBlob),
|
||||||
|
AllTypes.Bytea.GT_EQ(AllTypes.ByteaPtr),
|
||||||
|
AllTypes.Bytea.LT(AllTypes.ByteaPtr),
|
||||||
|
AllTypes.Bytea.LT_EQ(sampleBlob),
|
||||||
|
AllTypes.Bytea.BETWEEN(Bytea([]byte("min")), Bytea([]byte("max"))),
|
||||||
|
AllTypes.Bytea.NOT_BETWEEN(AllTypes.Bytea, AllTypes.ByteaPtr),
|
||||||
|
AllTypes.Bytea.CONCAT(textBlob),
|
||||||
|
|
||||||
|
func() ProjectionList {
|
||||||
|
if sourceIsCockroachDB() {
|
||||||
|
return ProjectionList{NULL}
|
||||||
|
}
|
||||||
|
// cockroach doesn't support currently
|
||||||
|
return ProjectionList{
|
||||||
|
AllTypes.Bytea.LIKE(Bytea("b'%pattern%'")),
|
||||||
|
AllTypes.Bytea.NOT_LIKE(Bytea("b'%pattern%'")),
|
||||||
|
|
||||||
|
BTRIM(AllTypes.Bytea, Bytea([]byte{33})),
|
||||||
|
RTRIM(AllTypes.ByteaPtr, sampleBlob),
|
||||||
|
LTRIM(sampleBlob, textBlob),
|
||||||
|
CONCAT(sampleBlob, AllTypes.ByteaPtr, textBlob),
|
||||||
|
BIT_COUNT(sampleBlob).EQ(Int(3)),
|
||||||
|
LENGTH(textBlob, UTF8).EQ(Int(4)),
|
||||||
|
|
||||||
|
CONVERT(textBlob, UTF8, WIN1252),
|
||||||
|
CONVERT(AllTypes.Bytea, UTF8, LATIN1).EQ(sampleBlob),
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
|
||||||
|
BIT_LENGTH(textBlob),
|
||||||
|
OCTET_LENGTH(textBlob),
|
||||||
|
|
||||||
|
GET_BIT(textBlob, Int(2)).EQ(Int(23)),
|
||||||
|
GET_BYTE(sampleBlob, Int(1)).EQ(Int(0)),
|
||||||
|
SET_BIT(textBlob, Int(1), Int(0)).EQ(sampleBlob),
|
||||||
|
SET_BYTE(textBlob, Int(1), Int(0)).EQ(textBlob),
|
||||||
|
LENGTH(sampleBlob),
|
||||||
|
|
||||||
|
SUBSTR(AllTypes.Bytea, Int(0), Int(2)),
|
||||||
|
|
||||||
|
MD5(AllTypes.Bytea),
|
||||||
|
SHA224(AllTypes.Bytea),
|
||||||
|
SHA256(AllTypes.Bytea),
|
||||||
|
SHA384(AllTypes.Bytea),
|
||||||
|
SHA512(AllTypes.Bytea),
|
||||||
|
|
||||||
|
ENCODE(sampleBlob, Base64),
|
||||||
|
DECODE(String("A234C12B"), Hex).EQ(sampleBlob),
|
||||||
|
|
||||||
|
CONVERT_FROM(AllTypes.ByteaPtr, UTF8).EQ(AllTypes.VarChar),
|
||||||
|
CONVERT_TO(AllTypes.Text, UTF8).NOT_EQ(textBlob),
|
||||||
|
|
||||||
|
RawBytea("DECODE(#1::text, #2)", RawArgs{
|
||||||
|
"#1": "A234C12B",
|
||||||
|
"#2": "hex",
|
||||||
|
}).EQ(sampleBlob),
|
||||||
|
).FROM(
|
||||||
|
AllTypes,
|
||||||
|
)
|
||||||
|
|
||||||
|
if !sourceIsCockroachDB() {
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
SELECT all_types.bytea = $1::bytea,
|
||||||
|
all_types.bytea = all_types.bytea_ptr,
|
||||||
|
all_types.bytea != $2::bytea,
|
||||||
|
all_types.bytea > $3::bytea,
|
||||||
|
all_types.bytea >= all_types.bytea_ptr,
|
||||||
|
all_types.bytea < all_types.bytea_ptr,
|
||||||
|
all_types.bytea <= $4::bytea,
|
||||||
|
all_types.bytea BETWEEN $5::bytea AND $6::bytea,
|
||||||
|
all_types.bytea NOT BETWEEN all_types.bytea AND all_types.bytea_ptr,
|
||||||
|
all_types.bytea || $7::bytea,
|
||||||
|
all_types.bytea LIKE $8::bytea,
|
||||||
|
all_types.bytea NOT LIKE $9::bytea,
|
||||||
|
BTRIM(all_types.bytea, $10::bytea),
|
||||||
|
RTRIM(all_types.bytea_ptr, $11::bytea),
|
||||||
|
LTRIM($12::bytea, $13::bytea),
|
||||||
|
CONCAT($14::bytea, all_types.bytea_ptr, $15::bytea),
|
||||||
|
BIT_COUNT($16::bytea) = $17,
|
||||||
|
LENGTH($18::bytea, $19::text) = $20,
|
||||||
|
CONVERT($21::bytea, $22::text, $23::text),
|
||||||
|
CONVERT(all_types.bytea, $24::text, $25::text) = $26::bytea,
|
||||||
|
BIT_LENGTH($27::bytea),
|
||||||
|
OCTET_LENGTH($28::bytea),
|
||||||
|
GET_BIT($29::bytea, $30) = $31,
|
||||||
|
GET_BYTE($32::bytea, $33) = $34,
|
||||||
|
SET_BIT($35::bytea, $36, $37) = $38::bytea,
|
||||||
|
SET_BYTE($39::bytea, $40, $41) = $42::bytea,
|
||||||
|
LENGTH($43::bytea),
|
||||||
|
SUBSTR(all_types.bytea, $44, $45),
|
||||||
|
MD5(all_types.bytea),
|
||||||
|
SHA224(all_types.bytea),
|
||||||
|
SHA256(all_types.bytea),
|
||||||
|
SHA384(all_types.bytea),
|
||||||
|
SHA512(all_types.bytea),
|
||||||
|
ENCODE($46::bytea, $47::text),
|
||||||
|
DECODE($48::text, $49::text) = $50::bytea,
|
||||||
|
CONVERT_FROM(all_types.bytea_ptr, $51::text) = all_types.var_char,
|
||||||
|
CONVERT_TO(all_types.text, $52::text) != $53::bytea,
|
||||||
|
(DECODE($54::text, $55)) = $56::bytea
|
||||||
|
FROM test_sample.all_types;
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dest []struct{}
|
||||||
|
err := stmt.Query(db, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlobConversion(t *testing.T) {
|
||||||
|
|
||||||
|
nonPrintable := []byte{11, 22, 33, 44, 55}
|
||||||
|
printable := []byte("this is blob")
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
Bytea(nonPrintable).AS("non_printable"),
|
||||||
|
Bytea(printable).AS("printable"),
|
||||||
|
|
||||||
|
ENCODE(Bytea(nonPrintable), Base64).AS("non_printable_base64"),
|
||||||
|
CONVERT_FROM(Bytea(printable), UTF8).AS("printable_utf8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
var dest struct {
|
||||||
|
NonPrintable []byte
|
||||||
|
Printable []byte
|
||||||
|
|
||||||
|
NonPrintableBase64 []byte
|
||||||
|
PrintableUTF8 string
|
||||||
|
}
|
||||||
|
|
||||||
|
err := stmt.Query(db, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, dest.NonPrintable, nonPrintable)
|
||||||
|
require.Equal(t, dest.Printable, printable)
|
||||||
|
require.Equal(t, dest.NonPrintableBase64, []byte(base64.StdEncoding.EncodeToString(nonPrintable)))
|
||||||
|
require.Equal(t, dest.PrintableUTF8, string(printable))
|
||||||
|
}
|
||||||
|
|
||||||
func TestBoolOperators(t *testing.T) {
|
func TestBoolOperators(t *testing.T) {
|
||||||
query := AllTypes.SELECT(
|
query := AllTypes.SELECT(
|
||||||
AllTypes.Boolean.EQ(AllTypes.BooleanPtr).AS("EQ1"),
|
AllTypes.Boolean.EQ(AllTypes.BooleanPtr).AS("EQ1"),
|
||||||
|
|
@ -1208,6 +1358,106 @@ SELECT ROW($1::integer, $2::real, $3::text) AS "row",
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAllTypesSubQueryFrom(t *testing.T) {
|
||||||
|
subQuery := SELECT(
|
||||||
|
AllTypes.Boolean,
|
||||||
|
AllTypes.Integer,
|
||||||
|
AllTypes.DoublePrecision,
|
||||||
|
AllTypes.Text,
|
||||||
|
AllTypes.Date,
|
||||||
|
AllTypes.Time,
|
||||||
|
AllTypes.Timez,
|
||||||
|
AllTypes.Timestamp,
|
||||||
|
AllTypes.Interval,
|
||||||
|
AllTypes.Bytea,
|
||||||
|
).FROM(
|
||||||
|
AllTypes,
|
||||||
|
).AsTable("subQuery")
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
AllTypes.Boolean.From(subQuery),
|
||||||
|
AllTypes.Integer.From(subQuery),
|
||||||
|
AllTypes.DoublePrecision.From(subQuery),
|
||||||
|
AllTypes.Text.From(subQuery),
|
||||||
|
AllTypes.Date.From(subQuery),
|
||||||
|
AllTypes.Time.From(subQuery),
|
||||||
|
AllTypes.Timez.From(subQuery),
|
||||||
|
AllTypes.Timestamp.From(subQuery),
|
||||||
|
AllTypes.Interval.From(subQuery),
|
||||||
|
AllTypes.Bytea.From(subQuery),
|
||||||
|
).FROM(
|
||||||
|
subQuery,
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
|
||||||
|
"subQuery"."all_types.integer" AS "all_types.integer",
|
||||||
|
"subQuery"."all_types.double_precision" AS "all_types.double_precision",
|
||||||
|
"subQuery"."all_types.text" AS "all_types.text",
|
||||||
|
"subQuery"."all_types.date" AS "all_types.date",
|
||||||
|
"subQuery"."all_types.time" AS "all_types.time",
|
||||||
|
"subQuery"."all_types.timez" AS "all_types.timez",
|
||||||
|
"subQuery"."all_types.timestamp" AS "all_types.timestamp",
|
||||||
|
"subQuery"."all_types.interval" AS "all_types.interval",
|
||||||
|
"subQuery"."all_types.bytea" AS "all_types.bytea"
|
||||||
|
FROM (
|
||||||
|
SELECT all_types.boolean AS "all_types.boolean",
|
||||||
|
all_types.integer AS "all_types.integer",
|
||||||
|
all_types.double_precision AS "all_types.double_precision",
|
||||||
|
all_types.text AS "all_types.text",
|
||||||
|
all_types.date AS "all_types.date",
|
||||||
|
all_types.time AS "all_types.time",
|
||||||
|
all_types.timez AS "all_types.timez",
|
||||||
|
all_types.timestamp AS "all_types.timestamp",
|
||||||
|
all_types.interval AS "all_types.interval",
|
||||||
|
all_types.bytea AS "all_types.bytea"
|
||||||
|
FROM test_sample.all_types
|
||||||
|
) AS "subQuery";
|
||||||
|
`)
|
||||||
|
|
||||||
|
var dest []model.AllTypes
|
||||||
|
|
||||||
|
err := stmt.Query(db, &dest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllTypesUpdateSet(t *testing.T) {
|
||||||
|
|
||||||
|
stmt := AllTypes.UPDATE().
|
||||||
|
SET(
|
||||||
|
AllTypes.Boolean.SET(Bool(false)),
|
||||||
|
AllTypes.Integer.SET(Int(2)),
|
||||||
|
AllTypes.DoublePrecision.SET(Float(2.22)),
|
||||||
|
AllTypes.Text.SET(Text("some text")),
|
||||||
|
AllTypes.Date.SET(DateT(time.Now())),
|
||||||
|
AllTypes.Time.SET(TimeT(time.Now())),
|
||||||
|
AllTypes.Timez.SET(TimezT(time.Now())),
|
||||||
|
AllTypes.Timestamp.SET(TimestampT(time.Now())),
|
||||||
|
AllTypes.Interval.SET(INTERVAL(1, HOUR)),
|
||||||
|
AllTypes.Bytea.SET(Bytea([]byte{11, 22, 33, 44})),
|
||||||
|
).WHERE(Bool(true))
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
UPDATE test_sample.all_types
|
||||||
|
SET boolean = $1::boolean,
|
||||||
|
integer = $2,
|
||||||
|
double_precision = $3,
|
||||||
|
text = $4::text,
|
||||||
|
date = $5::date,
|
||||||
|
time = $6::time without time zone,
|
||||||
|
timez = $7::time with time zone,
|
||||||
|
timestamp = $8::timestamp without time zone,
|
||||||
|
interval = INTERVAL '1 HOUR',
|
||||||
|
bytea = $9::bytea
|
||||||
|
WHERE $10::boolean;
|
||||||
|
`)
|
||||||
|
|
||||||
|
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
|
||||||
|
_, err := stmt.Exec(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSubQueryColumnReference(t *testing.T) {
|
func TestSubQueryColumnReference(t *testing.T) {
|
||||||
type expected struct {
|
type expected struct {
|
||||||
sql string
|
sql string
|
||||||
|
|
|
||||||
|
|
@ -974,8 +974,8 @@ type allTypesTable struct {
|
||||||
Char postgres.ColumnString
|
Char postgres.ColumnString
|
||||||
TextPtr postgres.ColumnString
|
TextPtr postgres.ColumnString
|
||||||
Text postgres.ColumnString
|
Text postgres.ColumnString
|
||||||
ByteaPtr postgres.ColumnString
|
ByteaPtr postgres.ColumnBytea
|
||||||
Bytea postgres.ColumnString
|
Bytea postgres.ColumnBytea
|
||||||
TimestampzPtr postgres.ColumnTimestampz
|
TimestampzPtr postgres.ColumnTimestampz
|
||||||
Timestampz postgres.ColumnTimestampz
|
Timestampz postgres.ColumnTimestampz
|
||||||
TimestampPtr postgres.ColumnTimestamp
|
TimestampPtr postgres.ColumnTimestamp
|
||||||
|
|
@ -1078,8 +1078,8 @@ func newAllTypesTableImpl(schemaName, tableName, alias string) allTypesTable {
|
||||||
CharColumn = postgres.StringColumn("char")
|
CharColumn = postgres.StringColumn("char")
|
||||||
TextPtrColumn = postgres.StringColumn("text_ptr")
|
TextPtrColumn = postgres.StringColumn("text_ptr")
|
||||||
TextColumn = postgres.StringColumn("text")
|
TextColumn = postgres.StringColumn("text")
|
||||||
ByteaPtrColumn = postgres.StringColumn("bytea_ptr")
|
ByteaPtrColumn = postgres.ByteaColumn("bytea_ptr")
|
||||||
ByteaColumn = postgres.StringColumn("bytea")
|
ByteaColumn = postgres.ByteaColumn("bytea")
|
||||||
TimestampzPtrColumn = postgres.TimestampzColumn("timestampz_ptr")
|
TimestampzPtrColumn = postgres.TimestampzColumn("timestampz_ptr")
|
||||||
TimestampzColumn = postgres.TimestampzColumn("timestampz")
|
TimestampzColumn = postgres.TimestampzColumn("timestampz")
|
||||||
TimestampPtrColumn = postgres.TimestampColumn("timestamp_ptr")
|
TimestampPtrColumn = postgres.TimestampColumn("timestamp_ptr")
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ const CockroachDB = "COCKROACH_DB"
|
||||||
func init() {
|
func init() {
|
||||||
source = os.Getenv("PG_SOURCE")
|
source = os.Getenv("PG_SOURCE")
|
||||||
withStatementCaching = os.Getenv("JET_TESTS_WITH_STMT_CACHE") == "true"
|
withStatementCaching = os.Getenv("JET_TESTS_WITH_STMT_CACHE") == "true"
|
||||||
|
testRoot = repo.GetTestsDirPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
func sourceIsCockroachDB() bool {
|
func sourceIsCockroachDB() bool {
|
||||||
|
|
@ -46,8 +47,6 @@ func skipForCockroachDB(t *testing.T) {
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
defer profile.Start().Stop()
|
defer profile.Start().Stop()
|
||||||
|
|
||||||
setTestRoot()
|
|
||||||
|
|
||||||
for _, driverName := range []string{"postgres", "pgx"} {
|
for _, driverName := range []string{"postgres", "pgx"} {
|
||||||
|
|
||||||
fmt.Printf("\nRunning postgres tests for driver: %s, caching enabled: %t \n", driverName, withStatementCaching)
|
fmt.Printf("\nRunning postgres tests for driver: %s, caching enabled: %t \n", driverName, withStatementCaching)
|
||||||
|
|
@ -94,10 +93,6 @@ func getConnectionString() string {
|
||||||
return dbconfig.PostgresConnectString
|
return dbconfig.PostgresConnectString
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTestRoot() {
|
|
||||||
testRoot = repo.GetTestsDirPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
var loggedSQL string
|
var loggedSQL string
|
||||||
var loggedSQLArgs []interface{}
|
var loggedSQLArgs []interface{}
|
||||||
var loggedDebugSQL string
|
var loggedDebugSQL string
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"github.com/go-jet/jet/v2/internal/testutils"
|
"github.com/go-jet/jet/v2/internal/testutils"
|
||||||
"github.com/go-jet/jet/v2/internal/utils/ptr"
|
"github.com/go-jet/jet/v2/internal/utils/ptr"
|
||||||
. "github.com/go-jet/jet/v2/sqlite"
|
. "github.com/go-jet/jet/v2/sqlite"
|
||||||
|
|
@ -18,7 +19,7 @@ import (
|
||||||
|
|
||||||
func TestAllTypes(t *testing.T) {
|
func TestAllTypes(t *testing.T) {
|
||||||
|
|
||||||
dest := []model.AllTypes{}
|
var dest []model.AllTypes
|
||||||
|
|
||||||
err := SELECT(AllTypes.AllColumns).
|
err := SELECT(AllTypes.AllColumns).
|
||||||
FROM(AllTypes).
|
FROM(AllTypes).
|
||||||
|
|
@ -571,12 +572,102 @@ func TestStringOperators(t *testing.T) {
|
||||||
SUBSTR(AllTypes.CharPtr, Int(3), Int(2)),
|
SUBSTR(AllTypes.CharPtr, Int(3), Int(2)),
|
||||||
).FROM(AllTypes)
|
).FROM(AllTypes)
|
||||||
|
|
||||||
dest := []struct{}{}
|
var dest []struct{}
|
||||||
err := query.Query(sampleDB, &dest)
|
err := query.Query(sampleDB, &dest)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlob(t *testing.T) {
|
||||||
|
|
||||||
|
var sampleBlob = Blob([]byte{11, 0, 22, 33, 44})
|
||||||
|
var textBlob = Blob([]byte("text blob"))
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
AllTypes.Blob.EQ(sampleBlob),
|
||||||
|
AllTypes.Blob.EQ(AllTypes.BlobPtr),
|
||||||
|
AllTypes.Blob.NOT_EQ(sampleBlob),
|
||||||
|
AllTypes.Blob.GT(textBlob),
|
||||||
|
AllTypes.Blob.GT_EQ(AllTypes.BlobPtr),
|
||||||
|
AllTypes.Blob.LT(AllTypes.BlobPtr),
|
||||||
|
AllTypes.Blob.LT_EQ(sampleBlob),
|
||||||
|
AllTypes.Blob.BETWEEN(Blob([]byte("min")), Blob([]byte("max"))),
|
||||||
|
AllTypes.Blob.NOT_BETWEEN(AllTypes.Blob, AllTypes.BlobPtr),
|
||||||
|
AllTypes.Blob.CONCAT(textBlob),
|
||||||
|
AllTypes.Blob.LIKE(AllTypes.BlobPtr),
|
||||||
|
AllTypes.Blob.NOT_LIKE(sampleBlob),
|
||||||
|
|
||||||
|
RTRIM(AllTypes.BlobPtr, sampleBlob),
|
||||||
|
LTRIM(sampleBlob, textBlob),
|
||||||
|
LENGTH(sampleBlob),
|
||||||
|
OCTET_LENGTH(textBlob),
|
||||||
|
SUBSTR(AllTypes.Blob, Int(0), Int(2)),
|
||||||
|
|
||||||
|
HEX(AllTypes.Blob),
|
||||||
|
UNHEX(AllTypes.Text),
|
||||||
|
).FROM(
|
||||||
|
AllTypes,
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
SELECT all_types.blob = X'0b0016212c',
|
||||||
|
all_types.blob = all_types.blob_ptr,
|
||||||
|
all_types.blob != X'0b0016212c',
|
||||||
|
all_types.blob > X'7465787420626c6f62',
|
||||||
|
all_types.blob >= all_types.blob_ptr,
|
||||||
|
all_types.blob < all_types.blob_ptr,
|
||||||
|
all_types.blob <= X'0b0016212c',
|
||||||
|
all_types.blob BETWEEN X'6d696e' AND X'6d6178',
|
||||||
|
all_types.blob NOT BETWEEN all_types.blob AND all_types.blob_ptr,
|
||||||
|
all_types.blob || X'7465787420626c6f62',
|
||||||
|
all_types.blob LIKE all_types.blob_ptr,
|
||||||
|
all_types.blob NOT LIKE X'0b0016212c',
|
||||||
|
RTRIM(all_types.blob_ptr, X'0b0016212c'),
|
||||||
|
LTRIM(X'0b0016212c', X'7465787420626c6f62'),
|
||||||
|
LENGTH(X'0b0016212c'),
|
||||||
|
OCTET_LENGTH(X'7465787420626c6f62'),
|
||||||
|
SUBSTR(all_types.blob, 0, 2),
|
||||||
|
HEX(all_types.blob),
|
||||||
|
UNHEX(all_types.text)
|
||||||
|
FROM all_types;
|
||||||
|
`)
|
||||||
|
|
||||||
|
var dest []struct{}
|
||||||
|
err := stmt.Query(sampleDB, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlobConversion(t *testing.T) {
|
||||||
|
|
||||||
|
nonPrintable := []byte{0x11, 0x22, 0x33, 0x44, 0x55}
|
||||||
|
printable := []byte("this is blob")
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
Blob(nonPrintable).AS("non_printable"),
|
||||||
|
Blob(printable).AS("printable"),
|
||||||
|
|
||||||
|
HEX(Blob(nonPrintable)).AS("non_printable_hex"),
|
||||||
|
UNHEX(String("1122334455")).AS("non_printable_unhex"),
|
||||||
|
)
|
||||||
|
|
||||||
|
var dest struct {
|
||||||
|
NonPrintable []byte
|
||||||
|
Printable []byte
|
||||||
|
|
||||||
|
NonPrintableHex string
|
||||||
|
NonPrintableUnHex []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
err := stmt.Query(db, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, dest.NonPrintable, nonPrintable)
|
||||||
|
require.Equal(t, dest.Printable, printable)
|
||||||
|
require.Equal(t, dest.NonPrintableHex, hex.EncodeToString(nonPrintable))
|
||||||
|
require.Equal(t, dest.NonPrintableUnHex, nonPrintable)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReservedWord(t *testing.T) {
|
func TestReservedWord(t *testing.T) {
|
||||||
stmt := SELECT(ReservedWords.AllColumns).
|
stmt := SELECT(ReservedWords.AllColumns).
|
||||||
FROM(ReservedWords)
|
FROM(ReservedWords)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue