Add SQL function string.slug

This commit is contained in:
Tobie Morgan Hitchcock 2018-09-11 13:18:19 +01:00
parent 44d2fc129f
commit 9bab9f3ce7
5 changed files with 177 additions and 0 deletions

View file

@ -166,6 +166,7 @@ var funcs = map[string]map[int]interface{}{
"string.reverse": {1: nil},
"string.search": {2: nil},
"string.slice": {3: nil},
"string.slug": {1: nil, 2: nil},
"string.split": {2: nil},
"string.startsWith": {2: nil},
"string.substr": {3: nil},

View file

@ -198,6 +198,8 @@ func Run(ctx context.Context, name string, args ...interface{}) (interface{}, er
return stringSearch(ctx, args...)
case "string.slice":
return stringSlice(ctx, args...)
case "string.slug":
return stringSlug(ctx, args...)
case "string.split":
return stringSplit(ctx, args...)
case "string.startsWith":

View file

@ -20,6 +20,7 @@ import (
"strings"
"github.com/abcum/surreal/util/ints"
"github.com/abcum/surreal/util/slug"
"github.com/abcum/surreal/util/text"
)
@ -138,6 +139,19 @@ func stringSlice(ctx context.Context, args ...interface{}) (interface{}, error)
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) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])

76
util/slug/lang.go Normal file
View 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
View 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()
}