5
5
// - LIKE and REGEXP operators,
6
6
// - collation sequences.
7
7
//
8
- // It also provides, from PostgreSQL:
9
- // - unaccent(),
10
- // - initcap().
11
- //
12
8
// The implementation is not 100% compatible with the [ICU extension]:
13
9
// - upper() and lower() use [strings.ToUpper], [strings.ToLower] and [cases];
14
10
// - the LIKE operator follows [strings.EqualFold] rules;
15
11
// - the REGEXP operator uses Go [regexp/syntax];
16
12
// - collation sequences use [collate].
17
13
//
14
+ // It also provides (approximately) from PostgreSQL:
15
+ // - casefold(),
16
+ // - initcap(),
17
+ // - normalize(),
18
+ // - unaccent().
19
+ //
18
20
// Expect subtle differences (e.g.) in the handling of Turkish case folding.
19
21
//
20
22
// [ICU extension]: https://sqlite.org/src/dir/ext/icu
@@ -48,21 +50,24 @@ var RegisterLike = true
48
50
// Register registers Unicode aware functions for a database connection.
49
51
func Register (db * sqlite3.Conn ) error {
50
52
const flags = sqlite3 .DETERMINISTIC | sqlite3 .INNOCUOUS
51
- var errs util. ErrorJoiner
53
+ var lkfn sqlite3. ScalarFunction
52
54
if RegisterLike {
53
- errs .Join (
54
- db .CreateFunction ("like" , 2 , flags , like ),
55
- db .CreateFunction ("like" , 3 , flags , like ))
55
+ lkfn = like
56
56
}
57
- errs .Join (
57
+ return errors .Join (
58
+ db .CreateFunction ("like" , 2 , flags , lkfn ),
59
+ db .CreateFunction ("like" , 3 , flags , lkfn ),
58
60
db .CreateFunction ("upper" , 1 , flags , upper ),
59
61
db .CreateFunction ("upper" , 2 , flags , upper ),
60
62
db .CreateFunction ("lower" , 1 , flags , lower ),
61
63
db .CreateFunction ("lower" , 2 , flags , lower ),
62
64
db .CreateFunction ("regexp" , 2 , flags , regex ),
63
65
db .CreateFunction ("initcap" , 1 , flags , initcap ),
64
66
db .CreateFunction ("initcap" , 2 , flags , initcap ),
67
+ db .CreateFunction ("casefold" , 1 , flags , casefold ),
65
68
db .CreateFunction ("unaccent" , 1 , flags , unaccent ),
69
+ db .CreateFunction ("normalize" , 1 , flags , normalize ),
70
+ db .CreateFunction ("normalize" , 2 , flags , normalize ),
66
71
db .CreateFunction ("icu_load_collation" , 2 , sqlite3 .DIRECTONLY ,
67
72
func (ctx sqlite3.Context , arg ... sqlite3.Value ) {
68
73
name := arg [1 ].Text ()
@@ -76,7 +81,6 @@ func Register(db *sqlite3.Conn) error {
76
81
return // notest
77
82
}
78
83
}))
79
- return errors .Join (errs ... )
80
84
}
81
85
82
86
// RegisterCollation registers a Unicode collation sequence for a database connection.
@@ -154,6 +158,10 @@ func initcap(ctx sqlite3.Context, arg ...sqlite3.Value) {
154
158
ctx .ResultRawText (cs .Bytes (arg [0 ].RawText ()))
155
159
}
156
160
161
+ func casefold (ctx sqlite3.Context , arg ... sqlite3.Value ) {
162
+ ctx .ResultRawText (cases .Fold ().Bytes (arg [0 ].RawText ()))
163
+ }
164
+
157
165
func unaccent (ctx sqlite3.Context , arg ... sqlite3.Value ) {
158
166
unaccent := transform .Chain (norm .NFD , runes .Remove (runes .In (unicode .Mn )), norm .NFC )
159
167
res , _ , err := transform .Bytes (unaccent , arg [0 ].RawText ())
@@ -164,6 +172,31 @@ func unaccent(ctx sqlite3.Context, arg ...sqlite3.Value) {
164
172
}
165
173
}
166
174
175
+ func normalize (ctx sqlite3.Context , arg ... sqlite3.Value ) {
176
+ form := norm .NFC
177
+ if len (arg ) > 1 {
178
+ switch strings .ToUpper (arg [1 ].Text ()) {
179
+ case "NFC" :
180
+ //
181
+ case "NFD" :
182
+ form = norm .NFD
183
+ case "NFKC" :
184
+ form = norm .NFKC
185
+ case "NFKD" :
186
+ form = norm .NFKD
187
+ default :
188
+ ctx .ResultError (util .ErrorString ("unicode: invalid form" ))
189
+ return
190
+ }
191
+ }
192
+ res , _ , err := transform .Bytes (form , arg [0 ].RawText ())
193
+ if err != nil {
194
+ ctx .ResultError (err ) // notest
195
+ } else {
196
+ ctx .ResultRawText (res )
197
+ }
198
+ }
199
+
167
200
func regex (ctx sqlite3.Context , arg ... sqlite3.Value ) {
168
201
re , ok := ctx .GetAuxData (0 ).(* regexp.Regexp )
169
202
if ! ok {
0 commit comments