Skip to content

Commit

Permalink
ZDM-606: Support colon operator in fuzzy SAI queries
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-antoniak committed Jun 5, 2024
1 parent f893984 commit 8b6772e
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 66 deletions.
17 changes: 12 additions & 5 deletions antlr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

## How to generate the grammar files

First, install antlr 4.
1. Install ANTLR 4.
- On a Mac: `brew install antlr`.

On a Mac: `brew install antlr`.
2. Generate the Go files for the `SimplifiedCql` grammar:
```
antlr -Dlanguage=Go antlr/SimplifiedCql.g4
```
Second, generate the Go files for the `SimplifiedCql` grammar:

antlr -Dlanguage=Go antlr/SimplifiedCql.g4
Current ZDM code works with ANTLR 4.9.3, so if you have issues downloading it from system package managers you can:
1. Download JAR file from https://repo1.maven.org/maven2/org/antlr/antlr4/4.9.3
2. Generate Go files for simplified CQL grammar:
```
java -Xmx500M -cp ".:/path/to/antlr4-4.9.3-complete.jar" org.antlr.v4.Tool -Dlanguage=Go antlr/SimplifiedCql.g4
```
1 change: 1 addition & 0 deletions antlr/SimplifiedCql.g4
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ operator
| '>'
| '>='
| '!='
| ':'
;

// CQL literals
Expand Down
4 changes: 2 additions & 2 deletions antlr/SimplifiedCql.interp

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions antlr/SimplifiedCql.tokens
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ OTHER=107
'>'=15
'>='=16
'!='=17
'{'=18
'}'=19
':'=20
':'=18
'{'=19
'}'=20
'?'=96
';'=106
4 changes: 2 additions & 2 deletions antlr/SimplifiedCqlLexer.interp

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions antlr/SimplifiedCqlLexer.tokens
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ OTHER=107
'>'=15
'>='=16
'!='=17
'{'=18
'}'=19
':'=20
':'=18
'{'=19
'}'=20
'?'=96
';'=106
6 changes: 3 additions & 3 deletions antlr/simplifiedcql_lexer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 37 additions & 37 deletions antlr/simplifiedcql_parser.go

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions integration-tests/basicselect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package integration_tests

import (
"fmt"
"github.com/datastax/zdm-proxy/integration-tests/env"
"github.com/datastax/zdm-proxy/integration-tests/setup"
"github.com/datastax/zdm-proxy/integration-tests/utils"
"github.com/stretchr/testify/require"
"testing"
)

func TestSaiSelect(t *testing.T) {
if !env.RunCcmTests {
t.Skip("Test requires CCM, set RUN_CCMTESTS env variable to TRUE")
}
if !(env.IsDse && env.CompareServerVersion("6.9") >= 0) {
t.Skip("Test requires DSE 6.9 cluster")
}

proxyInstance, err := NewProxyInstanceForGlobalCcmClusters()
require.Nil(t, err)
defer proxyInstance.Shutdown()

originCluster, targetCluster, err := SetupOrGetGlobalCcmClusters()
require.Nil(t, err)

// Initialize test data
dataIds1 := []string{
"43bfd159-dede-47bf-a4da-6d446065e618",
"17a424d1-e611-47e2-8bcd-2cec885edf28"}
dataTasks1 := []string{
"Mile",
"Mission"}

// Seed originCluster and targetCluster w/ schema and data
setup.SeedData(originCluster.GetSession(), targetCluster.GetSession(), setup.TestTable3, dataIds1, dataTasks1)

// Connect to proxy as a "client"
proxy, err := utils.ConnectToCluster("127.0.0.1", "", "", 14002)

if err != nil {
t.Log("Unable to connect to proxy session.")
t.Fatal(err)
}
defer proxy.Close()

// run query on proxied connection
// use lowercased version of the actual value
itr := proxy.Query(fmt.Sprintf("SELECT * FROM %s.%s where task : 'mile';", setup.TestKeyspace, setup.TestTable3)).Iter()
row := make(map[string]interface{})

// Assertions!
require.True(t, itr.MapScan(row))
task := setup.MapToTask(row)

setup.AssertEqual(t, "Mile", task.Task)
}
5 changes: 4 additions & 1 deletion integration-tests/ccm/ccm.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ func Create(name string, version string, isDse bool) (string, error) {

}

func Add(seed bool, address string, remoteDebugPort int, jmxPort int, name string) (string, error) {
func Add(seed bool, address string, remoteDebugPort int, jmxPort int, name string, isDse bool) (string, error) {
var addArgs = []string{
"-i", address, "-r", fmt.Sprintf("%d", remoteDebugPort), "-j", fmt.Sprintf("%d", jmxPort), name}
if isDse {
addArgs = append(addArgs, "--dse")
}
if seed {
return execCcm(append([]string{"add", "-s"}, addArgs...)...)
} else {
Expand Down
6 changes: 4 additions & 2 deletions integration-tests/ccm/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ func (ccmCluster *Cluster) Create(numberOfNodes int, start bool) error {
fmt.Sprintf("127.0.0.%d", nodeIndex),
2000+nodeIndex*100,
7000+nodeIndex*100,
fmt.Sprintf("node%d", nodeIndex))
fmt.Sprintf("node%d", nodeIndex),
ccmCluster.isDse)

if err != nil {
Remove(ccmCluster.name)
Expand Down Expand Up @@ -152,7 +153,8 @@ func (ccmCluster *Cluster) AddNode(index int) error {
fmt.Sprintf("127.0.0.%d", nodeIndex),
2000+nodeIndex*100,
7000+nodeIndex*100,
fmt.Sprintf("node%d", nodeIndex))
fmt.Sprintf("node%d", nodeIndex),
ccmCluster.isDse)
return err
}

Expand Down
36 changes: 36 additions & 0 deletions integration-tests/env/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,42 @@ func InitGlobalVars() {
}
}

func CompareServerVersion(version string) int {
v1 := parseVersion(ServerVersion)
v2 := parseVersion(version)
return compareVersion(v1, v2)
}

func parseVersion(version string) []int {
// remove optional suffix (e.g. 5.0-beta1 becomes 5.0) and split version segments
segmentsStr := strings.Split(strings.Split(version, "-")[0], ".")
segments := make([]int, len(segmentsStr))
for i, str := range segmentsStr {
val, err := strconv.Atoi(str)
if err != nil {
return []int{0, 0, 0}
}
segments[i] = val
}
// if we have less than 3 segments, pad with zeros
for i := len(segments); i < 3; i++ {
segments = append(segments, 0)
}
return segments
}

func compareVersion(v1 []int, v2 []int) int {
for i := 0; i < len(v1); i++ {
if v1[i] == v2[i] {
continue
} else if v1[i] < v2[i] {
return -1
}
return 1
}
return 0
}

func getEnvironmentVariableOrDefault(key string, defaultValue string) string {
if value, ok := os.LookupEnv(key); ok {
return value
Expand Down
20 changes: 19 additions & 1 deletion integration-tests/setup/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,23 @@ const TestTable = "tasks"
// TestTable2 is another dedicated table for testing
const TestTable2 = "people"

// TestTable3 is dedicated table for custom data types testing
const TestTable3 = "cyclist"

// TestTables is an array of dedicated tables for testing
var TestTables = [...]string{TestTable, TestTable2}
var TestTables = [...]string{TestTable, TestTable2, TestTable3}

var TestTableDefinitions = map[string][]string{
TestTable: {"CREATE TABLE %s.%s(id UUID, task text, PRIMARY KEY(id));"},
TestTable2: {"CREATE TABLE %s.%s(id UUID, task text, PRIMARY KEY(id));"},
TestTable3: {
"CREATE TABLE %s.%s(id UUID, task text, PRIMARY KEY(id));",
"CREATE CUSTOM INDEX example_sai_idx ON %s.%s(task) USING 'StorageAttachedIndex' WITH OPTIONS = {'case_sensitive': 'false'};",
},
}

var TestTableInserts = map[string]string{
TestTable: "INSERT INTO %s.%s(id, task) VALUES (%s, '%s');",
TestTable2: "INSERT INTO %s.%s(id, task) VALUES (%s, '%s');",
TestTable3: "INSERT INTO %s.%s(id, task) VALUES (%s, '%s');",
}
18 changes: 11 additions & 7 deletions integration-tests/setup/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,24 @@ func SeedData(source *gocql.Session, dest *gocql.Session, table string, dataIds

log.Info("Seeding tables...")
// Create the table in source
err = source.Query(fmt.Sprintf("CREATE TABLE %s.%s(id UUID, task text, PRIMARY KEY(id));", TestKeyspace, table)).Exec()
if err != nil {
log.WithError(err).Error("Error creating table in source cluster.")
for _, statement := range TestTableDefinitions[table] {
err = source.Query(fmt.Sprintf(statement, TestKeyspace, table)).Exec()
if err != nil {
log.WithError(err).Error("Error creating table in source cluster.")
}
}

err = dest.Query(fmt.Sprintf("CREATE TABLE %s.%s(id UUID, task text, PRIMARY KEY(id));", TestKeyspace, table)).Exec()
if err != nil {
log.WithError(err).Error("Error creating table in dest cluster.")
for _, statement := range TestTableDefinitions[table] {
err = dest.Query(fmt.Sprintf(statement, TestKeyspace, table)).Exec()
if err != nil {
log.WithError(err).Error("Error creating table in dest cluster.")
}
}

// Seed the rows
for i := 0; i < len(dataIds); i++ {
id, task := dataIds[i], dataEntries[i]
err = source.Query(fmt.Sprintf("INSERT INTO %s.%s(id, task) VALUES (%s, '%s');", TestKeyspace, table, id, task)).Exec()
err = source.Query(fmt.Sprintf(TestTableInserts[table], TestKeyspace, table, id, task)).Exec()
if err != nil {
log.WithError(err).Error("Error inserting into table for source cluster.")
}
Expand Down
4 changes: 4 additions & 0 deletions proxy/pkg/zdmproxy/cqlparser_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func TestParseAndInspect_SearchRequests(t *testing.T) {
"select * from person where solr_query='{\"q\" : \"*:*\", \"distrib.singlePass\" : true}';",
NewGenericRequestInfo(forwardToOrigin, true, true),
},
{"Query using SAI fuzzy search operator",
"select * from person where nick_name:'fuzzy';",
NewGenericRequestInfo(forwardToOrigin, true, true),
},
}

for _, tt := range tests {
Expand Down

0 comments on commit 8b6772e

Please sign in to comment.