Make sure mysql select json object keys are escaped.

This commit is contained in:
go-jet 2026-05-04 12:34:29 +02:00
parent 1c2a595750
commit a1d7684fc1
4 changed files with 96 additions and 1 deletions

View file

@ -112,7 +112,8 @@ func (s *SQLBuilder) WriteString(str string) {
// WriteJsonObjKey serializes json object key
func (s *SQLBuilder) WriteJsonObjKey(key string) {
s.WriteString(fmt.Sprintf(`'%s', `, key))
s.WriteString(stringQuote(key))
s.WriteString(", ")
}
// WriteIdentifier adds identifier to output SQL

View file

@ -45,6 +45,14 @@ func TestArgToString(t *testing.T) {
}()
}
func TestWriteJsonObjKeyEscapesStringLiteral(t *testing.T) {
s := &SQLBuilder{Dialect: defaultDialect}
s.WriteJsonObjKey("author's name")
require.Equal(t, "'author''s name', ", s.Buff.String())
}
func TestFallTrough(t *testing.T) {
require.Equal(t, FallTrough([]SerializeOption{ShortName}), []SerializeOption{ShortName})
require.Equal(t, FallTrough([]SerializeOption{SkipNewLine}), []SerializeOption(nil))

View file

@ -505,3 +505,47 @@ func TestSelectJson_ProjectionNotAliased(t *testing.T) {
}, "jet: expression need to be aliased when used as SELECT JSON projection.")
})
}
func TestSelectJsonObject_EscapesJsonKeys(t *testing.T) {
stmt := SELECT_JSON_OBJ(
String("value").AS("author"),
String("value").AS("author's name"),
String("value").AS("author''s name"),
String("value").AS("author \"name\""),
String("value").AS(`C:\tmp\file`),
String("value").AS("hello\nworld"),
String("value").AS("a'b\\\\c\\nd\\r\\x00e\\x1af"),
String("value").AS("žika 😀"),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT JSON_OBJECT(
'author', 'value',
'author''s name', 'value',
'author''''s name', 'value',
'author "name"', 'value',
'C:\tmp\file', 'value',
'hello
world', 'value',
'a''b\\c\nd\r\x00e\x1af', 'value',
'žika 😀', 'value'
) AS "json";
`)
var dest map[string]any
err := stmt.QueryContext(ctx, db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
{
"C:\tmpfile": "value",
"a'b\\c\nd\rx00ex1af": "value",
"author": "value",
"author \"name\"": "value",
"author''s name": "value",
"author's name": "value",
"hello\nworld": "value",
"žika 😀": "value"
}
`)
}

View file

@ -914,3 +914,45 @@ func TestSelectJson_InvalidJson(t *testing.T) {
err := stmt.QueryContext(ctx, db, &dest)
require.ErrorContains(t, err, "invalid json")
}
func TestSelectJsonObject_EscapesJsonKeys(t *testing.T) {
stmt := SELECT_JSON_OBJ(
String("value").AS("author"),
String("value").AS("author's name"),
String("value").AS("author''s name"),
String("value").AS(`C:\tmp\file`),
String("value").AS("hello\nworld"),
String("value").AS("a'b\\\\c\\nd\\r\\x00e\\x1af"),
String("value").AS("žika 😀"),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT row_to_json(records) AS "json"
FROM (
SELECT 'value'::text AS "author",
'value'::text AS "author's name",
'value'::text AS "author''s name",
'value'::text AS "C:\tmp\file",
'value'::text AS "hello
world",
'value'::text AS "a'b\\c\nd\r\x00e\x1af",
'value'::text AS "žika 😀"
) AS records;
`)
var dest map[string]any
err := stmt.QueryContext(ctx, db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
{
"C:\\tmp\\file": "value",
"a'b\\\\c\\nd\\r\\x00e\\x1af": "value",
"author": "value",
"author''s name": "value",
"author's name": "value",
"hello\nworld": "value",
"žika 😀": "value"
}
`)
}