Skip to content

Commit c731d18

Browse files
committed
fix: accept unicode cypher symbols
1 parent 37e6b4f commit c731d18

2 files changed

Lines changed: 29 additions & 7 deletions

File tree

query/v2/query_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,22 @@ func TestInvalidScopeAliasesReturnBuildErrors(t *testing.T) {
248248
require.ErrorContains(t, err, `scope alias node has invalid symbol "bad name"`)
249249
}
250250

251+
func TestUnicodeCypherSymbols(t *testing.T) {
252+
scope := v2.NewScope("路径", "节点", "起点", "关系", "终点")
253+
254+
preparedQuery, err := scope.New().Where(
255+
scope.Node().Property("name").Equals(v2.NamedParameter("名字", "alice")),
256+
).Return(
257+
v2.As(scope.Node().ID(), "标识"),
258+
).Build()
259+
require.NoError(t, err)
260+
261+
require.Equal(t, "match (节点) where 节点.name = $名字 return id(节点) as 标识", renderPrepared(t, preparedQuery))
262+
require.Equal(t, map[string]any{
263+
"名字": "alice",
264+
}, preparedQuery.Parameters)
265+
}
266+
251267
func TestInvalidRelationshipDirectionReturnsError(t *testing.T) {
252268
_, err := v2.New().WithRelationshipDirection(graph.Direction(99)).Return(v2.Relationship()).Build()
253269
require.ErrorContains(t, err, "unsupported relationship direction: invalid")

query/v2/util.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"sort"
88
"strconv"
99
"strings"
10+
"unicode"
11+
"unicode/utf8"
1012

1113
"github.com/specterops/dawgs/cypher/models/cypher"
1214
"github.com/specterops/dawgs/cypher/models/walk"
@@ -264,25 +266,29 @@ func sortedPropertyKeys(properties map[string]any) []string {
264266
return keys
265267
}
266268

267-
func isCypherSymbolStart(char byte) bool {
268-
return char == '_' || (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')
269+
func isCypherSymbolStart(char rune) bool {
270+
return char == '_' || unicode.IsLetter(char) || unicode.In(char, unicode.Nl, unicode.Pc)
269271
}
270272

271-
func isCypherSymbolPart(char byte) bool {
272-
return isCypherSymbolStart(char) || (char >= '0' && char <= '9')
273+
func isCypherSymbolPart(char rune) bool {
274+
return isCypherSymbolStart(char) || unicode.IsDigit(char) || unicode.In(char, unicode.Mark, unicode.Sc)
273275
}
274276

275277
func validateCypherSymbol(symbol, context string) error {
276278
if strings.TrimSpace(symbol) == "" {
277279
return fmt.Errorf("%s is empty", context)
278280
}
279281

280-
if !isCypherSymbolStart(symbol[0]) {
282+
if !utf8.ValidString(symbol) {
281283
return fmt.Errorf("%s has invalid symbol %q", context, symbol)
282284
}
283285

284-
for idx := 1; idx < len(symbol); idx++ {
285-
if !isCypherSymbolPart(symbol[idx]) {
286+
for idx, char := range symbol {
287+
if idx == 0 {
288+
if !isCypherSymbolStart(char) {
289+
return fmt.Errorf("%s has invalid symbol %q", context, symbol)
290+
}
291+
} else if !isCypherSymbolPart(char) {
286292
return fmt.Errorf("%s has invalid symbol %q", context, symbol)
287293
}
288294
}

0 commit comments

Comments
 (0)