Skip to content

Commit a6a3d98

Browse files
author
Dean Karn
authored
enhance coersion support (#16)
## [0.9.0] - 2023-06-17 ### Changed - Function signature of custom coercions to allow parsing more complex coercions types such as substr. ### Added - Added new `_substr_[n:n]` COERCE identifier.
1 parent 828277f commit a6a3d98

File tree

10 files changed

+336
-123
lines changed

10 files changed

+336
-123
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.9.0] - 2023-06-17
10+
### Changed
11+
- Function signature of custom coercions to allow parsing more complex coercions types such as substr.
12+
13+
### Added
14+
- Added new `_substr_[n:n]` COERCE identifier.
15+
916
## [0.8.0] - 2023-06-10
1017
### Added
1118
- Ability to register new, remove existing and replace existing COERCE types.
@@ -70,7 +77,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7077
### Added
7178
- Initial conversion from https://github.com/rust-playground/ksql.
7279

73-
[Unreleased]: https://github.com/go-playground/ksql/compare/v0.8.0...HEAD
80+
[Unreleased]: https://github.com/go-playground/ksql/compare/v0.9.0...HEAD
81+
[0.9.0]: https://github.com/go-playground/ksql/compare/v0.8.0...v0.9.0
7482
[0.8.0]: https://github.com/go-playground/ksql/compare/v0.7.0...v0.8.0
7583
[0.7.0]: https://github.com/go-playground/ksql/compare/v0.6.1...v0.7.0
7684
[0.6.1]: https://github.com/go-playground/ksql/compare/v0.6.0...v0.6.1

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ksql
22
=====
3-
![Project status](https://img.shields.io/badge/version-0.8.0-green.svg)
3+
![Project status](https://img.shields.io/badge/version-0.9.0-green.svg)
44
[![GoDoc](https://godoc.org/github.com/go-playground/ksql?status.svg)](https://pkg.go.dev/github.com/go-playground/ksql)
55
![License](https://img.shields.io/dub/l/vibe-d.svg)
66

@@ -86,17 +86,19 @@ Expressions support most mathematical and string expressions see below for detai
8686
| `NULL` | `NULL` | N/A |
8787
| `Coerce` | `COERCE` | Coerces one data type into another using in combination with 'Identifier'. Syntax is `COERCE <expression> _identifer_`. |
8888
| `Identifier` | `_identifier_` | Starts and end with an `_` used with 'COERCE' to cast data types, see table below with supported values. You can combine multiple coercions if separated by a COMMA. |
89+
| `Colon` | `:` | N/A |
8990

9091
#### COERCE Types
9192

92-
| Type | Description |
93-
|---------------|--------------------------------------------------------------------------------------------------------------------------|
94-
| `_datetime_` | This attempts to convert the type into a DateTime. |
95-
| `_lowercase_` | This converts the text into lowercase. |
96-
| `_uppercase_` | This converts the text into uppercase. |
97-
| `_title_` | This converts the text into title case, when the first letter is capitalized but the rest lower cased. |
98-
| `_string_` | This converts the value into a string and supports the Value's String, Number, Bool, DateTime with nanosecond precision. |
99-
| `_number_` | This converts the value into an f64 number and supports the Value's Null, String, Number, Bool and DateTime. |
93+
| Type | Description |
94+
|-----------------|--------------------------------------------------------------------------------------------------------------------------|
95+
| `_datetime_` | This attempts to convert the type into a DateTime. |
96+
| `_lowercase_` | This converts the text into lowercase. |
97+
| `_uppercase_` | This converts the text into uppercase. |
98+
| `_title_` | This converts the text into title case, when the first letter is capitalized but the rest lower cased. |
99+
| `_string_` | This converts the value into a string and supports the Value's String, Number, Bool, DateTime with nanosecond precision. |
100+
| `_number_` | This converts the value into an f64 number and supports the Value's Null, String, Number, Bool and DateTime. |
101+
| `_substr_[n:n]` | This allows taking a substring of a string value. this returns Null if no match at specified indices exits. |
100102

101103
#### License
102104

_examples/custom-coercion/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func main() {
2929
// Add custom coercion to the parser.
3030
// REMEMBER: coercions start and end with an _(underscore).
3131
guard := ksql.Coercions.Lock()
32-
guard.T["_star_"] = func(constEligible bool, expression ksql.Expression) (stillConstEligible bool, e ksql.Expression, err error) {
32+
guard.T["_star_"] = func(_ *ksql.Parser, constEligible bool, expression ksql.Expression) (stillConstEligible bool, e ksql.Expression, err error) {
3333
return constEligible, &Star{expression}, nil
3434
}
3535
guard.Unlock()

errors.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,21 @@ type ErrUnsupportedCoerce struct {
8888
func (e ErrUnsupportedCoerce) Error() string {
8989
return fmt.Sprintf("unsupported type comparison for COERCE: `%s`", e.s)
9090
}
91+
92+
// ErrCustom represents a custom error
93+
type ErrCustom struct {
94+
S string
95+
}
96+
97+
func (e ErrCustom) Error() string {
98+
return e.S
99+
}
100+
101+
// ErrInvalidCoerce represents an invalid Coerce error
102+
type ErrInvalidCoerce struct {
103+
Err error
104+
}
105+
106+
func (e ErrInvalidCoerce) Error() string {
107+
return fmt.Sprintf("invalid COERCE: `%s`", e.Err.Error())
108+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ go 1.18
55
require (
66
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
77
github.com/go-playground/itertools v0.1.0
8+
github.com/go-playground/pkg/v5 v5.20.0
89
github.com/stretchr/testify v1.8.1
9-
github.com/go-playground/pkg/v5 v5.18.0
1010
github.com/tidwall/gjson v1.14.4
1111
)
1212

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ github.com/go-playground/itertools v0.1.0 h1:isiUTLIViAz4J3qWrowvRoOYWSXy2ubkXKN
88
github.com/go-playground/itertools v0.1.0/go.mod h1:+TD1WVpn32jr+GpvO+nnb2xXD45SSzt18Fo/C0y9PJE=
99
github.com/go-playground/pkg/v5 v5.18.0 h1:qnYuhWhwLdWj6ut9jagFjaiUI6PZTo3SafR5Um9w214=
1010
github.com/go-playground/pkg/v5 v5.18.0/go.mod h1:eT8XZeFHnqZkfkpkbI8ayjfCw9GohV2/j8STbVmoR6s=
11+
github.com/go-playground/pkg/v5 v5.20.0 h1:cSiC5f8KAvWHCV2vmYyNFgIZE6Fvx3WJO5Uw+pXOdxw=
12+
github.com/go-playground/pkg/v5 v5.20.0/go.mod h1:eT8XZeFHnqZkfkpkbI8ayjfCw9GohV2/j8STbVmoR6s=
1113
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
1214
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1315
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

lexer.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import (
77

88
// Token represents a lexed token
99
type Token struct {
10-
start uint32
11-
len uint16
12-
kind TokenKind
10+
Start uint32
11+
Len uint16
12+
Kind TokenKind
1313
}
1414

1515
// LexerResult represents a token lexed result
@@ -54,6 +54,7 @@ const (
5454
CloseParen
5555
Coerce
5656
Identifier
57+
Colon
5758
)
5859

5960
// / Try to lex a single token from the input stream.
@@ -108,6 +109,8 @@ func tokenizeSingleToken(data []byte) (result LexerResult, err error) {
108109
result = LexerResult{kind: Comma, len: 1}
109110
case '!':
110111
result = LexerResult{kind: Not, len: 1}
112+
case ':':
113+
result = LexerResult{kind: Colon, len: 1}
111114
case '"', '\'':
112115
result, err = tokenizeString(data, b)
113116
case '.':
@@ -168,9 +171,9 @@ func tokenizeSingleToken(data []byte) (result LexerResult, err error) {
168171

169172
func tokenizeIdentifier(data []byte) (result LexerResult, err error) {
170173
end := takeWhile(data, func(b byte) bool {
171-
return !isWhitespace(b) && b != ')' && b != ']' && b != ','
174+
return !isWhitespace(b) && b != ')' && b != '[' && b != ']' && b != ','
172175
})
173-
// identifier must start and end with underscore
176+
// identifier must Start and end with underscore
174177
if end > 0 && data[end-1] == '_' {
175178
result = LexerResult{
176179
kind: Identifier,
@@ -351,7 +354,7 @@ func skipWhitespace(data []byte) uint16 {
351354
})
352355
}
353356

354-
// NewTokenizer creates a new tokenizer for use
357+
// NewTokenizer creates a new Tokenizer for use
355358
func NewTokenizer(src []byte) *Tokenizer {
356359
return &Tokenizer{
357360
pos: 0,
@@ -379,9 +382,9 @@ func (t *Tokenizer) nextToken() optionext.Option[resultext.Result[Token, error]]
379382
return optionext.Some(resultext.Err[Token, error](err))
380383
}
381384
token := Token{
382-
start: t.pos,
383-
len: result.len,
384-
kind: result.kind,
385+
Start: t.pos,
386+
Len: result.len,
387+
Kind: result.kind,
385388
}
386389
t.chomp(result.len)
387390
return optionext.Some(resultext.Ok[Token, error](token))

0 commit comments

Comments
 (0)