mirror of https://github.com/pikami/cosmium.git
Code cleanup; Implement persistant storage; Use maps for storage
This commit is contained in:
parent
1c5e5ce85d
commit
48660b5f63
|
@ -14,12 +14,13 @@ var Config = ServerConfig{}
|
||||||
func ParseFlags() {
|
func ParseFlags() {
|
||||||
host := flag.String("Host", "localhost", "Hostname")
|
host := flag.String("Host", "localhost", "Hostname")
|
||||||
port := flag.Int("Port", 8081, "Listen port")
|
port := flag.Int("Port", 8081, "Listen port")
|
||||||
explorerPath := flag.String("ExplorerDir", "/home/pk/pro/cosmos-explorer/dist", "Path to cosmos-explorer files")
|
explorerPath := flag.String("ExplorerDir", "", "Path to cosmos-explorer files")
|
||||||
tlsCertificatePath := flag.String("Cert", "../example.crt", "Hostname")
|
tlsCertificatePath := flag.String("Cert", "", "Hostname")
|
||||||
tlsCertificateKey := flag.String("CertKey", "../example.key", "Hostname")
|
tlsCertificateKey := flag.String("CertKey", "", "Hostname")
|
||||||
initialDataPath := flag.String("InitialData", "", "Path to JSON containing initial state")
|
initialDataPath := flag.String("InitialData", "", "Path to JSON containing initial state")
|
||||||
accountKey := flag.String("AccountKey", DefaultAccountKey, "Account key for authentication")
|
accountKey := flag.String("AccountKey", DefaultAccountKey, "Account key for authentication")
|
||||||
disableAuthentication := flag.Bool("DisableAuth", false, "Disable authentication")
|
disableAuthentication := flag.Bool("DisableAuth", false, "Disable authentication")
|
||||||
|
persistDataPath := flag.String("Persist", "", "Saves data to given path on application exit")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -28,7 +29,8 @@ func ParseFlags() {
|
||||||
Config.ExplorerPath = *explorerPath
|
Config.ExplorerPath = *explorerPath
|
||||||
Config.TLS_CertificatePath = *tlsCertificatePath
|
Config.TLS_CertificatePath = *tlsCertificatePath
|
||||||
Config.TLS_CertificateKey = *tlsCertificateKey
|
Config.TLS_CertificateKey = *tlsCertificateKey
|
||||||
Config.DataFilePath = *initialDataPath
|
Config.InitialDataFilePath = *initialDataPath
|
||||||
|
Config.PersistDataFilePath = *persistDataPath
|
||||||
Config.DisableAuth = *disableAuthentication
|
Config.DisableAuth = *disableAuthentication
|
||||||
|
|
||||||
Config.DatabaseAccount = Config.Host
|
Config.DatabaseAccount = Config.Host
|
||||||
|
|
|
@ -11,6 +11,7 @@ type ServerConfig struct {
|
||||||
Host string
|
Host string
|
||||||
TLS_CertificatePath string
|
TLS_CertificatePath string
|
||||||
TLS_CertificateKey string
|
TLS_CertificateKey string
|
||||||
DataFilePath string
|
InitialDataFilePath string
|
||||||
|
PersistDataFilePath string
|
||||||
DisableAuth bool
|
DisableAuth bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,14 +65,14 @@ func CreateDatabase(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := repositories.CreateDatabase(newDatabase)
|
createdDatabase, status := repositories.CreateDatabase(newDatabase)
|
||||||
if status == repositorymodels.Conflict {
|
if status == repositorymodels.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == repositorymodels.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, newDatabase)
|
c.IndentedJSON(http.StatusCreated, createdDatabase)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,14 +78,14 @@ func ReplaceDocument(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status = repositories.CreateDocument(databaseId, collectionId, requestBody)
|
createdDocument, status := repositories.CreateDocument(databaseId, collectionId, requestBody)
|
||||||
if status == repositorymodels.Conflict {
|
if status == repositorymodels.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == repositorymodels.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, requestBody)
|
c.IndentedJSON(http.StatusCreated, createdDocument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,6 @@ func DocumentsPost(c *gin.Context) {
|
||||||
queryParameters = parametersToMap(paramsArray)
|
queryParameters = parametersToMap(paramsArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle these {"query":"select c.id, c._self, c._rid, c._ts, [c[\"pk\"]] as _partitionKeyValue from c"}
|
|
||||||
docs, status := repositories.ExecuteQueryDocuments(databaseId, collectionId, query.(string), queryParameters)
|
docs, status := repositories.ExecuteQueryDocuments(databaseId, collectionId, query.(string), queryParameters)
|
||||||
if status != repositorymodels.StatusOk {
|
if status != repositorymodels.StatusOk {
|
||||||
// TODO: Currently we return everything if the query fails
|
// TODO: Currently we return everything if the query fails
|
||||||
|
@ -131,14 +130,14 @@ func DocumentsPost(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := repositories.CreateDocument(databaseId, collectionId, requestBody)
|
createdDocument, status := repositories.CreateDocument(databaseId, collectionId, requestBody)
|
||||||
if status == repositorymodels.Conflict {
|
if status == repositorymodels.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == repositorymodels.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, requestBody)
|
c.IndentedJSON(http.StatusCreated, createdDocument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,9 @@ func RegisterExplorerHandlers(router *gin.Engine) {
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
explorer.Static("/", config.Config.ExplorerPath)
|
|
||||||
|
if config.Config.ExplorerPath != "" {
|
||||||
|
explorer.Static("/", config.Config.ExplorerPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ func Test_Collections(t *testing.T) {
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
repositories.CreateDatabase(repositorymodels.Database{ID: testDatabaseName})
|
||||||
databaseClient, err := client.NewDatabase(testDatabaseName)
|
databaseClient, err := client.NewDatabase(testDatabaseName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
func runTestServer() *httptest.Server {
|
func runTestServer() *httptest.Server {
|
||||||
config.Config.AccountKey = config.DefaultAccountKey
|
config.Config.AccountKey = config.DefaultAccountKey
|
||||||
|
config.Config.ExplorerPath = "/tmp/nothing"
|
||||||
|
|
||||||
return httptest.NewServer(api.CreateRouter())
|
return httptest.NewServer(api.CreateRouter())
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ func testCosmosQuery(t *testing.T,
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Documents(t *testing.T) {
|
func Test_Documents(t *testing.T) {
|
||||||
|
repositories.CreateDatabase(repositorymodels.Database{ID: testDatabaseName})
|
||||||
repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
||||||
ID: testCollectionName,
|
ID: testCollectionName,
|
||||||
PartitionKey: struct {
|
PartitionKey: struct {
|
||||||
|
@ -77,7 +78,7 @@ func Test_Documents(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Should query document", func(t *testing.T) {
|
t.Run("Should query document", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT c.id, c[\"pk\"] FROM c",
|
"SELECT c.id, c[\"pk\"] FROM c ORDER BY c.id",
|
||||||
nil,
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "12345", "pk": "123"},
|
map[string]interface{}{"id": "12345", "pk": "123"},
|
||||||
|
@ -88,7 +89,7 @@ func Test_Documents(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Should query VALUE array", func(t *testing.T) {
|
t.Run("Should query VALUE array", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT VALUE [c.id, c[\"pk\"]] FROM c",
|
"SELECT VALUE [c.id, c[\"pk\"]] FROM c ORDER BY c.id",
|
||||||
nil,
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
[]interface{}{"12345", "123"},
|
[]interface{}{"12345", "123"},
|
||||||
|
@ -99,7 +100,7 @@ func Test_Documents(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Should query VALUE object", func(t *testing.T) {
|
t.Run("Should query VALUE object", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT VALUE { id: c.id, _pk: c.pk } FROM c",
|
"SELECT VALUE { id: c.id, _pk: c.pk } FROM c ORDER BY c.id",
|
||||||
nil,
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "12345", "_pk": "123"},
|
map[string]interface{}{"id": "12345", "_pk": "123"},
|
||||||
|
@ -112,7 +113,8 @@ func Test_Documents(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
`select c.id
|
`select c.id
|
||||||
FROM c
|
FROM c
|
||||||
WHERE c.isCool=true`,
|
WHERE c.isCool=true
|
||||||
|
ORDER BY c.id`,
|
||||||
nil,
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "67890"},
|
map[string]interface{}{"id": "67890"},
|
||||||
|
@ -124,7 +126,8 @@ func Test_Documents(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
`select c.id
|
`select c.id
|
||||||
FROM c
|
FROM c
|
||||||
WHERE c.id=@param_id`,
|
WHERE c.id=@param_id
|
||||||
|
ORDER BY c.id`,
|
||||||
[]azcosmos.QueryParameter{
|
[]azcosmos.QueryParameter{
|
||||||
{Name: "@param_id", Value: "67890"},
|
{Name: "@param_id", Value: "67890"},
|
||||||
},
|
},
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -38,8 +38,9 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
|
||||||
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
|
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
|
||||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
@ -86,6 +87,8 @@ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||||
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -94,7 +97,6 @@ golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
|
|
|
@ -7,48 +7,50 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
structhidrators "github.com/pikami/cosmium/internal/struct_hidrators"
|
structhidrators "github.com/pikami/cosmium/internal/struct_hidrators"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var collections = []repositorymodels.Collection{}
|
|
||||||
|
|
||||||
func GetAllCollections(databaseId string) ([]repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func GetAllCollections(databaseId string) ([]repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
||||||
dbCollections := make([]repositorymodels.Collection, 0)
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
|
return make([]repositorymodels.Collection, 0), repositorymodels.StatusNotFound
|
||||||
for _, coll := range collections {
|
|
||||||
if coll.Internals.DatabaseId == databaseId {
|
|
||||||
dbCollections = append(dbCollections, coll)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbCollections, repositorymodels.StatusOk
|
return maps.Values(storeState.Collections[databaseId]), repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCollection(databaseId string, id string) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func GetCollection(databaseId string, collectionId string) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
||||||
for _, coll := range collections {
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.ID == id {
|
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
||||||
return coll, repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
if _, ok := storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return storeState.Collections[databaseId][collectionId], repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteCollection(databaseId string, id string) repositorymodels.RepositoryStatus {
|
func DeleteCollection(databaseId string, collectionId string) repositorymodels.RepositoryStatus {
|
||||||
for index, coll := range collections {
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.ID == id {
|
return repositorymodels.StatusNotFound
|
||||||
collections = append(collections[:index], collections[index+1:]...)
|
|
||||||
return repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.StatusNotFound
|
if _, ok := storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(storeState.Collections[databaseId], collectionId)
|
||||||
|
|
||||||
|
return repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCollection(databaseId string, newCollection repositorymodels.Collection) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func CreateCollection(databaseId string, newCollection repositorymodels.Collection) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
||||||
for _, coll := range collections {
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.ID == newCollection.ID {
|
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
||||||
return repositorymodels.Collection{}, repositorymodels.Conflict
|
}
|
||||||
}
|
|
||||||
|
if _, ok := storeState.Collections[databaseId][newCollection.ID]; ok {
|
||||||
|
return repositorymodels.Collection{}, repositorymodels.Conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
newCollection = structhidrators.Hidrate(newCollection).(repositorymodels.Collection)
|
newCollection = structhidrators.Hidrate(newCollection).(repositorymodels.Collection)
|
||||||
|
@ -56,9 +58,9 @@ func CreateCollection(databaseId string, newCollection repositorymodels.Collecti
|
||||||
newCollection.TimeStamp = time.Now().Unix()
|
newCollection.TimeStamp = time.Now().Unix()
|
||||||
newCollection.UniqueID = uuid.New().String()
|
newCollection.UniqueID = uuid.New().String()
|
||||||
newCollection.ETag = fmt.Sprintf("\"%s\"", newCollection.UniqueID)
|
newCollection.ETag = fmt.Sprintf("\"%s\"", newCollection.UniqueID)
|
||||||
newCollection.Internals = struct{ DatabaseId string }{
|
|
||||||
DatabaseId: databaseId,
|
storeState.Collections[databaseId][newCollection.ID] = newCollection
|
||||||
}
|
storeState.Documents[databaseId][newCollection.ID] = make(map[string]repositorymodels.Document)
|
||||||
collections = append(collections, newCollection)
|
|
||||||
return newCollection, repositorymodels.StatusOk
|
return newCollection, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,48 +6,42 @@ import (
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var databases = []repositorymodels.Database{
|
|
||||||
{ID: "db1"},
|
|
||||||
{ID: "db2"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllDatabases() ([]repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
func GetAllDatabases() ([]repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
||||||
return databases, repositorymodels.StatusOk
|
return maps.Values(storeState.Databases), repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDatabase(id string) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
func GetDatabase(id string) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
||||||
for _, db := range databases {
|
if database, ok := storeState.Databases[id]; ok {
|
||||||
if db.ID == id {
|
return database, repositorymodels.StatusOk
|
||||||
return db, repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.Database{}, repositorymodels.StatusNotFound
|
return repositorymodels.Database{}, repositorymodels.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDatabase(id string) repositorymodels.RepositoryStatus {
|
func DeleteDatabase(id string) repositorymodels.RepositoryStatus {
|
||||||
for index, db := range databases {
|
if _, ok := storeState.Databases[id]; !ok {
|
||||||
if db.ID == id {
|
return repositorymodels.StatusNotFound
|
||||||
databases = append(databases[:index], databases[index+1:]...)
|
|
||||||
return repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.StatusNotFound
|
delete(storeState.Databases, id)
|
||||||
|
|
||||||
|
return repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateDatabase(newDatabase repositorymodels.Database) repositorymodels.RepositoryStatus {
|
func CreateDatabase(newDatabase repositorymodels.Database) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
||||||
for _, db := range databases {
|
if _, ok := storeState.Databases[newDatabase.ID]; ok {
|
||||||
if db.ID == newDatabase.ID {
|
return repositorymodels.Database{}, repositorymodels.Conflict
|
||||||
return repositorymodels.Conflict
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newDatabase.TimeStamp = time.Now().Unix()
|
newDatabase.TimeStamp = time.Now().Unix()
|
||||||
newDatabase.UniqueID = uuid.New().String()
|
newDatabase.UniqueID = uuid.New().String()
|
||||||
newDatabase.ETag = fmt.Sprintf("\"%s\"", newDatabase.UniqueID)
|
newDatabase.ETag = fmt.Sprintf("\"%s\"", newDatabase.UniqueID)
|
||||||
databases = append(databases, newDatabase)
|
storeState.Databases[newDatabase.ID] = newDatabase
|
||||||
return repositorymodels.StatusOk
|
storeState.Collections[newDatabase.ID] = make(map[string]repositorymodels.Collection)
|
||||||
|
storeState.Documents[newDatabase.ID] = make(map[string]map[string]repositorymodels.Document)
|
||||||
|
|
||||||
|
return newDatabase, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package repositories
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -11,102 +10,81 @@ import (
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
"github.com/pikami/cosmium/parsers/nosql"
|
"github.com/pikami/cosmium/parsers/nosql"
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var documents = []repositorymodels.Document{}
|
|
||||||
|
|
||||||
func GetAllDocuments(databaseId string, collectionId string) ([]repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
func GetAllDocuments(databaseId string, collectionId string) ([]repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
||||||
filteredDocuments := make([]repositorymodels.Document, 0)
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
|
return make([]repositorymodels.Document, 0), repositorymodels.StatusNotFound
|
||||||
for _, doc := range documents {
|
|
||||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
|
||||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
|
||||||
|
|
||||||
if docDbId == databaseId && docCollId == collectionId {
|
|
||||||
doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"]
|
|
||||||
filteredDocuments = append(filteredDocuments, doc)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredDocuments, repositorymodels.StatusOk
|
if _, ok := storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return make([]repositorymodels.Document, 0), repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return maps.Values(storeState.Documents[databaseId][collectionId]), repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDocument(databaseId string, collectionId string, documentId string) (repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
func GetDocument(databaseId string, collectionId string, documentId string) (repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
||||||
for _, doc := range documents {
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
||||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
|
||||||
docId := doc["id"]
|
|
||||||
|
|
||||||
if docDbId == databaseId && docCollId == collectionId && docId == documentId {
|
|
||||||
doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"]
|
|
||||||
return doc, repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
if _, ok := storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return storeState.Documents[databaseId][collectionId][documentId], repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDocument(databaseId string, collectionId string, documentId string) repositorymodels.RepositoryStatus {
|
func DeleteDocument(databaseId string, collectionId string, documentId string) repositorymodels.RepositoryStatus {
|
||||||
for index, doc := range documents {
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
|
||||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
|
||||||
docId := doc["id"]
|
|
||||||
|
|
||||||
if docDbId == databaseId && docCollId == collectionId && docId == documentId {
|
|
||||||
documents = append(documents[:index], documents[index+1:]...)
|
|
||||||
return repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateDocument(databaseId string, collectionId string, document map[string]interface{}) repositorymodels.RepositoryStatus {
|
|
||||||
if document["id"] == "" {
|
|
||||||
return repositorymodels.BadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
collection, status := GetCollection(databaseId, collectionId)
|
|
||||||
if status != repositorymodels.StatusOk {
|
|
||||||
return repositorymodels.StatusNotFound
|
return repositorymodels.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, doc := range documents {
|
if _, ok := storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
return repositorymodels.StatusNotFound
|
||||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
|
||||||
docId := doc["id"]
|
|
||||||
|
|
||||||
if docDbId == databaseId && docCollId == collectionId && docId == document["id"] {
|
|
||||||
return repositorymodels.Conflict
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partitionKeyValue := make([]string, 0)
|
if _, ok := storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||||
for _, path := range collection.PartitionKey.Paths {
|
return repositorymodels.StatusNotFound
|
||||||
var val interface{}
|
}
|
||||||
for _, part := range strings.Split(path, "/") {
|
|
||||||
val = document[part]
|
|
||||||
}
|
|
||||||
|
|
||||||
if val == nil {
|
delete(storeState.Documents[databaseId][collectionId], documentId)
|
||||||
val = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle non-string partition keys
|
return repositorymodels.StatusOk
|
||||||
partitionKeyValue = append(partitionKeyValue, val.(string))
|
}
|
||||||
|
|
||||||
|
func CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
||||||
|
var documentId string
|
||||||
|
var ok bool
|
||||||
|
if documentId, ok = document["id"].(string); !ok || documentId == "" {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok = storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := storeState.Documents[databaseId][collectionId][documentId]; ok {
|
||||||
|
return repositorymodels.Document{}, repositorymodels.Conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
document["_ts"] = time.Now().Unix()
|
document["_ts"] = time.Now().Unix()
|
||||||
document["_rid"] = uuid.New().String()
|
document["_rid"] = uuid.New().String()
|
||||||
document["_etag"] = fmt.Sprintf("\"%s\"", document["_rid"])
|
document["_etag"] = fmt.Sprintf("\"%s\"", document["_rid"])
|
||||||
document["_internal"] = map[string]interface{}{
|
|
||||||
"databaseId": databaseId,
|
|
||||||
"collectionId": collectionId,
|
|
||||||
"partitionKeyValue": partitionKeyValue,
|
|
||||||
}
|
|
||||||
documents = append(documents, document)
|
|
||||||
|
|
||||||
return repositorymodels.StatusOk
|
storeState.Documents[databaseId][collectionId][documentId] = document
|
||||||
|
|
||||||
|
return document, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteQueryDocuments(databaseId string, collectionId string, query string, queryParameters map[string]interface{}) ([]memoryexecutor.RowType, repositorymodels.RepositoryStatus) {
|
func ExecuteQueryDocuments(databaseId string, collectionId string, query string, queryParameters map[string]interface{}) ([]memoryexecutor.RowType, repositorymodels.RepositoryStatus) {
|
||||||
|
|
|
@ -5,10 +5,20 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var storedProcedures = []repositorymodels.StoredProcedure{}
|
||||||
|
var triggers = []repositorymodels.Trigger{}
|
||||||
|
var userDefinedFunctions = []repositorymodels.UserDefinedFunction{}
|
||||||
|
var storeState = repositorymodels.State{
|
||||||
|
Databases: make(map[string]repositorymodels.Database),
|
||||||
|
Collections: make(map[string]map[string]repositorymodels.Collection),
|
||||||
|
Documents: make(map[string]map[string]map[string]repositorymodels.Document),
|
||||||
|
}
|
||||||
|
|
||||||
func LoadStateFS(filePath string) {
|
func LoadStateFS(filePath string) {
|
||||||
data, err := os.ReadFile(filePath)
|
data, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -21,19 +31,91 @@ func LoadStateFS(filePath string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Loaded state:")
|
fmt.Println("Loaded state:")
|
||||||
fmt.Printf("Databases: %d\n", len(state.Databases))
|
fmt.Printf("Databases: %d\n", getLength(state.Databases))
|
||||||
fmt.Printf("Collections: %d\n", len(state.Collections))
|
fmt.Printf("Collections: %d\n", getLength(state.Collections))
|
||||||
fmt.Printf("Documents: %d\n", len(state.Documents))
|
fmt.Printf("Documents: %d\n", getLength(state.Documents))
|
||||||
|
|
||||||
databases = state.Databases
|
storeState = state
|
||||||
collections = state.Collections
|
|
||||||
documents = state.Documents
|
ensureStoreStateNoNullReferences()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetState() map[string]interface{} {
|
func SaveStateFS(filePath string) {
|
||||||
return map[string]interface{}{
|
data, err := json.MarshalIndent(storeState, "", "\t")
|
||||||
"databases": databases,
|
if err != nil {
|
||||||
"collections": collections,
|
fmt.Printf("Failed to save state: %v\n", err)
|
||||||
"documents": documents,
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.WriteFile(filePath, data, os.ModePerm)
|
||||||
|
|
||||||
|
fmt.Println("Saved state:")
|
||||||
|
fmt.Printf("Databases: %d\n", getLength(storeState.Databases))
|
||||||
|
fmt.Printf("Collections: %d\n", getLength(storeState.Collections))
|
||||||
|
fmt.Printf("Documents: %d\n", getLength(storeState.Documents))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetState() repositorymodels.State {
|
||||||
|
return storeState
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLength(v interface{}) int {
|
||||||
|
switch v.(type) {
|
||||||
|
case repositorymodels.Database,
|
||||||
|
repositorymodels.Collection,
|
||||||
|
repositorymodels.Document:
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.Kind() != reflect.Map {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for _, key := range rv.MapKeys() {
|
||||||
|
if rv.MapIndex(key).Kind() == reflect.Map {
|
||||||
|
count += getLength(rv.MapIndex(key).Interface())
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureStoreStateNoNullReferences() {
|
||||||
|
if storeState.Databases == nil {
|
||||||
|
storeState.Databases = make(map[string]repositorymodels.Database)
|
||||||
|
}
|
||||||
|
|
||||||
|
if storeState.Collections == nil {
|
||||||
|
storeState.Collections = make(map[string]map[string]repositorymodels.Collection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if storeState.Documents == nil {
|
||||||
|
storeState.Documents = make(map[string]map[string]map[string]repositorymodels.Document)
|
||||||
|
}
|
||||||
|
|
||||||
|
for database := range storeState.Databases {
|
||||||
|
if storeState.Collections[database] == nil {
|
||||||
|
storeState.Collections[database] = make(map[string]repositorymodels.Collection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if storeState.Documents[database] == nil {
|
||||||
|
storeState.Documents[database] = make(map[string]map[string]repositorymodels.Document)
|
||||||
|
}
|
||||||
|
|
||||||
|
for collection := range storeState.Collections[database] {
|
||||||
|
if storeState.Documents[database][collection] == nil {
|
||||||
|
storeState.Documents[database][collection] = make(map[string]repositorymodels.Document)
|
||||||
|
}
|
||||||
|
|
||||||
|
for document := range storeState.Documents[database][collection] {
|
||||||
|
if storeState.Documents[database][collection][document] == nil {
|
||||||
|
delete(storeState.Documents[database][collection], document)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,6 @@ package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
|
||||||
var storedProcedures = []repositorymodels.StoredProcedure{}
|
|
||||||
|
|
||||||
func GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
func GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
||||||
sps := make([]repositorymodels.StoredProcedure, 0)
|
return storedProcedures, repositorymodels.StatusOk
|
||||||
|
|
||||||
for _, coll := range storedProcedures {
|
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId {
|
|
||||||
sps = append(sps, coll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sps, repositorymodels.StatusOk
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,6 @@ package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
|
||||||
var triggers = []repositorymodels.Trigger{}
|
|
||||||
|
|
||||||
func GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
func GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
||||||
filteredTriggers := make([]repositorymodels.Trigger, 0)
|
return triggers, repositorymodels.StatusOk
|
||||||
|
|
||||||
for _, coll := range triggers {
|
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId {
|
|
||||||
filteredTriggers = append(filteredTriggers, coll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredTriggers, repositorymodels.StatusOk
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,6 @@ package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
|
||||||
var userDefinedFunctions = []repositorymodels.UserDefinedFunction{}
|
|
||||||
|
|
||||||
func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
||||||
udfs := make([]repositorymodels.UserDefinedFunction, 0)
|
return userDefinedFunctions, repositorymodels.StatusOk
|
||||||
|
|
||||||
for _, coll := range userDefinedFunctions {
|
|
||||||
if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId {
|
|
||||||
udfs = append(udfs, coll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return udfs, repositorymodels.StatusOk
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,6 @@ type Collection struct {
|
||||||
Triggers string `json:"_triggers"`
|
Triggers string `json:"_triggers"`
|
||||||
Udfs string `json:"_udfs"`
|
Udfs string `json:"_udfs"`
|
||||||
Conflicts string `json:"_conflicts"`
|
Conflicts string `json:"_conflicts"`
|
||||||
Internals struct {
|
|
||||||
DatabaseId string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CollectionIndexingPolicy struct {
|
type CollectionIndexingPolicy struct {
|
||||||
|
@ -57,29 +54,21 @@ type CollectionPartitionKey struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserDefinedFunction struct {
|
type UserDefinedFunction struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Rid string `json:"_rid"`
|
Rid string `json:"_rid"`
|
||||||
Ts int `json:"_ts"`
|
Ts int `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
Etag string `json:"_etag"`
|
||||||
Internals struct {
|
|
||||||
DatabaseId string
|
|
||||||
CollectionId string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoredProcedure struct {
|
type StoredProcedure struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Rid string `json:"_rid"`
|
Rid string `json:"_rid"`
|
||||||
Ts int `json:"_ts"`
|
Ts int `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
Etag string `json:"_etag"`
|
||||||
Internals struct {
|
|
||||||
DatabaseId string
|
|
||||||
CollectionId string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Trigger struct {
|
type Trigger struct {
|
||||||
|
@ -91,10 +80,6 @@ type Trigger struct {
|
||||||
Ts int `json:"_ts"`
|
Ts int `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
Etag string `json:"_etag"`
|
||||||
Internals struct {
|
|
||||||
DatabaseId string
|
|
||||||
CollectionId string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Document map[string]interface{}
|
type Document map[string]interface{}
|
||||||
|
@ -115,7 +100,12 @@ type PartitionKeyRange struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
Databases []Database `json:"databases"`
|
// Map databaseId -> Database
|
||||||
Collections []Collection `json:"collections"`
|
Databases map[string]Database `json:"databases"`
|
||||||
Documents []Document `json:"documents"`
|
|
||||||
|
// Map databaseId -> collectionId -> Collection
|
||||||
|
Collections map[string]map[string]Collection `json:"collections"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> documentId -> Documents
|
||||||
|
Documents map[string]map[string]map[string]Document `json:"documents"`
|
||||||
}
|
}
|
||||||
|
|
34
main.go
34
main.go
|
@ -2,6 +2,9 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pikami/cosmium/api"
|
"github.com/pikami/cosmium/api"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
|
@ -11,13 +14,32 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
config.ParseFlags()
|
config.ParseFlags()
|
||||||
|
|
||||||
if config.Config.DataFilePath != "" {
|
if config.Config.InitialDataFilePath != "" {
|
||||||
repositories.LoadStateFS(config.Config.DataFilePath)
|
repositories.LoadStateFS(config.Config.InitialDataFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
router := api.CreateRouter()
|
router := api.CreateRouter()
|
||||||
router.RunTLS(
|
if config.Config.TLS_CertificatePath == "" ||
|
||||||
fmt.Sprintf(":%d", config.Config.Port),
|
config.Config.TLS_CertificateKey == "" {
|
||||||
config.Config.TLS_CertificatePath,
|
go router.Run(fmt.Sprintf(":%d", config.Config.Port))
|
||||||
config.Config.TLS_CertificateKey)
|
} else {
|
||||||
|
go router.RunTLS(
|
||||||
|
fmt.Sprintf(":%d", config.Config.Port),
|
||||||
|
config.Config.TLS_CertificatePath,
|
||||||
|
config.Config.TLS_CertificateKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForExit() {
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
// Block until a exit signal is received
|
||||||
|
<-sigs
|
||||||
|
|
||||||
|
if config.Config.PersistDataFilePath != "" {
|
||||||
|
repositories.SaveStateFS(config.Config.PersistDataFilePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,15 +9,10 @@ func makeSelectStmt(columns, table, whereClause interface{}, count interface{},
|
||||||
Table: table.(parsers.Table),
|
Table: table.(parsers.Table),
|
||||||
}
|
}
|
||||||
|
|
||||||
if filters, ok := whereClause.(parsers.ComparisonExpression); ok {
|
switch v := whereClause.(type) {
|
||||||
selectStmt.Filters = filters
|
case parsers.ComparisonExpression, parsers.LogicalExpression, parsers.Constant, parsers.SelectItem:
|
||||||
} else if filters, ok := whereClause.(parsers.LogicalExpression); ok {
|
selectStmt.Filters = v
|
||||||
selectStmt.Filters = filters
|
}
|
||||||
} else if filters, ok := whereClause.(parsers.Constant); ok {
|
|
||||||
selectStmt.Filters = filters
|
|
||||||
} else if filters, ok := whereClause.(parsers.SelectItem); ok {
|
|
||||||
selectStmt.Filters = filters
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, ok := count.(int); ok {
|
if n, ok := count.(int); ok {
|
||||||
selectStmt.Count = n
|
selectStmt.Count = n
|
||||||
|
@ -284,14 +279,12 @@ ComparisonOperator <- ("=" / "!=" / "<" / "<=" / ">" / ">=") {
|
||||||
return string(c.text), nil
|
return string(c.text), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
StringEquals <- "STRINGEQUALS"i
|
|
||||||
|
|
||||||
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant / NullConstant
|
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant / NullConstant
|
||||||
|
|
||||||
ParameterConstant <- "@" Identifier {
|
ParameterConstant <- "@" Identifier {
|
||||||
return parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: string(c.text)}, nil
|
return parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: string(c.text)}, nil
|
||||||
}
|
}
|
||||||
NullConstant <- "null" {
|
NullConstant <- "null"i {
|
||||||
return parsers.Constant{Value: nil}, nil
|
return parsers.Constant{Value: nil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +350,7 @@ LowerExpression <- "LOWER"i ws "(" ex:SelectItem ")" {
|
||||||
return createFunctionCall(parsers.FunctionCallLower, []interface{}{ex})
|
return createFunctionCall(parsers.FunctionCallLower, []interface{}{ex})
|
||||||
}
|
}
|
||||||
|
|
||||||
StringEqualsExpression <- StringEquals ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ignoreCase:("," ws boolean:SelectItem { return boolean, nil })? ")" {
|
StringEqualsExpression <- "STRINGEQUALS"i ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ignoreCase:("," ws boolean:SelectItem { return boolean, nil })? ")" {
|
||||||
return createFunctionCall(parsers.FunctionCallStringEquals, []interface{}{ex1, ex2, ignoreCase})
|
return createFunctionCall(parsers.FunctionCallStringEquals, []interface{}{ex1, ex2, ignoreCase})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +418,7 @@ ThreeArgumentStringFunctionExpression <- function:ThreeArgumentStringFunction ws
|
||||||
functionType = parsers.FunctionCallIndexOf
|
functionType = parsers.FunctionCallIndexOf
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsers.FunctionCall{Type: functionType, Arguments: []interface{}{ex1, ex2, ignoreCase}}, nil
|
return createFunctionCall(functionType, []interface{}{ex1, ex2, ignoreCase})
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreeArgumentStringFunction <- ("CONTAINS"i / "ENDSWITH"i / "STARTSWITH"i / "INDEX_OF"i) {
|
ThreeArgumentStringFunction <- ("CONTAINS"i / "ENDSWITH"i / "STARTSWITH"i / "INDEX_OF"i) {
|
||||||
|
@ -493,8 +486,7 @@ SetUnionExpression <- "SetUnion"i ws "(" ws set1:SelectItem ws "," ws set2:Selec
|
||||||
}
|
}
|
||||||
|
|
||||||
InFunction <- ex1:SelectProperty ws "IN"i ws "(" ws ex2:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" {
|
InFunction <- ex1:SelectProperty ws "IN"i ws "(" ws ex2:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" {
|
||||||
arguments := append([]interface{}{ex1, ex2}, others.([]interface{})...)
|
return createFunctionCall(parsers.FunctionCallIn, append([]interface{}{ex1, ex2}, others.([]interface{})...))
|
||||||
return parsers.FunctionCall{Type: parsers.FunctionCallIn, Arguments: arguments}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer <- [0-9]+ {
|
Integer <- [0-9]+ {
|
||||||
|
|
|
@ -7,17 +7,17 @@ import (
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func array_Concat(arguments []interface{}, queryParameters map[string]interface{}, row RowType) []interface{} {
|
func (c memoryExecutorContext) array_Concat(arguments []interface{}, row RowType) []interface{} {
|
||||||
var result []interface{}
|
var result []interface{}
|
||||||
for _, arg := range arguments {
|
for _, arg := range arguments {
|
||||||
array := parseArray(arg, queryParameters, row)
|
array := c.parseArray(arg, row)
|
||||||
result = append(result, array...)
|
result = append(result, array...)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func array_Length(arguments []interface{}, queryParameters map[string]interface{}, row RowType) int {
|
func (c memoryExecutorContext) array_Length(arguments []interface{}, row RowType) int {
|
||||||
array := parseArray(arguments[0], queryParameters, row)
|
array := c.parseArray(arguments[0], row)
|
||||||
if array == nil {
|
if array == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,15 @@ func array_Length(arguments []interface{}, queryParameters map[string]interface{
|
||||||
return len(array)
|
return len(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
func array_Slice(arguments []interface{}, queryParameters map[string]interface{}, row RowType) []interface{} {
|
func (c memoryExecutorContext) array_Slice(arguments []interface{}, row RowType) []interface{} {
|
||||||
var ok bool
|
var ok bool
|
||||||
var start int
|
var start int
|
||||||
var length int
|
var length int
|
||||||
array := parseArray(arguments[0], queryParameters, row)
|
array := c.parseArray(arguments[0], row)
|
||||||
startEx := getFieldValue(arguments[1].(parsers.SelectItem), queryParameters, row)
|
startEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if arguments[2] != nil {
|
if arguments[2] != nil {
|
||||||
lengthEx := getFieldValue(arguments[2].(parsers.SelectItem), queryParameters, row)
|
lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
fmt.Println("array_Slice - got length parameters of wrong type")
|
fmt.Println("array_Slice - got length parameters of wrong type")
|
||||||
|
@ -65,9 +65,9 @@ func array_Slice(arguments []interface{}, queryParameters map[string]interface{}
|
||||||
return array[start:end]
|
return array[start:end]
|
||||||
}
|
}
|
||||||
|
|
||||||
func set_Intersect(arguments []interface{}, queryParameters map[string]interface{}, row RowType) []interface{} {
|
func (c memoryExecutorContext) set_Intersect(arguments []interface{}, row RowType) []interface{} {
|
||||||
set1 := parseArray(arguments[0], queryParameters, row)
|
set1 := c.parseArray(arguments[0], row)
|
||||||
set2 := parseArray(arguments[1], queryParameters, row)
|
set2 := c.parseArray(arguments[1], row)
|
||||||
|
|
||||||
intersection := make(map[interface{}]struct{})
|
intersection := make(map[interface{}]struct{})
|
||||||
if set1 == nil || set2 == nil {
|
if set1 == nil || set2 == nil {
|
||||||
|
@ -88,9 +88,9 @@ func set_Intersect(arguments []interface{}, queryParameters map[string]interface
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func set_Union(arguments []interface{}, queryParameters map[string]interface{}, row RowType) []interface{} {
|
func (c memoryExecutorContext) set_Union(arguments []interface{}, row RowType) []interface{} {
|
||||||
set1 := parseArray(arguments[0], queryParameters, row)
|
set1 := c.parseArray(arguments[0], row)
|
||||||
set2 := parseArray(arguments[1], queryParameters, row)
|
set2 := c.parseArray(arguments[1], row)
|
||||||
|
|
||||||
var result []interface{}
|
var result []interface{}
|
||||||
union := make(map[interface{}]struct{})
|
union := make(map[interface{}]struct{})
|
||||||
|
@ -111,9 +111,9 @@ func set_Union(arguments []interface{}, queryParameters map[string]interface{},
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseArray(argument interface{}, queryParameters map[string]interface{}, row RowType) []interface{} {
|
func (c memoryExecutorContext) parseArray(argument interface{}, row RowType) []interface{} {
|
||||||
exItem := argument.(parsers.SelectItem)
|
exItem := argument.(parsers.SelectItem)
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
arrValue := reflect.ValueOf(ex)
|
arrValue := reflect.ValueOf(ex)
|
||||||
if arrValue.Kind() != reflect.Slice {
|
if arrValue.Kind() != reflect.Slice {
|
||||||
|
|
|
@ -12,19 +12,27 @@ import (
|
||||||
type RowType interface{}
|
type RowType interface{}
|
||||||
type ExpressionType interface{}
|
type ExpressionType interface{}
|
||||||
|
|
||||||
|
type memoryExecutorContext struct {
|
||||||
|
parameters map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
||||||
|
ctx := memoryExecutorContext{
|
||||||
|
parameters: query.Parameters,
|
||||||
|
}
|
||||||
|
|
||||||
result := make([]RowType, 0)
|
result := make([]RowType, 0)
|
||||||
|
|
||||||
// Apply Filter
|
// Apply Filter
|
||||||
for _, row := range data {
|
for _, row := range data {
|
||||||
if evaluateFilters(query.Filters, query.Parameters, row) {
|
if ctx.evaluateFilters(query.Filters, row) {
|
||||||
result = append(result, row)
|
result = append(result, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply order
|
// Apply order
|
||||||
if query.OrderExpressions != nil && len(query.OrderExpressions) > 0 {
|
if query.OrderExpressions != nil && len(query.OrderExpressions) > 0 {
|
||||||
orderBy(query.OrderExpressions, query.Parameters, result)
|
ctx.orderBy(query.OrderExpressions, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply result limit
|
// Apply result limit
|
||||||
|
@ -41,16 +49,16 @@ func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
||||||
// Apply select
|
// Apply select
|
||||||
selectedData := make([]RowType, 0)
|
selectedData := make([]RowType, 0)
|
||||||
for _, row := range result {
|
for _, row := range result {
|
||||||
selectedData = append(selectedData, selectRow(query.SelectItems, query.Parameters, row))
|
selectedData = append(selectedData, ctx.selectRow(query.SelectItems, row))
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedData
|
return selectedData
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectRow(selectItems []parsers.SelectItem, queryParameters map[string]interface{}, row RowType) interface{} {
|
func (c memoryExecutorContext) selectRow(selectItems []parsers.SelectItem, row RowType) interface{} {
|
||||||
// When the first value is top level, select it instead
|
// When the first value is top level, select it instead
|
||||||
if len(selectItems) > 0 && selectItems[0].IsTopLevel {
|
if len(selectItems) > 0 && selectItems[0].IsTopLevel {
|
||||||
return getFieldValue(selectItems[0], queryParameters, row)
|
return c.getFieldValue(selectItems[0], row)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a new row based on the selected columns
|
// Construct a new row based on the selected columns
|
||||||
|
@ -65,21 +73,21 @@ func selectRow(selectItems []parsers.SelectItem, queryParameters map[string]inte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newRow[destinationName] = getFieldValue(column, queryParameters, row)
|
newRow[destinationName] = c.getFieldValue(column, row)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newRow
|
return newRow
|
||||||
}
|
}
|
||||||
|
|
||||||
func evaluateFilters(expr ExpressionType, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) evaluateFilters(expr ExpressionType, row RowType) bool {
|
||||||
if expr == nil {
|
if expr == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typedValue := expr.(type) {
|
switch typedValue := expr.(type) {
|
||||||
case parsers.ComparisonExpression:
|
case parsers.ComparisonExpression:
|
||||||
leftValue := getExpressionParameterValue(typedValue.Left, queryParameters, row)
|
leftValue := c.getExpressionParameterValue(typedValue.Left, row)
|
||||||
rightValue := getExpressionParameterValue(typedValue.Right, queryParameters, row)
|
rightValue := c.getExpressionParameterValue(typedValue.Right, row)
|
||||||
|
|
||||||
cmp := compareValues(leftValue, rightValue)
|
cmp := compareValues(leftValue, rightValue)
|
||||||
switch typedValue.Operation {
|
switch typedValue.Operation {
|
||||||
|
@ -99,7 +107,7 @@ func evaluateFilters(expr ExpressionType, queryParameters map[string]interface{}
|
||||||
case parsers.LogicalExpression:
|
case parsers.LogicalExpression:
|
||||||
var result bool
|
var result bool
|
||||||
for i, expression := range typedValue.Expressions {
|
for i, expression := range typedValue.Expressions {
|
||||||
expressionResult := evaluateFilters(expression, queryParameters, row)
|
expressionResult := c.evaluateFilters(expression, row)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
result = expressionResult
|
result = expressionResult
|
||||||
}
|
}
|
||||||
|
@ -124,7 +132,7 @@ func evaluateFilters(expr ExpressionType, queryParameters map[string]interface{}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
case parsers.SelectItem:
|
case parsers.SelectItem:
|
||||||
resolvedValue := getFieldValue(typedValue, queryParameters, row)
|
resolvedValue := c.getFieldValue(typedValue, row)
|
||||||
if value, ok := resolvedValue.(bool); ok {
|
if value, ok := resolvedValue.(bool); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
@ -132,11 +140,11 @@ func evaluateFilters(expr ExpressionType, queryParameters map[string]interface{}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFieldValue(field parsers.SelectItem, queryParameters map[string]interface{}, row RowType) interface{} {
|
func (c memoryExecutorContext) getFieldValue(field parsers.SelectItem, row RowType) interface{} {
|
||||||
if field.Type == parsers.SelectItemTypeArray {
|
if field.Type == parsers.SelectItemTypeArray {
|
||||||
arrayValue := make([]interface{}, 0)
|
arrayValue := make([]interface{}, 0)
|
||||||
for _, selectItem := range field.SelectItems {
|
for _, selectItem := range field.SelectItems {
|
||||||
arrayValue = append(arrayValue, getFieldValue(selectItem, queryParameters, row))
|
arrayValue = append(arrayValue, c.getFieldValue(selectItem, row))
|
||||||
}
|
}
|
||||||
return arrayValue
|
return arrayValue
|
||||||
}
|
}
|
||||||
|
@ -144,7 +152,7 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
if field.Type == parsers.SelectItemTypeObject {
|
if field.Type == parsers.SelectItemTypeObject {
|
||||||
objectValue := make(map[string]interface{})
|
objectValue := make(map[string]interface{})
|
||||||
for _, selectItem := range field.SelectItems {
|
for _, selectItem := range field.SelectItems {
|
||||||
objectValue[selectItem.Alias] = getFieldValue(selectItem, queryParameters, row)
|
objectValue[selectItem.Alias] = c.getFieldValue(selectItem, row)
|
||||||
}
|
}
|
||||||
return objectValue
|
return objectValue
|
||||||
}
|
}
|
||||||
|
@ -158,9 +166,9 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
}
|
}
|
||||||
|
|
||||||
if typedValue.Type == parsers.ConstantTypeParameterConstant &&
|
if typedValue.Type == parsers.ConstantTypeParameterConstant &&
|
||||||
queryParameters != nil {
|
c.parameters != nil {
|
||||||
if key, ok := typedValue.Value.(string); ok {
|
if key, ok := typedValue.Value.(string); ok {
|
||||||
return queryParameters[key]
|
return c.parameters[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,78 +185,78 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
|
|
||||||
switch typedValue.Type {
|
switch typedValue.Type {
|
||||||
case parsers.FunctionCallStringEquals:
|
case parsers.FunctionCallStringEquals:
|
||||||
return strings_StringEquals(typedValue.Arguments, queryParameters, row)
|
return c.strings_StringEquals(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallContains:
|
case parsers.FunctionCallContains:
|
||||||
return strings_Contains(typedValue.Arguments, queryParameters, row)
|
return c.strings_Contains(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallEndsWith:
|
case parsers.FunctionCallEndsWith:
|
||||||
return strings_EndsWith(typedValue.Arguments, queryParameters, row)
|
return c.strings_EndsWith(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallStartsWith:
|
case parsers.FunctionCallStartsWith:
|
||||||
return strings_StartsWith(typedValue.Arguments, queryParameters, row)
|
return c.strings_StartsWith(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallConcat:
|
case parsers.FunctionCallConcat:
|
||||||
return strings_Concat(typedValue.Arguments, queryParameters, row)
|
return c.strings_Concat(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIndexOf:
|
case parsers.FunctionCallIndexOf:
|
||||||
return strings_IndexOf(typedValue.Arguments, queryParameters, row)
|
return c.strings_IndexOf(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallToString:
|
case parsers.FunctionCallToString:
|
||||||
return strings_ToString(typedValue.Arguments, queryParameters, row)
|
return c.strings_ToString(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallUpper:
|
case parsers.FunctionCallUpper:
|
||||||
return strings_Upper(typedValue.Arguments, queryParameters, row)
|
return c.strings_Upper(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallLower:
|
case parsers.FunctionCallLower:
|
||||||
return strings_Lower(typedValue.Arguments, queryParameters, row)
|
return c.strings_Lower(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallLeft:
|
case parsers.FunctionCallLeft:
|
||||||
return strings_Left(typedValue.Arguments, queryParameters, row)
|
return c.strings_Left(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallLength:
|
case parsers.FunctionCallLength:
|
||||||
return strings_Length(typedValue.Arguments, queryParameters, row)
|
return c.strings_Length(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallLTrim:
|
case parsers.FunctionCallLTrim:
|
||||||
return strings_LTrim(typedValue.Arguments, queryParameters, row)
|
return c.strings_LTrim(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallReplace:
|
case parsers.FunctionCallReplace:
|
||||||
return strings_Replace(typedValue.Arguments, queryParameters, row)
|
return c.strings_Replace(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallReplicate:
|
case parsers.FunctionCallReplicate:
|
||||||
return strings_Replicate(typedValue.Arguments, queryParameters, row)
|
return c.strings_Replicate(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallReverse:
|
case parsers.FunctionCallReverse:
|
||||||
return strings_Reverse(typedValue.Arguments, queryParameters, row)
|
return c.strings_Reverse(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallRight:
|
case parsers.FunctionCallRight:
|
||||||
return strings_Right(typedValue.Arguments, queryParameters, row)
|
return c.strings_Right(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallRTrim:
|
case parsers.FunctionCallRTrim:
|
||||||
return strings_RTrim(typedValue.Arguments, queryParameters, row)
|
return c.strings_RTrim(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallSubstring:
|
case parsers.FunctionCallSubstring:
|
||||||
return strings_Substring(typedValue.Arguments, queryParameters, row)
|
return c.strings_Substring(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallTrim:
|
case parsers.FunctionCallTrim:
|
||||||
return strings_Trim(typedValue.Arguments, queryParameters, row)
|
return c.strings_Trim(typedValue.Arguments, row)
|
||||||
|
|
||||||
case parsers.FunctionCallIsDefined:
|
case parsers.FunctionCallIsDefined:
|
||||||
return typeChecking_IsDefined(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsDefined(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsArray:
|
case parsers.FunctionCallIsArray:
|
||||||
return typeChecking_IsArray(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsArray(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsBool:
|
case parsers.FunctionCallIsBool:
|
||||||
return typeChecking_IsBool(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsBool(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsFiniteNumber:
|
case parsers.FunctionCallIsFiniteNumber:
|
||||||
return typeChecking_IsFiniteNumber(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsFiniteNumber(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsInteger:
|
case parsers.FunctionCallIsInteger:
|
||||||
return typeChecking_IsInteger(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsInteger(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsNull:
|
case parsers.FunctionCallIsNull:
|
||||||
return typeChecking_IsNull(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsNull(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsNumber:
|
case parsers.FunctionCallIsNumber:
|
||||||
return typeChecking_IsNumber(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsNumber(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsObject:
|
case parsers.FunctionCallIsObject:
|
||||||
return typeChecking_IsObject(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsObject(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsPrimitive:
|
case parsers.FunctionCallIsPrimitive:
|
||||||
return typeChecking_IsPrimitive(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsPrimitive(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallIsString:
|
case parsers.FunctionCallIsString:
|
||||||
return typeChecking_IsString(typedValue.Arguments, queryParameters, row)
|
return c.typeChecking_IsString(typedValue.Arguments, row)
|
||||||
|
|
||||||
case parsers.FunctionCallArrayConcat:
|
case parsers.FunctionCallArrayConcat:
|
||||||
return array_Concat(typedValue.Arguments, queryParameters, row)
|
return c.array_Concat(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallArrayLength:
|
case parsers.FunctionCallArrayLength:
|
||||||
return array_Length(typedValue.Arguments, queryParameters, row)
|
return c.array_Length(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallArraySlice:
|
case parsers.FunctionCallArraySlice:
|
||||||
return array_Slice(typedValue.Arguments, queryParameters, row)
|
return c.array_Slice(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallSetIntersect:
|
case parsers.FunctionCallSetIntersect:
|
||||||
return set_Intersect(typedValue.Arguments, queryParameters, row)
|
return c.set_Intersect(typedValue.Arguments, row)
|
||||||
case parsers.FunctionCallSetUnion:
|
case parsers.FunctionCallSetUnion:
|
||||||
return set_Union(typedValue.Arguments, queryParameters, row)
|
return c.set_Union(typedValue.Arguments, row)
|
||||||
|
|
||||||
case parsers.FunctionCallIn:
|
case parsers.FunctionCallIn:
|
||||||
return misc_In(typedValue.Arguments, queryParameters, row)
|
return c.misc_In(typedValue.Arguments, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,14 +273,13 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExpressionParameterValue(
|
func (c memoryExecutorContext) getExpressionParameterValue(
|
||||||
parameter interface{},
|
parameter interface{},
|
||||||
queryParameters map[string]interface{},
|
|
||||||
row RowType,
|
row RowType,
|
||||||
) interface{} {
|
) interface{} {
|
||||||
switch typedParameter := parameter.(type) {
|
switch typedParameter := parameter.(type) {
|
||||||
case parsers.SelectItem:
|
case parsers.SelectItem:
|
||||||
return getFieldValue(typedParameter, queryParameters, row)
|
return c.getFieldValue(typedParameter, row)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("getExpressionParameterValue - got incorrect parameter type")
|
fmt.Println("getExpressionParameterValue - got incorrect parameter type")
|
||||||
|
@ -280,11 +287,11 @@ func getExpressionParameterValue(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func orderBy(orderBy []parsers.OrderExpression, queryParameters map[string]interface{}, data []RowType) {
|
func (c memoryExecutorContext) orderBy(orderBy []parsers.OrderExpression, data []RowType) {
|
||||||
less := func(i, j int) bool {
|
less := func(i, j int) bool {
|
||||||
for _, order := range orderBy {
|
for _, order := range orderBy {
|
||||||
val1 := getFieldValue(order.SelectItem, queryParameters, data[i])
|
val1 := c.getFieldValue(order.SelectItem, data[i])
|
||||||
val2 := getFieldValue(order.SelectItem, queryParameters, data[j])
|
val2 := c.getFieldValue(order.SelectItem, data[j])
|
||||||
|
|
||||||
cmp := compareValues(val1, val2)
|
cmp := compareValues(val1, val2)
|
||||||
if cmp != 0 {
|
if cmp != 0 {
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
package memoryexecutor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
|
||||||
)
|
|
||||||
|
|
||||||
func typeChecking_IsDefined(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
return ex != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsArray(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isArray := ex.([]interface{})
|
|
||||||
return isArray
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsBool(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isBool := ex.(bool)
|
|
||||||
return isBool
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsFiniteNumber(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
switch num := ex.(type) {
|
|
||||||
case int:
|
|
||||||
return true
|
|
||||||
case float64:
|
|
||||||
return !math.IsInf(num, 0) && !math.IsNaN(num)
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsInteger(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isInt := ex.(int)
|
|
||||||
return isInt
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsNull(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
return ex == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsNumber(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isFloat := ex.(float64)
|
|
||||||
_, isInt := ex.(int)
|
|
||||||
return isFloat || isInt
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsObject(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isObject := ex.(map[string]interface{})
|
|
||||||
return isObject
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsPrimitive(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
switch ex.(type) {
|
|
||||||
case bool, string, float64, int, nil:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeChecking_IsString(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
|
||||||
exItem := arguments[0].(parsers.SelectItem)
|
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
|
||||||
|
|
||||||
_, isStr := ex.(string)
|
|
||||||
return isStr
|
|
||||||
}
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func misc_In(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) misc_In(arguments []interface{}, row RowType) bool {
|
||||||
value := getFieldValue(arguments[0].(parsers.SelectItem), queryParameters, row)
|
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row)
|
||||||
|
|
||||||
for i := 1; i < len(arguments); i++ {
|
for i := 1; i < len(arguments); i++ {
|
||||||
compareValue := getFieldValue(arguments[i].(parsers.SelectItem), queryParameters, row)
|
compareValue := c.getFieldValue(arguments[i].(parsers.SelectItem), row)
|
||||||
if compareValues(value, compareValue) == 0 {
|
if compareValues(value, compareValue) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func strings_StringEquals(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) strings_StringEquals(arguments []interface{}, row RowType) bool {
|
||||||
str1 := parseString(arguments[0], queryParameters, row)
|
str1 := c.parseString(arguments[0], row)
|
||||||
str2 := parseString(arguments[1], queryParameters, row)
|
str2 := c.parseString(arguments[1], row)
|
||||||
ignoreCase := getBoolFlag(arguments, queryParameters, row)
|
ignoreCase := c.getBoolFlag(arguments, row)
|
||||||
|
|
||||||
if ignoreCase {
|
if ignoreCase {
|
||||||
return strings.EqualFold(str1, str2)
|
return strings.EqualFold(str1, str2)
|
||||||
|
@ -19,10 +19,10 @@ func strings_StringEquals(arguments []interface{}, queryParameters map[string]in
|
||||||
return str1 == str2
|
return str1 == str2
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Contains(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) strings_Contains(arguments []interface{}, row RowType) bool {
|
||||||
str1 := parseString(arguments[0], queryParameters, row)
|
str1 := c.parseString(arguments[0], row)
|
||||||
str2 := parseString(arguments[1], queryParameters, row)
|
str2 := c.parseString(arguments[1], row)
|
||||||
ignoreCase := getBoolFlag(arguments, queryParameters, row)
|
ignoreCase := c.getBoolFlag(arguments, row)
|
||||||
|
|
||||||
if ignoreCase {
|
if ignoreCase {
|
||||||
str1 = strings.ToLower(str1)
|
str1 = strings.ToLower(str1)
|
||||||
|
@ -32,10 +32,10 @@ func strings_Contains(arguments []interface{}, queryParameters map[string]interf
|
||||||
return strings.Contains(str1, str2)
|
return strings.Contains(str1, str2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_EndsWith(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) strings_EndsWith(arguments []interface{}, row RowType) bool {
|
||||||
str1 := parseString(arguments[0], queryParameters, row)
|
str1 := c.parseString(arguments[0], row)
|
||||||
str2 := parseString(arguments[1], queryParameters, row)
|
str2 := c.parseString(arguments[1], row)
|
||||||
ignoreCase := getBoolFlag(arguments, queryParameters, row)
|
ignoreCase := c.getBoolFlag(arguments, row)
|
||||||
|
|
||||||
if ignoreCase {
|
if ignoreCase {
|
||||||
str1 = strings.ToLower(str1)
|
str1 = strings.ToLower(str1)
|
||||||
|
@ -45,10 +45,10 @@ func strings_EndsWith(arguments []interface{}, queryParameters map[string]interf
|
||||||
return strings.HasSuffix(str1, str2)
|
return strings.HasSuffix(str1, str2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_StartsWith(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) strings_StartsWith(arguments []interface{}, row RowType) bool {
|
||||||
str1 := parseString(arguments[0], queryParameters, row)
|
str1 := c.parseString(arguments[0], row)
|
||||||
str2 := parseString(arguments[1], queryParameters, row)
|
str2 := c.parseString(arguments[1], row)
|
||||||
ignoreCase := getBoolFlag(arguments, queryParameters, row)
|
ignoreCase := c.getBoolFlag(arguments, row)
|
||||||
|
|
||||||
if ignoreCase {
|
if ignoreCase {
|
||||||
str1 = strings.ToLower(str1)
|
str1 = strings.ToLower(str1)
|
||||||
|
@ -58,12 +58,12 @@ func strings_StartsWith(arguments []interface{}, queryParameters map[string]inte
|
||||||
return strings.HasPrefix(str1, str2)
|
return strings.HasPrefix(str1, str2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Concat(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Concat(arguments []interface{}, row RowType) string {
|
||||||
result := ""
|
result := ""
|
||||||
|
|
||||||
for _, arg := range arguments {
|
for _, arg := range arguments {
|
||||||
if selectItem, ok := arg.(parsers.SelectItem); ok {
|
if selectItem, ok := arg.(parsers.SelectItem); ok {
|
||||||
value := getFieldValue(selectItem, queryParameters, row)
|
value := c.getFieldValue(selectItem, row)
|
||||||
result += convertToString(value)
|
result += convertToString(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@ func strings_Concat(arguments []interface{}, queryParameters map[string]interfac
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_IndexOf(arguments []interface{}, queryParameters map[string]interface{}, row RowType) int {
|
func (c memoryExecutorContext) strings_IndexOf(arguments []interface{}, row RowType) int {
|
||||||
str1 := parseString(arguments[0], queryParameters, row)
|
str1 := c.parseString(arguments[0], row)
|
||||||
str2 := parseString(arguments[1], queryParameters, row)
|
str2 := c.parseString(arguments[1], row)
|
||||||
|
|
||||||
start := 0
|
start := 0
|
||||||
if len(arguments) > 2 && arguments[2] != nil {
|
if len(arguments) > 2 && arguments[2] != nil {
|
||||||
if startPos, ok := getFieldValue(arguments[2].(parsers.SelectItem), queryParameters, row).(int); ok {
|
if startPos, ok := c.getFieldValue(arguments[2].(parsers.SelectItem), row).(int); ok {
|
||||||
start = startPos
|
start = startPos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,26 +96,26 @@ func strings_IndexOf(arguments []interface{}, queryParameters map[string]interfa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_ToString(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_ToString(arguments []interface{}, row RowType) string {
|
||||||
value := getFieldValue(arguments[0].(parsers.SelectItem), queryParameters, row)
|
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row)
|
||||||
return convertToString(value)
|
return convertToString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Upper(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Upper(arguments []interface{}, row RowType) string {
|
||||||
value := getFieldValue(arguments[0].(parsers.SelectItem), queryParameters, row)
|
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row)
|
||||||
return strings.ToUpper(convertToString(value))
|
return strings.ToUpper(convertToString(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Lower(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Lower(arguments []interface{}, row RowType) string {
|
||||||
value := getFieldValue(arguments[0].(parsers.SelectItem), queryParameters, row)
|
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row)
|
||||||
return strings.ToLower(convertToString(value))
|
return strings.ToLower(convertToString(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Left(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Left(arguments []interface{}, row RowType) string {
|
||||||
var ok bool
|
var ok bool
|
||||||
var length int
|
var length int
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
lengthEx := getFieldValue(arguments[1].(parsers.SelectItem), queryParameters, row)
|
lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
fmt.Println("strings_Left - got parameters of wrong type")
|
fmt.Println("strings_Left - got parameters of wrong type")
|
||||||
|
@ -133,28 +133,28 @@ func strings_Left(arguments []interface{}, queryParameters map[string]interface{
|
||||||
return str[:length]
|
return str[:length]
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Length(arguments []interface{}, queryParameters map[string]interface{}, row RowType) int {
|
func (c memoryExecutorContext) strings_Length(arguments []interface{}, row RowType) int {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
return len(str)
|
return len(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_LTrim(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_LTrim(arguments []interface{}, row RowType) string {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
return strings.TrimLeft(str, " ")
|
return strings.TrimLeft(str, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Replace(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Replace(arguments []interface{}, row RowType) string {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
oldStr := parseString(arguments[1], queryParameters, row)
|
oldStr := c.parseString(arguments[1], row)
|
||||||
newStr := parseString(arguments[2], queryParameters, row)
|
newStr := c.parseString(arguments[2], row)
|
||||||
return strings.Replace(str, oldStr, newStr, -1)
|
return strings.Replace(str, oldStr, newStr, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Replicate(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Replicate(arguments []interface{}, row RowType) string {
|
||||||
var ok bool
|
var ok bool
|
||||||
var times int
|
var times int
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
timesEx := getFieldValue(arguments[1].(parsers.SelectItem), queryParameters, row)
|
timesEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if times, ok = timesEx.(int); !ok {
|
if times, ok = timesEx.(int); !ok {
|
||||||
fmt.Println("strings_Replicate - got parameters of wrong type")
|
fmt.Println("strings_Replicate - got parameters of wrong type")
|
||||||
|
@ -172,8 +172,8 @@ func strings_Replicate(arguments []interface{}, queryParameters map[string]inter
|
||||||
return strings.Repeat(str, times)
|
return strings.Repeat(str, times)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Reverse(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Reverse(arguments []interface{}, row RowType) string {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
runes := []rune(str)
|
runes := []rune(str)
|
||||||
|
|
||||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
@ -183,11 +183,11 @@ func strings_Reverse(arguments []interface{}, queryParameters map[string]interfa
|
||||||
return string(runes)
|
return string(runes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Right(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Right(arguments []interface{}, row RowType) string {
|
||||||
var ok bool
|
var ok bool
|
||||||
var length int
|
var length int
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
lengthEx := getFieldValue(arguments[1].(parsers.SelectItem), queryParameters, row)
|
lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
fmt.Println("strings_Right - got parameters of wrong type")
|
fmt.Println("strings_Right - got parameters of wrong type")
|
||||||
|
@ -205,18 +205,18 @@ func strings_Right(arguments []interface{}, queryParameters map[string]interface
|
||||||
return str[len(str)-length:]
|
return str[len(str)-length:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_RTrim(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_RTrim(arguments []interface{}, row RowType) string {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
return strings.TrimRight(str, " ")
|
return strings.TrimRight(str, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Substring(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Substring(arguments []interface{}, row RowType) string {
|
||||||
var ok bool
|
var ok bool
|
||||||
var startPos int
|
var startPos int
|
||||||
var length int
|
var length int
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
startPosEx := getFieldValue(arguments[1].(parsers.SelectItem), queryParameters, row)
|
startPosEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row)
|
||||||
lengthEx := getFieldValue(arguments[2].(parsers.SelectItem), queryParameters, row)
|
lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row)
|
||||||
|
|
||||||
if startPos, ok = startPosEx.(int); !ok {
|
if startPos, ok = startPosEx.(int); !ok {
|
||||||
fmt.Println("strings_Substring - got start parameters of wrong type")
|
fmt.Println("strings_Substring - got start parameters of wrong type")
|
||||||
|
@ -239,16 +239,16 @@ func strings_Substring(arguments []interface{}, queryParameters map[string]inter
|
||||||
return str[startPos:endPos]
|
return str[startPos:endPos]
|
||||||
}
|
}
|
||||||
|
|
||||||
func strings_Trim(arguments []interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) strings_Trim(arguments []interface{}, row RowType) string {
|
||||||
str := parseString(arguments[0], queryParameters, row)
|
str := c.parseString(arguments[0], row)
|
||||||
return strings.TrimSpace(str)
|
return strings.TrimSpace(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBoolFlag(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func (c memoryExecutorContext) getBoolFlag(arguments []interface{}, row RowType) bool {
|
||||||
ignoreCase := false
|
ignoreCase := false
|
||||||
if len(arguments) > 2 && arguments[2] != nil {
|
if len(arguments) > 2 && arguments[2] != nil {
|
||||||
ignoreCaseItem := arguments[2].(parsers.SelectItem)
|
ignoreCaseItem := arguments[2].(parsers.SelectItem)
|
||||||
if value, ok := getFieldValue(ignoreCaseItem, queryParameters, row).(bool); ok {
|
if value, ok := c.getFieldValue(ignoreCaseItem, row).(bool); ok {
|
||||||
ignoreCase = value
|
ignoreCase = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,9 +256,9 @@ func getBoolFlag(arguments []interface{}, queryParameters map[string]interface{}
|
||||||
return ignoreCase
|
return ignoreCase
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseString(argument interface{}, queryParameters map[string]interface{}, row RowType) string {
|
func (c memoryExecutorContext) parseString(argument interface{}, row RowType) string {
|
||||||
exItem := argument.(parsers.SelectItem)
|
exItem := argument.(parsers.SelectItem)
|
||||||
ex := getFieldValue(exItem, queryParameters, row)
|
ex := c.getFieldValue(exItem, row)
|
||||||
if str1, ok := ex.(string); ok {
|
if str1, ok := ex.(string); ok {
|
||||||
return str1
|
return str1
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package memoryexecutor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsDefined(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
return ex != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsArray(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isArray := ex.([]interface{})
|
||||||
|
return isArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsBool(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isBool := ex.(bool)
|
||||||
|
return isBool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsFiniteNumber(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
switch num := ex.(type) {
|
||||||
|
case int:
|
||||||
|
return true
|
||||||
|
case float64:
|
||||||
|
return !math.IsInf(num, 0) && !math.IsNaN(num)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsInteger(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isInt := ex.(int)
|
||||||
|
return isInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsNull(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
return ex == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsNumber(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isFloat := ex.(float64)
|
||||||
|
_, isInt := ex.(int)
|
||||||
|
return isFloat || isInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsObject(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isObject := ex.(map[string]interface{})
|
||||||
|
return isObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsPrimitive(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
switch ex.(type) {
|
||||||
|
case bool, string, float64, int, nil:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c memoryExecutorContext) typeChecking_IsString(arguments []interface{}, row RowType) bool {
|
||||||
|
exItem := arguments[0].(parsers.SelectItem)
|
||||||
|
ex := c.getFieldValue(exItem, row)
|
||||||
|
|
||||||
|
_, isStr := ex.(string)
|
||||||
|
return isStr
|
||||||
|
}
|
24
tests.http
24
tests.http
|
@ -1,24 +0,0 @@
|
||||||
### Create collection
|
|
||||||
|
|
||||||
POST https://localhost:8081/dbs/db1/colls
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{"id":"test1", "partitionKey":{"paths":["/pk"],"kind":"Hash","version":2}}
|
|
||||||
|
|
||||||
### Insert document
|
|
||||||
|
|
||||||
POST https://localhost:8081/dbs/db1/colls/test/docs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{"id":"1","_pk":"123","isCool":true}
|
|
||||||
|
|
||||||
### Get all documents
|
|
||||||
|
|
||||||
GET https://localhost:8081/dbs/db1/colls/test/docs
|
|
||||||
|
|
||||||
### Query documents
|
|
||||||
|
|
||||||
POST https://localhost:8081/dbs/db1/colls/test/docs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{"query":"SELECT c.id, c.isCool AS cool FROM c WHERE c.isCool = false"}
|
|
Loading…
Reference in New Issue