Add SQL function string.slug
This commit is contained in:
parent
44d2fc129f
commit
9bab9f3ce7
5 changed files with 177 additions and 0 deletions
|
@ -166,6 +166,7 @@ var funcs = map[string]map[int]interface{}{
|
||||||
"string.reverse": {1: nil},
|
"string.reverse": {1: nil},
|
||||||
"string.search": {2: nil},
|
"string.search": {2: nil},
|
||||||
"string.slice": {3: nil},
|
"string.slice": {3: nil},
|
||||||
|
"string.slug": {1: nil, 2: nil},
|
||||||
"string.split": {2: nil},
|
"string.split": {2: nil},
|
||||||
"string.startsWith": {2: nil},
|
"string.startsWith": {2: nil},
|
||||||
"string.substr": {3: nil},
|
"string.substr": {3: nil},
|
||||||
|
|
|
@ -198,6 +198,8 @@ func Run(ctx context.Context, name string, args ...interface{}) (interface{}, er
|
||||||
return stringSearch(ctx, args...)
|
return stringSearch(ctx, args...)
|
||||||
case "string.slice":
|
case "string.slice":
|
||||||
return stringSlice(ctx, args...)
|
return stringSlice(ctx, args...)
|
||||||
|
case "string.slug":
|
||||||
|
return stringSlug(ctx, args...)
|
||||||
case "string.split":
|
case "string.split":
|
||||||
return stringSplit(ctx, args...)
|
return stringSplit(ctx, args...)
|
||||||
case "string.startsWith":
|
case "string.startsWith":
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/abcum/surreal/util/ints"
|
"github.com/abcum/surreal/util/ints"
|
||||||
|
"github.com/abcum/surreal/util/slug"
|
||||||
"github.com/abcum/surreal/util/text"
|
"github.com/abcum/surreal/util/text"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,6 +139,19 @@ func stringSlice(ctx context.Context, args ...interface{}) (interface{}, error)
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringSlug(ctx context.Context, args ...interface{}) (interface{}, error) {
|
||||||
|
switch len(args) {
|
||||||
|
case 1:
|
||||||
|
s, _ := ensureString(args[0])
|
||||||
|
return slug.Make(s), nil
|
||||||
|
case 2:
|
||||||
|
s, _ := ensureString(args[0])
|
||||||
|
l, _ := ensureString(args[1])
|
||||||
|
return slug.MakeLang(s, l), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func stringSplit(ctx context.Context, args ...interface{}) (interface{}, error) {
|
func stringSplit(ctx context.Context, args ...interface{}) (interface{}, error) {
|
||||||
s, _ := ensureString(args[0])
|
s, _ := ensureString(args[0])
|
||||||
p, _ := ensureString(args[1])
|
p, _ := ensureString(args[1])
|
||||||
|
|
76
util/slug/lang.go
Normal file
76
util/slug/lang.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright © 2016 Abcum Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package slug
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Merge language subs with the default one
|
||||||
|
for _, sub := range []*map[rune]string{&en, &de, &fr, &es, &nl, &pl, &gr} {
|
||||||
|
for key, value := range defaults {
|
||||||
|
(*sub)[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaults = map[rune]string{
|
||||||
|
'"': "",
|
||||||
|
'\'': "",
|
||||||
|
'’': "",
|
||||||
|
'‒': "-", // figure dash
|
||||||
|
'–': "-", // en dash
|
||||||
|
'—': "-", // em dash
|
||||||
|
'―': "-", // horizontal bar
|
||||||
|
}
|
||||||
|
|
||||||
|
var en = map[rune]string{
|
||||||
|
'&': "and",
|
||||||
|
'@': "at",
|
||||||
|
}
|
||||||
|
|
||||||
|
var de = map[rune]string{
|
||||||
|
'&': "und",
|
||||||
|
'@': "an",
|
||||||
|
}
|
||||||
|
|
||||||
|
var fr = map[rune]string{
|
||||||
|
'&': "et",
|
||||||
|
'@': "a",
|
||||||
|
}
|
||||||
|
|
||||||
|
var es = map[rune]string{
|
||||||
|
'&': "y",
|
||||||
|
'@': "en",
|
||||||
|
}
|
||||||
|
|
||||||
|
var nl = map[rune]string{
|
||||||
|
'&': "en",
|
||||||
|
'@': "at",
|
||||||
|
}
|
||||||
|
|
||||||
|
var pl = map[rune]string{
|
||||||
|
'&': "i",
|
||||||
|
'@': "na",
|
||||||
|
}
|
||||||
|
|
||||||
|
var gr = map[rune]string{
|
||||||
|
'&': "kai",
|
||||||
|
'η': "i",
|
||||||
|
'ή': "i",
|
||||||
|
'Η': "i",
|
||||||
|
'ι': "i",
|
||||||
|
'ί': "i",
|
||||||
|
'Ι': "i",
|
||||||
|
'χ': "x",
|
||||||
|
'Χ': "x",
|
||||||
|
}
|
84
util/slug/slug.go
Normal file
84
util/slug/slug.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright © 2016 Abcum Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package slug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rainycape/unidecode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
regexpUnicode = regexp.MustCompile("[^a-z0-9-_]")
|
||||||
|
regexpHyphens = regexp.MustCompile("-+")
|
||||||
|
)
|
||||||
|
|
||||||
|
func Make(s string) (slug string) {
|
||||||
|
return MakeLang(s, "en")
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeLang(s string, l string) (slug string) {
|
||||||
|
|
||||||
|
slug = strings.TrimSpace(s)
|
||||||
|
|
||||||
|
switch l {
|
||||||
|
case "de":
|
||||||
|
slug = substitute(slug, de)
|
||||||
|
case "en":
|
||||||
|
slug = substitute(slug, en)
|
||||||
|
case "pl":
|
||||||
|
slug = substitute(slug, pl)
|
||||||
|
case "es":
|
||||||
|
slug = substitute(slug, es)
|
||||||
|
case "gr":
|
||||||
|
slug = substitute(slug, gr)
|
||||||
|
case "nl":
|
||||||
|
slug = substitute(slug, nl)
|
||||||
|
default:
|
||||||
|
slug = substitute(slug, en)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all non ASCII symbols
|
||||||
|
slug = unidecode.Unidecode(slug)
|
||||||
|
|
||||||
|
// Format the text as lower case
|
||||||
|
slug = strings.ToLower(slug)
|
||||||
|
|
||||||
|
// Process remaining symbols
|
||||||
|
slug = regexpUnicode.ReplaceAllString(slug, "-")
|
||||||
|
|
||||||
|
// Process duplicated hyphens
|
||||||
|
slug = regexpHyphens.ReplaceAllString(slug, "-")
|
||||||
|
|
||||||
|
// Trim leading hyphens
|
||||||
|
slug = strings.Trim(slug, "-")
|
||||||
|
|
||||||
|
return slug
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func substitute(s string, sub map[rune]string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, c := range s {
|
||||||
|
if d, ok := sub[c]; ok {
|
||||||
|
buf.WriteString(d)
|
||||||
|
} else {
|
||||||
|
buf.WriteRune(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
Loading…
Reference in a new issue