Encode json values implicitly in the sql queries according the golang json package spec.
This commit is contained in:
parent
9616bb5cfe
commit
17646ca99c
54 changed files with 1446 additions and 744 deletions
|
|
@ -43,29 +43,82 @@ func TestAllTypesJSON(t *testing.T) {
|
|||
AllTypes.JSONPtr,
|
||||
AllTypes.Bit,
|
||||
AllTypes.BitPtr,
|
||||
AllTypes.Blob,
|
||||
AllTypes.BlobPtr,
|
||||
AllTypes.Binary,
|
||||
AllTypes.BinaryPtr,
|
||||
AllTypes.VarBinary,
|
||||
AllTypes.VarBinaryPtr,
|
||||
),
|
||||
CAST(AllTypes.JSON).AS_CHAR().AS("Json"),
|
||||
CAST(AllTypes.JSONPtr).AS_CHAR().AS("JsonPtr"),
|
||||
CAST(AllTypes.Bit).AS_CHAR().AS("Bit"),
|
||||
CAST(AllTypes.BitPtr).AS_CHAR().AS("BitPtr"),
|
||||
|
||||
// TODO: remove when binary string is implemented
|
||||
CONCAT(String("\\x"), HEX(AllTypes.Blob)).AS("Blob"),
|
||||
CONCAT(String("\\x"), HEX(AllTypes.BlobPtr)).AS("BlobPtr"),
|
||||
|
||||
CONCAT(String("\\x"), HEX(AllTypes.Binary)).AS("Binary"),
|
||||
CONCAT(String("\\x"), HEX(AllTypes.BinaryPtr)).AS("BinaryPtr"),
|
||||
|
||||
CONCAT(String("\\x"), HEX(AllTypes.VarBinary)).AS("VarBinary"),
|
||||
CONCAT(String("\\x"), HEX(AllTypes.VarBinaryPtr)).AS("VarBinaryPtr"),
|
||||
).FROM(AllTypes)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, strings.ReplaceAll(`
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'id', all_types.id,
|
||||
'boolean', all_types.boolean = 1,
|
||||
'booleanPtr', all_types.boolean_ptr = 1,
|
||||
'tinyInt', all_types.tiny_int,
|
||||
'uTinyInt', all_types.u_tiny_int,
|
||||
'smallInt', all_types.small_int,
|
||||
'uSmallInt', all_types.u_small_int,
|
||||
'mediumInt', all_types.medium_int,
|
||||
'uMediumInt', all_types.u_medium_int,
|
||||
'integer', all_types.''integer'',
|
||||
'uInteger', all_types.u_integer,
|
||||
'bigInt', all_types.big_int,
|
||||
'uBigInt', all_types.u_big_int,
|
||||
'tinyIntPtr', all_types.tiny_int_ptr,
|
||||
'uTinyIntPtr', all_types.u_tiny_int_ptr,
|
||||
'smallIntPtr', all_types.small_int_ptr,
|
||||
'uSmallIntPtr', all_types.u_small_int_ptr,
|
||||
'mediumIntPtr', all_types.medium_int_ptr,
|
||||
'uMediumIntPtr', all_types.u_medium_int_ptr,
|
||||
'integerPtr', all_types.integer_ptr,
|
||||
'uIntegerPtr', all_types.u_integer_ptr,
|
||||
'bigIntPtr', all_types.big_int_ptr,
|
||||
'uBigIntPtr', all_types.u_big_int_ptr,
|
||||
'decimal', all_types.''decimal'',
|
||||
'decimalPtr', all_types.decimal_ptr,
|
||||
'numeric', all_types.''numeric'',
|
||||
'numericPtr', all_types.numeric_ptr,
|
||||
'float', all_types.''float'',
|
||||
'floatPtr', all_types.float_ptr,
|
||||
'double', all_types.''double'',
|
||||
'doublePtr', all_types.double_ptr,
|
||||
'real', all_types.''real'',
|
||||
'realPtr', all_types.real_ptr,
|
||||
'time', CONCAT('0000-01-01T', DATE_FORMAT(all_types.time,'%H:%i:%s.%fZ')),
|
||||
'timePtr', CONCAT('0000-01-01T', DATE_FORMAT(all_types.time_ptr,'%H:%i:%s.%fZ')),
|
||||
'date', CONCAT(DATE_FORMAT(all_types.date,'%Y-%m-%d'), 'T00:00:00Z'),
|
||||
'datePtr', CONCAT(DATE_FORMAT(all_types.date_ptr,'%Y-%m-%d'), 'T00:00:00Z'),
|
||||
'dateTime', DATE_FORMAT(all_types.date_time,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'dateTimePtr', DATE_FORMAT(all_types.date_time_ptr,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'timestamp', DATE_FORMAT(all_types.timestamp,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'timestampPtr', DATE_FORMAT(all_types.timestamp_ptr,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'year', all_types.year,
|
||||
'yearPtr', all_types.year_ptr,
|
||||
'char', all_types.''char'',
|
||||
'charPtr', all_types.char_ptr,
|
||||
'varChar', all_types.var_char,
|
||||
'varCharPtr', all_types.var_char_ptr,
|
||||
'binary', TO_BASE64(all_types.''binary''),
|
||||
'binaryPtr', TO_BASE64(all_types.binary_ptr),
|
||||
'varBinary', TO_BASE64(all_types.var_binary),
|
||||
'varBinaryPtr', TO_BASE64(all_types.var_binary_ptr),
|
||||
'blob', TO_BASE64(all_types.''blob''),
|
||||
'blobPtr', TO_BASE64(all_types.blob_ptr),
|
||||
'text', all_types.text,
|
||||
'textPtr', all_types.text_ptr,
|
||||
'enum', all_types.enum,
|
||||
'enumPtr', all_types.enum_ptr,
|
||||
'set', all_types.''set'',
|
||||
'setPtr', all_types.set_ptr,
|
||||
'Json', CAST(all_types.json AS CHAR),
|
||||
'JsonPtr', CAST(all_types.json_ptr AS CHAR),
|
||||
'Bit', CAST(all_types.bit AS CHAR),
|
||||
'BitPtr', CAST(all_types.bit_ptr AS CHAR)
|
||||
)) AS "json"
|
||||
FROM test_sample.all_types;
|
||||
`, "''", "`"))
|
||||
|
||||
var dest []model.AllTypes
|
||||
|
||||
err := stmt.QueryJSON(ctx, db, &dest)
|
||||
|
|
@ -76,7 +129,6 @@ func TestAllTypesJSON(t *testing.T) {
|
|||
dest[0].FloatPtr = ptr.Of(3.33)
|
||||
dest[1].Float = 3.33
|
||||
|
||||
//fmt.Println(allTypesJson)
|
||||
testutils.AssertJSON(t, dest, allTypesJson)
|
||||
}
|
||||
|
||||
|
|
@ -1182,6 +1234,118 @@ func TestAllTypesInsertOnDuplicateKeyUpdate(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAllTypesSubQueryFrom(t *testing.T) {
|
||||
subQuery := SELECT(
|
||||
AllTypes.Boolean,
|
||||
AllTypes.Integer,
|
||||
AllTypes.Double,
|
||||
AllTypes.Text,
|
||||
AllTypes.Date,
|
||||
AllTypes.Time,
|
||||
AllTypes.Timestamp,
|
||||
AllTypes.Blob,
|
||||
).FROM(
|
||||
AllTypes,
|
||||
).AsTable("sub_query")
|
||||
|
||||
stmt := SELECT(
|
||||
AllTypes.Boolean.From(subQuery),
|
||||
AllTypes.Integer.From(subQuery),
|
||||
AllTypes.Double.From(subQuery),
|
||||
AllTypes.Text.From(subQuery),
|
||||
AllTypes.Date.From(subQuery),
|
||||
AllTypes.Time.From(subQuery),
|
||||
AllTypes.Timestamp.From(subQuery),
|
||||
AllTypes.Blob.From(subQuery),
|
||||
).FROM(
|
||||
subQuery,
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, strings.ReplaceAll(`
|
||||
SELECT sub_query.''all_types.boolean'' AS "all_types.boolean",
|
||||
sub_query.''all_types.integer'' AS "all_types.integer",
|
||||
sub_query.''all_types.double'' AS "all_types.double",
|
||||
sub_query.''all_types.text'' AS "all_types.text",
|
||||
sub_query.''all_types.date'' AS "all_types.date",
|
||||
sub_query.''all_types.time'' AS "all_types.time",
|
||||
sub_query.''all_types.timestamp'' AS "all_types.timestamp",
|
||||
sub_query.''all_types.blob'' AS "all_types.blob"
|
||||
FROM (
|
||||
SELECT all_types.boolean AS "all_types.boolean",
|
||||
all_types.''integer'' AS "all_types.integer",
|
||||
all_types.''double'' AS "all_types.double",
|
||||
all_types.text AS "all_types.text",
|
||||
all_types.date AS "all_types.date",
|
||||
all_types.time AS "all_types.time",
|
||||
all_types.timestamp AS "all_types.timestamp",
|
||||
all_types.''blob'' AS "all_types.blob"
|
||||
FROM test_sample.all_types
|
||||
) AS sub_query;
|
||||
`, "''", "`"))
|
||||
|
||||
var dest []model.AllTypes
|
||||
|
||||
err := stmt.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, dest)
|
||||
|
||||
t.Run("using SELECT_JSON", func(t *testing.T) {
|
||||
stmtJson := SELECT_JSON_ARR(
|
||||
AllTypes.Boolean.From(subQuery),
|
||||
AllTypes.Integer.From(subQuery),
|
||||
AllTypes.Double.From(subQuery),
|
||||
AllTypes.Text.From(subQuery),
|
||||
AllTypes.Date.From(subQuery),
|
||||
AllTypes.Time.From(subQuery),
|
||||
AllTypes.Timestamp.From(subQuery),
|
||||
AllTypes.Blob.From(subQuery),
|
||||
).FROM(
|
||||
subQuery,
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmtJson, strings.ReplaceAll(`
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'boolean', sub_query.''all_types.boolean'' = 1,
|
||||
'integer', sub_query.''all_types.integer'',
|
||||
'double', sub_query.''all_types.double'',
|
||||
'text', sub_query.''all_types.text'',
|
||||
'date', CONCAT(DATE_FORMAT(sub_query.''all_types.date'','%Y-%m-%d'), 'T00:00:00Z'),
|
||||
'time', CONCAT('0000-01-01T', DATE_FORMAT(sub_query.''all_types.time'','%H:%i:%s.%fZ')),
|
||||
'timestamp', DATE_FORMAT(sub_query.''all_types.timestamp'','%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'blob', TO_BASE64(sub_query.''all_types.blob'')
|
||||
)) AS "json"
|
||||
FROM (
|
||||
SELECT all_types.boolean AS "all_types.boolean",
|
||||
all_types.''integer'' AS "all_types.integer",
|
||||
all_types.''double'' AS "all_types.double",
|
||||
all_types.text AS "all_types.text",
|
||||
all_types.date AS "all_types.date",
|
||||
all_types.time AS "all_types.time",
|
||||
all_types.timestamp AS "all_types.timestamp",
|
||||
all_types.''blob'' AS "all_types.blob"
|
||||
FROM test_sample.all_types
|
||||
) AS sub_query;
|
||||
`, "''", "`"))
|
||||
|
||||
var destJson []model.AllTypes
|
||||
|
||||
err := stmtJson.QueryJSON(ctx, db, &destJson)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("using AllColumns()", func(t *testing.T) {
|
||||
stmtJsonAllColumns := SELECT_JSON_ARR(
|
||||
subQuery.AllColumns(),
|
||||
).FROM(
|
||||
subQuery,
|
||||
)
|
||||
|
||||
require.Equal(t, stmtJson.DebugSql(), stmtJsonAllColumns.DebugSql())
|
||||
})
|
||||
|
||||
testutils.AssertJsonEqual(t, dest, destJson)
|
||||
})
|
||||
}
|
||||
|
||||
var toInsert = model.AllTypes{
|
||||
Boolean: false,
|
||||
BooleanPtr: ptr.Of(true),
|
||||
|
|
|
|||
|
|
@ -23,10 +23,12 @@ func TestSelectJsonObj(t *testing.T) {
|
|||
WHERE(Actor.ActorID.EQ(Int(2)))
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
SELECT JSON_OBJECT('actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', actor.last_update) AS "json"
|
||||
SELECT JSON_OBJECT(
|
||||
'actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', DATE_FORMAT(actor.last_update,'%Y-%m-%dT%H:%i:%s.%fZ')
|
||||
) AS "json"
|
||||
FROM dvds.actor
|
||||
WHERE actor.actor_id = ?;
|
||||
`, int64(2))
|
||||
|
|
@ -57,30 +59,34 @@ func TestSelectJsonObj_NestedObj(t *testing.T) {
|
|||
)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
SELECT JSON_OBJECT('actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', actor.last_update,
|
||||
'LongestFilm', (
|
||||
SELECT JSON_OBJECT('filmID', film.film_id,
|
||||
'title', film.title,
|
||||
'description', film.description,
|
||||
'releaseYear', film.release_year,
|
||||
'languageID', film.language_id,
|
||||
'originalLanguageID', film.original_language_id,
|
||||
'rentalDuration', film.rental_duration,
|
||||
'rentalRate', film.rental_rate,
|
||||
'length', film.length,
|
||||
'replacementCost', film.replacement_cost,
|
||||
'rating', film.rating,
|
||||
'specialFeatures', film.special_features,
|
||||
'lastUpdate', film.last_update) AS "json"
|
||||
FROM dvds.film_actor
|
||||
INNER JOIN dvds.film ON (film.film_id = film_actor.film_id)
|
||||
WHERE actor.actor_id = film_actor.actor_id
|
||||
ORDER BY film.length DESC
|
||||
LIMIT ?
|
||||
)) AS "json"
|
||||
SELECT JSON_OBJECT(
|
||||
'actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', DATE_FORMAT(actor.last_update,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'LongestFilm', (
|
||||
SELECT JSON_OBJECT(
|
||||
'filmID', film.film_id,
|
||||
'title', film.title,
|
||||
'description', film.description,
|
||||
'releaseYear', film.release_year,
|
||||
'languageID', film.language_id,
|
||||
'originalLanguageID', film.original_language_id,
|
||||
'rentalDuration', film.rental_duration,
|
||||
'rentalRate', film.rental_rate,
|
||||
'length', film.length,
|
||||
'replacementCost', film.replacement_cost,
|
||||
'rating', film.rating,
|
||||
'specialFeatures', film.special_features,
|
||||
'lastUpdate', DATE_FORMAT(film.last_update,'%Y-%m-%dT%H:%i:%s.%fZ')
|
||||
) AS "json"
|
||||
FROM dvds.film_actor
|
||||
INNER JOIN dvds.film ON (film.film_id = film_actor.film_id)
|
||||
WHERE actor.actor_id = film_actor.actor_id
|
||||
ORDER BY film.length DESC
|
||||
LIMIT ?
|
||||
)
|
||||
) AS "json"
|
||||
FROM dvds.actor
|
||||
WHERE actor.actor_id = ?;
|
||||
`)
|
||||
|
|
@ -125,10 +131,12 @@ func TestSelectJsonArr(t *testing.T) {
|
|||
ORDER_BY(Actor.ActorID)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT('actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', actor.last_update)) AS "json"
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', DATE_FORMAT(actor.last_update,'%Y-%m-%dT%H:%i:%s.%fZ')
|
||||
)) AS "json"
|
||||
FROM dvds.actor
|
||||
ORDER BY actor.actor_id;
|
||||
`)
|
||||
|
|
@ -169,29 +177,33 @@ func TestSelectJsonArr_NestedArr(t *testing.T) {
|
|||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT('actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', actor.last_update,
|
||||
'Films', (
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT('filmID', film.film_id,
|
||||
'title', film.title,
|
||||
'description', film.description,
|
||||
'releaseYear', film.release_year,
|
||||
'languageID', film.language_id,
|
||||
'originalLanguageID', film.original_language_id,
|
||||
'rentalDuration', film.rental_duration,
|
||||
'rentalRate', film.rental_rate,
|
||||
'length', film.length,
|
||||
'replacementCost', film.replacement_cost,
|
||||
'rating', film.rating,
|
||||
'specialFeatures', film.special_features,
|
||||
'lastUpdate', film.last_update)) AS "json"
|
||||
FROM dvds.film_actor
|
||||
INNER JOIN dvds.film ON ((film.film_id = film_actor.film_id) AND (actor.actor_id = film_actor.actor_id))
|
||||
WHERE (film.film_id % 17) = 0
|
||||
ORDER BY film.length DESC
|
||||
))) AS "json"
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'actorID', actor.actor_id,
|
||||
'firstName', actor.first_name,
|
||||
'lastName', actor.last_name,
|
||||
'lastUpdate', DATE_FORMAT(actor.last_update,'%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'Films', (
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'filmID', film.film_id,
|
||||
'title', film.title,
|
||||
'description', film.description,
|
||||
'releaseYear', film.release_year,
|
||||
'languageID', film.language_id,
|
||||
'originalLanguageID', film.original_language_id,
|
||||
'rentalDuration', film.rental_duration,
|
||||
'rentalRate', film.rental_rate,
|
||||
'length', film.length,
|
||||
'replacementCost', film.replacement_cost,
|
||||
'rating', film.rating,
|
||||
'specialFeatures', film.special_features,
|
||||
'lastUpdate', DATE_FORMAT(film.last_update,'%Y-%m-%dT%H:%i:%s.%fZ')
|
||||
)) AS "json"
|
||||
FROM dvds.film_actor
|
||||
INNER JOIN dvds.film ON ((film.film_id = film_actor.film_id) AND (actor.actor_id = film_actor.actor_id))
|
||||
WHERE (film.film_id % 17) = 0
|
||||
ORDER BY film.length DESC
|
||||
)
|
||||
)) AS "json"
|
||||
FROM dvds.actor
|
||||
WHERE actor.actor_id BETWEEN 1 AND 3
|
||||
ORDER BY actor.actor_id;
|
||||
|
|
@ -337,22 +349,26 @@ func TestSelectJson_GroupBy(t *testing.T) {
|
|||
).FROM(subQuery)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.ReplaceAll(`
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT('customerID', customers_info.""customer.customer_id"",
|
||||
'storeID', customers_info.""customer.store_id"",
|
||||
'firstName', customers_info.""customer.first_name"",
|
||||
'lastName', customers_info.""customer.last_name"",
|
||||
'email', customers_info.""customer.email"",
|
||||
'addressID', customers_info.""customer.address_id"",
|
||||
'active', customers_info.""customer.active"",
|
||||
'createDate', customers_info.""customer.create_date"",
|
||||
'lastUpdate', customers_info.""customer.last_update"",
|
||||
'amount', (
|
||||
SELECT JSON_OBJECT('sum', customers_info.sum,
|
||||
'avg', customers_info.avg,
|
||||
'max', customers_info.max,
|
||||
'min', customers_info.min,
|
||||
'count', customers_info.count) AS "json"
|
||||
))) AS "json"
|
||||
SELECT JSON_ARRAYAGG(JSON_OBJECT(
|
||||
'customerID', customers_info.''customer.customer_id'',
|
||||
'storeID', customers_info.''customer.store_id'',
|
||||
'firstName', customers_info.''customer.first_name'',
|
||||
'lastName', customers_info.''customer.last_name'',
|
||||
'email', customers_info.''customer.email'',
|
||||
'addressID', customers_info.''customer.address_id'',
|
||||
'active', customers_info.''customer.active'' = 1,
|
||||
'createDate', DATE_FORMAT(customers_info.''customer.create_date'','%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'lastUpdate', DATE_FORMAT(customers_info.''customer.last_update'','%Y-%m-%dT%H:%i:%s.%fZ'),
|
||||
'amount', (
|
||||
SELECT JSON_OBJECT(
|
||||
'sum', customers_info.sum,
|
||||
'avg', customers_info.avg,
|
||||
'max', customers_info.max,
|
||||
'min', customers_info.min,
|
||||
'count', customers_info.count
|
||||
) AS "json"
|
||||
)
|
||||
)) AS "json"
|
||||
FROM (
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
|
|
@ -374,7 +390,7 @@ FROM (
|
|||
HAVING SUM(payment.amount) > 125
|
||||
ORDER BY customer.customer_id, SUM(payment.amount) ASC
|
||||
) AS customers_info;
|
||||
`, `""`, "`"))
|
||||
`, "''", "`"))
|
||||
|
||||
var dest []struct {
|
||||
model.Customer
|
||||
|
|
@ -389,7 +405,6 @@ FROM (
|
|||
}
|
||||
|
||||
err := stmt.QueryJSON(ctx, db, &dest)
|
||||
fmt.Println(err)
|
||||
require.Nil(t, err)
|
||||
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/mysql/customer_payment_sum.json")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue