mirror of
https://github.com/pikami/cosmium.git
synced 2026-01-26 04:42:58 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b8b087aab | ||
|
|
c2c9dc03b3 | ||
|
|
d86bac7d79 | ||
|
|
69b76c1c3e | ||
|
|
8e3db3e44d |
@@ -78,7 +78,7 @@ To disable SSL and run Cosmium on HTTP instead, you can use the `-DisableTls` fl
|
|||||||
- **-InitialData**: Path to JSON containing initial state
|
- **-InitialData**: Path to JSON containing initial state
|
||||||
- **-Persist**: Saves data to the given path on application exit (When `-InitialData` argument is not supplied, it will try to load data from path supplied in `-Persist`)
|
- **-Persist**: Saves data to the given path on application exit (When `-InitialData` argument is not supplied, it will try to load data from path supplied in `-Persist`)
|
||||||
- **-Port**: Listen port (default 8081)
|
- **-Port**: Listen port (default 8081)
|
||||||
- **-Debug**: Runs application in debug mode, this provides additional logging
|
- **-LogLevel**: Sets the logging level (one of: debug, info, error, silent) (default info)
|
||||||
|
|
||||||
These arguments allow you to configure various aspects of Cosmium's behavior according to your requirements.
|
These arguments allow you to configure various aspects of Cosmium's behavior according to your requirements.
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ All mentioned arguments can also be set using environment variables:
|
|||||||
- **COSMIUM_INITIALDATA** for `-InitialData`
|
- **COSMIUM_INITIALDATA** for `-InitialData`
|
||||||
- **COSMIUM_PERSIST** for `-Persist`
|
- **COSMIUM_PERSIST** for `-Persist`
|
||||||
- **COSMIUM_PORT** for `-Port`
|
- **COSMIUM_PORT** for `-Port`
|
||||||
- **COSMIUM_DEBUG** for `-Debug`
|
- **COSMIUM_LOGLEVEL** for `-LogLevel`
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ func ParseFlags() ServerConfig {
|
|||||||
disableAuthentication := flag.Bool("DisableAuth", false, "Disable authentication")
|
disableAuthentication := flag.Bool("DisableAuth", false, "Disable authentication")
|
||||||
disableTls := flag.Bool("DisableTls", false, "Disable TLS, serve over HTTP")
|
disableTls := flag.Bool("DisableTls", false, "Disable TLS, serve over HTTP")
|
||||||
persistDataPath := flag.String("Persist", "", "Saves data to given path on application exit")
|
persistDataPath := flag.String("Persist", "", "Saves data to given path on application exit")
|
||||||
debug := flag.Bool("Debug", false, "Runs application in debug mode, this provides additional logging")
|
logLevel := NewEnumValue("info", []string{"debug", "info", "error", "silent"})
|
||||||
|
flag.Var(logLevel, "LogLevel", fmt.Sprintf("Sets the logging level %s", logLevel.AllowedValuesList()))
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
setFlagsFromEnvironment()
|
setFlagsFromEnvironment()
|
||||||
@@ -41,8 +42,8 @@ func ParseFlags() ServerConfig {
|
|||||||
config.PersistDataFilePath = *persistDataPath
|
config.PersistDataFilePath = *persistDataPath
|
||||||
config.DisableAuth = *disableAuthentication
|
config.DisableAuth = *disableAuthentication
|
||||||
config.DisableTls = *disableTls
|
config.DisableTls = *disableTls
|
||||||
config.Debug = *debug
|
|
||||||
config.AccountKey = *accountKey
|
config.AccountKey = *accountKey
|
||||||
|
config.LogLevel = logLevel.value
|
||||||
|
|
||||||
config.PopulateCalculatedFields()
|
config.PopulateCalculatedFields()
|
||||||
|
|
||||||
@@ -54,7 +55,19 @@ func (c *ServerConfig) PopulateCalculatedFields() {
|
|||||||
c.DatabaseDomain = c.Host
|
c.DatabaseDomain = c.Host
|
||||||
c.DatabaseEndpoint = fmt.Sprintf("https://%s:%d/", c.Host, c.Port)
|
c.DatabaseEndpoint = fmt.Sprintf("https://%s:%d/", c.Host, c.Port)
|
||||||
c.ExplorerBaseUrlLocation = ExplorerBaseUrlLocation
|
c.ExplorerBaseUrlLocation = ExplorerBaseUrlLocation
|
||||||
logger.EnableDebugOutput = c.Debug
|
|
||||||
|
switch c.LogLevel {
|
||||||
|
case "debug":
|
||||||
|
logger.LogLevel = logger.LogLevelDebug
|
||||||
|
case "info":
|
||||||
|
logger.LogLevel = logger.LogLevelInfo
|
||||||
|
case "error":
|
||||||
|
logger.LogLevel = logger.LogLevelError
|
||||||
|
case "silent":
|
||||||
|
logger.LogLevel = logger.LogLevelSilent
|
||||||
|
default:
|
||||||
|
logger.LogLevel = logger.LogLevelInfo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ServerConfig) ApplyDefaultsToEmptyFields() {
|
func (c *ServerConfig) ApplyDefaultsToEmptyFields() {
|
||||||
|
|||||||
36
api/config/enumFlag.go
Normal file
36
api/config/enumFlag.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnumValue struct {
|
||||||
|
allowedValues []string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EnumValue) String() string {
|
||||||
|
return e.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EnumValue) Set(v string) error {
|
||||||
|
for _, allowed := range e.allowedValues {
|
||||||
|
if v == allowed {
|
||||||
|
e.value = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("invalid value %q, must be one of: %s", v, strings.Join(e.allowedValues, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnumValue(defaultValue string, allowedValues []string) *EnumValue {
|
||||||
|
return &EnumValue{
|
||||||
|
allowedValues: allowedValues,
|
||||||
|
value: defaultValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EnumValue) AllowedValuesList() string {
|
||||||
|
return fmt.Sprintf("(one of: %s)", strings.Join(e.allowedValues, ", "))
|
||||||
|
}
|
||||||
@@ -15,6 +15,6 @@ type ServerConfig struct {
|
|||||||
PersistDataFilePath string `json:"persistDataFilePath"`
|
PersistDataFilePath string `json:"persistDataFilePath"`
|
||||||
DisableAuth bool `json:"disableAuth"`
|
DisableAuth bool `json:"disableAuth"`
|
||||||
DisableTls bool `json:"disableTls"`
|
DisableTls bool `json:"disableTls"`
|
||||||
Debug bool `json:"debug"`
|
LogLevel string `json:"logLevel"`
|
||||||
ExplorerBaseUrlLocation string `json:"explorerBaseUrlLocation"`
|
ExplorerBaseUrlLocation string `json:"explorerBaseUrlLocation"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func (h *Handlers) PatchDocument(c *gin.Context) {
|
|||||||
|
|
||||||
currentDocumentBytes, err := json.Marshal(document)
|
currentDocumentBytes, err := json.Marshal(document)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to marshal existing document:", err)
|
logger.ErrorLn("Failed to marshal existing document:", err)
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to marshal existing document"})
|
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to marshal existing document"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ func (h *Handlers) PatchDocument(c *gin.Context) {
|
|||||||
var modifiedDocument map[string]interface{}
|
var modifiedDocument map[string]interface{}
|
||||||
err = json.Unmarshal(modifiedDocumentBytes, &modifiedDocument)
|
err = json.Unmarshal(modifiedDocumentBytes, &modifiedDocument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to unmarshal modified document:", err)
|
logger.ErrorLn("Failed to unmarshal modified document:", err)
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to unmarshal modified document"})
|
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to unmarshal modified document"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ func requestToResourceId(c *gin.Context) string {
|
|||||||
|
|
||||||
isFeed := c.Request.Header.Get("A-Im") == "Incremental Feed"
|
isFeed := c.Request.Header.Get("A-Im") == "Incremental Feed"
|
||||||
if resourceType == "pkranges" && isFeed {
|
if resourceType == "pkranges" && isFeed {
|
||||||
resourceId = collId
|
// CosmosSDK replaces '/' with '-' in resource id requests
|
||||||
|
resourceId = strings.Replace(collId, "-", "/", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resourceId
|
return resourceId
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func RequestLogger() gin.HandlerFunc {
|
|||||||
|
|
||||||
bodyStr := readBody(rdr1)
|
bodyStr := readBody(rdr1)
|
||||||
if bodyStr != "" {
|
if bodyStr != "" {
|
||||||
logger.Debug(bodyStr)
|
logger.DebugLn(bodyStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Request.Body = rdr2
|
c.Request.Body = rdr2
|
||||||
|
|||||||
@@ -22,3 +22,97 @@ func (h *Handlers) GetAllStoredProcedures(c *gin.Context) {
|
|||||||
|
|
||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) GetStoredProcedure(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
spId := c.Param("spId")
|
||||||
|
|
||||||
|
sp, status := h.repository.GetStoredProcedure(databaseId, collectionId, spId)
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, sp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) DeleteStoredProcedure(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
spId := c.Param("spId")
|
||||||
|
|
||||||
|
status := h.repository.DeleteStoredProcedure(databaseId, collectionId, spId)
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) ReplaceStoredProcedure(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
spId := c.Param("spId")
|
||||||
|
|
||||||
|
var sp repositorymodels.StoredProcedure
|
||||||
|
if err := c.BindJSON(&sp); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status := h.repository.DeleteStoredProcedure(databaseId, collectionId, spId)
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdSP, status := h.repository.CreateStoredProcedure(databaseId, collectionId, sp)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, createdSP)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) CreateStoredProcedure(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
|
var sp repositorymodels.StoredProcedure
|
||||||
|
if err := c.BindJSON(&sp); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdSP, status := h.repository.CreateStoredProcedure(databaseId, collectionId, sp)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusCreated, createdSP)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,3 +22,97 @@ func (h *Handlers) GetAllTriggers(c *gin.Context) {
|
|||||||
|
|
||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) GetTrigger(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
|
trigger, status := h.repository.GetTrigger(databaseId, collectionId, triggerId)
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, trigger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) DeleteTrigger(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
|
status := h.repository.DeleteTrigger(databaseId, collectionId, triggerId)
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) ReplaceTrigger(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
|
var trigger repositorymodels.Trigger
|
||||||
|
if err := c.BindJSON(&trigger); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status := h.repository.DeleteTrigger(databaseId, collectionId, triggerId)
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdTrigger, status := h.repository.CreateTrigger(databaseId, collectionId, trigger)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, createdTrigger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) CreateTrigger(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
|
var trigger repositorymodels.Trigger
|
||||||
|
if err := c.BindJSON(&trigger); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdTrigger, status := h.repository.CreateTrigger(databaseId, collectionId, trigger)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusCreated, createdTrigger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,3 +22,97 @@ func (h *Handlers) GetAllUserDefinedFunctions(c *gin.Context) {
|
|||||||
|
|
||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) GetUserDefinedFunction(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
|
udf, status := h.repository.GetUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, udf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) DeleteUserDefinedFunction(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
|
status := h.repository.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) ReplaceUserDefinedFunction(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
|
var udf repositorymodels.UserDefinedFunction
|
||||||
|
if err := c.BindJSON(&udf); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status := h.repository.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
|
if status == repositorymodels.StatusNotFound {
|
||||||
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdUdf, status := h.repository.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusOK, createdUdf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) CreateUserDefinedFunction(c *gin.Context) {
|
||||||
|
databaseId := c.Param("databaseId")
|
||||||
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
|
var udf repositorymodels.UserDefinedFunction
|
||||||
|
if err := c.BindJSON(&udf); err != nil {
|
||||||
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdUdf, status := h.repository.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
||||||
|
if status == repositorymodels.Conflict {
|
||||||
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == repositorymodels.StatusOk {
|
||||||
|
c.IndentedJSON(http.StatusCreated, createdUdf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import (
|
|||||||
func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
|
func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
|
||||||
routeHandlers := handlers.NewHandlers(repository, s.config)
|
routeHandlers := handlers.NewHandlers(repository, s.config)
|
||||||
|
|
||||||
if !s.config.Debug {
|
gin.DefaultWriter = logger.InfoWriter()
|
||||||
|
gin.DefaultErrorWriter = logger.ErrorWriter()
|
||||||
|
|
||||||
|
if s.config.LogLevel != "debug" {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +27,7 @@ func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
|
|||||||
e.RedirectTrailingSlash = false
|
e.RedirectTrailingSlash = false
|
||||||
})
|
})
|
||||||
|
|
||||||
if s.config.Debug {
|
if s.config.LogLevel == "debug" {
|
||||||
router.Use(middleware.RequestLogger())
|
router.Use(middleware.RequestLogger())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,9 +53,23 @@ func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
|
|||||||
router.GET("/dbs/:databaseId", routeHandlers.GetDatabase)
|
router.GET("/dbs/:databaseId", routeHandlers.GetDatabase)
|
||||||
router.DELETE("/dbs/:databaseId", routeHandlers.DeleteDatabase)
|
router.DELETE("/dbs/:databaseId", routeHandlers.DeleteDatabase)
|
||||||
|
|
||||||
router.GET("/dbs/:databaseId/colls/:collId/udfs", routeHandlers.GetAllUserDefinedFunctions)
|
router.POST("/dbs/:databaseId/colls/:collId/triggers", routeHandlers.CreateTrigger)
|
||||||
router.GET("/dbs/:databaseId/colls/:collId/sprocs", routeHandlers.GetAllStoredProcedures)
|
|
||||||
router.GET("/dbs/:databaseId/colls/:collId/triggers", routeHandlers.GetAllTriggers)
|
router.GET("/dbs/:databaseId/colls/:collId/triggers", routeHandlers.GetAllTriggers)
|
||||||
|
router.GET("/dbs/:databaseId/colls/:collId/triggers/:triggerId", routeHandlers.GetTrigger)
|
||||||
|
router.PUT("/dbs/:databaseId/colls/:collId/triggers/:triggerId", routeHandlers.ReplaceTrigger)
|
||||||
|
router.DELETE("/dbs/:databaseId/colls/:collId/triggers/:triggerId", routeHandlers.DeleteTrigger)
|
||||||
|
|
||||||
|
router.POST("/dbs/:databaseId/colls/:collId/sprocs", routeHandlers.CreateStoredProcedure)
|
||||||
|
router.GET("/dbs/:databaseId/colls/:collId/sprocs", routeHandlers.GetAllStoredProcedures)
|
||||||
|
router.GET("/dbs/:databaseId/colls/:collId/sprocs/:sprocId", routeHandlers.GetStoredProcedure)
|
||||||
|
router.PUT("/dbs/:databaseId/colls/:collId/sprocs/:sprocId", routeHandlers.ReplaceStoredProcedure)
|
||||||
|
router.DELETE("/dbs/:databaseId/colls/:collId/sprocs/:sprocId", routeHandlers.DeleteStoredProcedure)
|
||||||
|
|
||||||
|
router.POST("/dbs/:databaseId/colls/:collId/udfs", routeHandlers.CreateUserDefinedFunction)
|
||||||
|
router.GET("/dbs/:databaseId/colls/:collId/udfs", routeHandlers.GetAllUserDefinedFunctions)
|
||||||
|
router.GET("/dbs/:databaseId/colls/:collId/udfs/:udfId", routeHandlers.GetUserDefinedFunction)
|
||||||
|
router.PUT("/dbs/:databaseId/colls/:collId/udfs/:udfId", routeHandlers.ReplaceUserDefinedFunction)
|
||||||
|
router.DELETE("/dbs/:databaseId/colls/:collId/udfs/:udfId", routeHandlers.DeleteUserDefinedFunction)
|
||||||
|
|
||||||
router.GET("/offers", handlers.GetOffers)
|
router.GET("/offers", handlers.GetOffers)
|
||||||
router.GET("/", routeHandlers.GetServerInfo)
|
router.GET("/", routeHandlers.GetServerInfo)
|
||||||
@@ -75,10 +92,10 @@ func (s *ApiServer) Start() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-s.stopServer
|
<-s.stopServer
|
||||||
logger.Info("Shutting down server...")
|
logger.InfoLn("Shutting down server...")
|
||||||
err := server.Shutdown(context.TODO())
|
err := server.Shutdown(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to shutdown server:", err)
|
logger.ErrorLn("Failed to shutdown server:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -87,7 +104,7 @@ func (s *ApiServer) Start() {
|
|||||||
logger.Infof("Listening and serving HTTP on %s\n", server.Addr)
|
logger.Infof("Listening and serving HTTP on %s\n", server.Addr)
|
||||||
err := server.ListenAndServe()
|
err := server.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to start HTTP server:", err)
|
logger.ErrorLn("Failed to start HTTP server:", err)
|
||||||
}
|
}
|
||||||
s.isActive = false
|
s.isActive = false
|
||||||
} else if s.config.TLS_CertificatePath != "" && s.config.TLS_CertificateKey != "" {
|
} else if s.config.TLS_CertificatePath != "" && s.config.TLS_CertificateKey != "" {
|
||||||
@@ -96,7 +113,7 @@ func (s *ApiServer) Start() {
|
|||||||
s.config.TLS_CertificatePath,
|
s.config.TLS_CertificatePath,
|
||||||
s.config.TLS_CertificateKey)
|
s.config.TLS_CertificateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to start HTTPS server:", err)
|
logger.ErrorLn("Failed to start HTTPS server:", err)
|
||||||
}
|
}
|
||||||
s.isActive = false
|
s.isActive = false
|
||||||
} else {
|
} else {
|
||||||
@@ -106,7 +123,7 @@ func (s *ApiServer) Start() {
|
|||||||
logger.Infof("Listening and serving HTTPS on %s\n", server.Addr)
|
logger.Infof("Listening and serving HTTPS on %s\n", server.Addr)
|
||||||
err := server.ListenAndServeTLS("", "")
|
err := server.ListenAndServeTLS("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to start HTTPS server:", err)
|
logger.ErrorLn("Failed to start HTTPS server:", err)
|
||||||
}
|
}
|
||||||
s.isActive = false
|
s.isActive = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ Cosmium strives to support the core features of Cosmos DB, including:
|
|||||||
| Function | Implemented |
|
| Function | Implemented |
|
||||||
| ------------------ | ----------- |
|
| ------------------ | ----------- |
|
||||||
| ARRAY_CONCAT | Yes |
|
| ARRAY_CONCAT | Yes |
|
||||||
| ARRAY_CONTAINS | No |
|
| ARRAY_CONTAINS | Yes |
|
||||||
| ARRAY_CONTAINS_ANY | No |
|
| ARRAY_CONTAINS_ANY | Yes |
|
||||||
| ARRAY_CONTAINS_ALL | No |
|
| ARRAY_CONTAINS_ALL | Yes |
|
||||||
| ARRAY_LENGTH | Yes |
|
| ARRAY_LENGTH | Yes |
|
||||||
| ARRAY_SLICE | Yes |
|
| ARRAY_SLICE | Yes |
|
||||||
| CHOOSE | No |
|
| CHOOSE | No |
|
||||||
|
|||||||
@@ -5,36 +5,100 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var EnableDebugOutput = false
|
type LogLevelType int
|
||||||
|
|
||||||
|
var (
|
||||||
|
LogLevelDebug LogLevelType = 0
|
||||||
|
LogLevelInfo LogLevelType = 1
|
||||||
|
LogLevelError LogLevelType = 2
|
||||||
|
LogLevelSilent LogLevelType = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogWriter struct {
|
||||||
|
WriterLevel LogLevelType
|
||||||
|
}
|
||||||
|
|
||||||
|
var LogLevel = LogLevelInfo
|
||||||
|
|
||||||
var DebugLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)
|
var DebugLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)
|
||||||
var InfoLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime)
|
var InfoLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime)
|
||||||
var ErrorLogger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
|
var ErrorLogger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
|
||||||
|
|
||||||
func Debug(v ...any) {
|
func DebugLn(v ...any) {
|
||||||
if EnableDebugOutput {
|
if LogLevel <= LogLevelDebug {
|
||||||
DebugLogger.Println(v...)
|
DebugLogger.Println(v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Debug(v ...any) {
|
||||||
|
if LogLevel <= LogLevelDebug {
|
||||||
|
DebugLogger.Print(v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Debugf(format string, v ...any) {
|
func Debugf(format string, v ...any) {
|
||||||
if EnableDebugOutput {
|
if LogLevel <= LogLevelDebug {
|
||||||
DebugLogger.Printf(format, v...)
|
DebugLogger.Printf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InfoLn(v ...any) {
|
||||||
|
if LogLevel <= LogLevelInfo {
|
||||||
|
InfoLogger.Println(v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Info(v ...any) {
|
func Info(v ...any) {
|
||||||
InfoLogger.Println(v...)
|
if LogLevel <= LogLevelInfo {
|
||||||
|
InfoLogger.Print(v...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Infof(format string, v ...any) {
|
func Infof(format string, v ...any) {
|
||||||
InfoLogger.Printf(format, v...)
|
if LogLevel <= LogLevelInfo {
|
||||||
|
InfoLogger.Printf(format, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorLn(v ...any) {
|
||||||
|
if LogLevel <= LogLevelError {
|
||||||
|
ErrorLogger.Println(v...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Error(v ...any) {
|
func Error(v ...any) {
|
||||||
ErrorLogger.Println(v...)
|
if LogLevel <= LogLevelError {
|
||||||
|
ErrorLogger.Print(v...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Errorf(format string, v ...any) {
|
func Errorf(format string, v ...any) {
|
||||||
ErrorLogger.Printf(format, v...)
|
if LogLevel <= LogLevelError {
|
||||||
|
ErrorLogger.Printf(format, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogWriter) Write(p []byte) (n int, err error) {
|
||||||
|
switch lw.WriterLevel {
|
||||||
|
case LogLevelDebug:
|
||||||
|
Debug(string(p))
|
||||||
|
case LogLevelInfo:
|
||||||
|
Info(string(p))
|
||||||
|
case LogLevelError:
|
||||||
|
Error(string(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorWriter() *LogWriter {
|
||||||
|
return &LogWriter{WriterLevel: LogLevelError}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoWriter() *LogWriter {
|
||||||
|
return &LogWriter{WriterLevel: LogLevelInfo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DebugWriter() *LogWriter {
|
||||||
|
return &LogWriter{WriterLevel: LogLevelDebug}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ func (r *DataRepository) CreateCollection(databaseId string, newCollection repos
|
|||||||
|
|
||||||
r.storeState.Collections[databaseId][newCollection.ID] = newCollection
|
r.storeState.Collections[databaseId][newCollection.ID] = newCollection
|
||||||
r.storeState.Documents[databaseId][newCollection.ID] = make(map[string]repositorymodels.Document)
|
r.storeState.Documents[databaseId][newCollection.ID] = make(map[string]repositorymodels.Document)
|
||||||
|
r.storeState.Triggers[databaseId][newCollection.ID] = make(map[string]repositorymodels.Trigger)
|
||||||
|
r.storeState.StoredProcedures[databaseId][newCollection.ID] = make(map[string]repositorymodels.StoredProcedure)
|
||||||
|
r.storeState.UserDefinedFunctions[databaseId][newCollection.ID] = make(map[string]repositorymodels.UserDefinedFunction)
|
||||||
|
|
||||||
return newCollection, repositorymodels.StatusOk
|
return newCollection, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ func (r *DataRepository) CreateDatabase(newDatabase repositorymodels.Database) (
|
|||||||
r.storeState.Databases[newDatabase.ID] = newDatabase
|
r.storeState.Databases[newDatabase.ID] = newDatabase
|
||||||
r.storeState.Collections[newDatabase.ID] = make(map[string]repositorymodels.Collection)
|
r.storeState.Collections[newDatabase.ID] = make(map[string]repositorymodels.Collection)
|
||||||
r.storeState.Documents[newDatabase.ID] = make(map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents[newDatabase.ID] = make(map[string]map[string]repositorymodels.Document)
|
||||||
|
r.storeState.Triggers[newDatabase.ID] = make(map[string]map[string]repositorymodels.Trigger)
|
||||||
|
r.storeState.StoredProcedures[newDatabase.ID] = make(map[string]map[string]repositorymodels.StoredProcedure)
|
||||||
|
r.storeState.UserDefinedFunctions[newDatabase.ID] = make(map[string]map[string]repositorymodels.UserDefinedFunction)
|
||||||
|
|
||||||
return newDatabase, repositorymodels.StatusOk
|
return newDatabase, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ package repositories
|
|||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
|
||||||
type DataRepository struct {
|
type DataRepository struct {
|
||||||
storedProcedures []repositorymodels.StoredProcedure
|
storeState repositorymodels.State
|
||||||
triggers []repositorymodels.Trigger
|
|
||||||
userDefinedFunctions []repositorymodels.UserDefinedFunction
|
|
||||||
storeState repositorymodels.State
|
|
||||||
|
|
||||||
initialDataFilePath string
|
initialDataFilePath string
|
||||||
persistDataFilePath string
|
persistDataFilePath string
|
||||||
@@ -19,13 +16,13 @@ type RepositoryOptions struct {
|
|||||||
|
|
||||||
func NewDataRepository(options RepositoryOptions) *DataRepository {
|
func NewDataRepository(options RepositoryOptions) *DataRepository {
|
||||||
repository := &DataRepository{
|
repository := &DataRepository{
|
||||||
storedProcedures: []repositorymodels.StoredProcedure{},
|
|
||||||
triggers: []repositorymodels.Trigger{},
|
|
||||||
userDefinedFunctions: []repositorymodels.UserDefinedFunction{},
|
|
||||||
storeState: repositorymodels.State{
|
storeState: repositorymodels.State{
|
||||||
Databases: make(map[string]repositorymodels.Database),
|
Databases: make(map[string]repositorymodels.Database),
|
||||||
Collections: make(map[string]map[string]repositorymodels.Collection),
|
Collections: make(map[string]map[string]repositorymodels.Collection),
|
||||||
Documents: make(map[string]map[string]map[string]repositorymodels.Document),
|
Documents: make(map[string]map[string]map[string]repositorymodels.Document),
|
||||||
|
Triggers: make(map[string]map[string]map[string]repositorymodels.Trigger),
|
||||||
|
StoredProcedures: make(map[string]map[string]map[string]repositorymodels.StoredProcedure),
|
||||||
|
UserDefinedFunctions: make(map[string]map[string]map[string]repositorymodels.UserDefinedFunction),
|
||||||
},
|
},
|
||||||
initialDataFilePath: options.InitialDataFilePath,
|
initialDataFilePath: options.InitialDataFilePath,
|
||||||
persistDataFilePath: options.PersistDataFilePath,
|
persistDataFilePath: options.PersistDataFilePath,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func (r *DataRepository) InitializeRepository() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stat.IsDir() {
|
if stat.IsDir() {
|
||||||
logger.Error("Argument '-Persist' must be a path to file, not a directory.")
|
logger.ErrorLn("Argument '-Persist' must be a path to file, not a directory.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,10 +60,13 @@ func (r *DataRepository) LoadStateJSON(jsonData string) error {
|
|||||||
|
|
||||||
r.ensureStoreStateNoNullReferences()
|
r.ensureStoreStateNoNullReferences()
|
||||||
|
|
||||||
logger.Info("Loaded state:")
|
logger.InfoLn("Loaded state:")
|
||||||
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
||||||
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
||||||
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
||||||
|
logger.Infof("Triggers: %d\n", getLength(r.storeState.Triggers))
|
||||||
|
logger.Infof("Stored procedures: %d\n", getLength(r.storeState.StoredProcedures))
|
||||||
|
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -80,10 +83,13 @@ func (r *DataRepository) SaveStateFS(filePath string) {
|
|||||||
|
|
||||||
os.WriteFile(filePath, data, os.ModePerm)
|
os.WriteFile(filePath, data, os.ModePerm)
|
||||||
|
|
||||||
logger.Info("Saved state:")
|
logger.InfoLn("Saved state:")
|
||||||
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
||||||
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
||||||
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
||||||
|
logger.Infof("Triggers: %d\n", getLength(r.storeState.Triggers))
|
||||||
|
logger.Infof("Stored procedures: %d\n", getLength(r.storeState.StoredProcedures))
|
||||||
|
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) GetState() (string, error) {
|
func (r *DataRepository) GetState() (string, error) {
|
||||||
@@ -103,7 +109,10 @@ func getLength(v interface{}) int {
|
|||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case repositorymodels.Database,
|
case repositorymodels.Database,
|
||||||
repositorymodels.Collection,
|
repositorymodels.Collection,
|
||||||
repositorymodels.Document:
|
repositorymodels.Document,
|
||||||
|
repositorymodels.Trigger,
|
||||||
|
repositorymodels.StoredProcedure,
|
||||||
|
repositorymodels.UserDefinedFunction:
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +146,18 @@ func (r *DataRepository) ensureStoreStateNoNullReferences() {
|
|||||||
r.storeState.Documents = make(map[string]map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents = make(map[string]map[string]map[string]repositorymodels.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.storeState.Triggers == nil {
|
||||||
|
r.storeState.Triggers = make(map[string]map[string]map[string]repositorymodels.Trigger)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.StoredProcedures == nil {
|
||||||
|
r.storeState.StoredProcedures = make(map[string]map[string]map[string]repositorymodels.StoredProcedure)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.UserDefinedFunctions == nil {
|
||||||
|
r.storeState.UserDefinedFunctions = make(map[string]map[string]map[string]repositorymodels.UserDefinedFunction)
|
||||||
|
}
|
||||||
|
|
||||||
for database := range r.storeState.Databases {
|
for database := range r.storeState.Databases {
|
||||||
if r.storeState.Collections[database] == nil {
|
if r.storeState.Collections[database] == nil {
|
||||||
r.storeState.Collections[database] = make(map[string]repositorymodels.Collection)
|
r.storeState.Collections[database] = make(map[string]repositorymodels.Collection)
|
||||||
@@ -146,6 +167,18 @@ func (r *DataRepository) ensureStoreStateNoNullReferences() {
|
|||||||
r.storeState.Documents[database] = make(map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents[database] = make(map[string]map[string]repositorymodels.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.storeState.Triggers[database] == nil {
|
||||||
|
r.storeState.Triggers[database] = make(map[string]map[string]repositorymodels.Trigger)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.StoredProcedures[database] == nil {
|
||||||
|
r.storeState.StoredProcedures[database] = make(map[string]map[string]repositorymodels.StoredProcedure)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.UserDefinedFunctions[database] == nil {
|
||||||
|
r.storeState.UserDefinedFunctions[database] = make(map[string]map[string]repositorymodels.UserDefinedFunction)
|
||||||
|
}
|
||||||
|
|
||||||
for collection := range r.storeState.Collections[database] {
|
for collection := range r.storeState.Collections[database] {
|
||||||
if r.storeState.Documents[database][collection] == nil {
|
if r.storeState.Documents[database][collection] == nil {
|
||||||
r.storeState.Documents[database][collection] = make(map[string]repositorymodels.Document)
|
r.storeState.Documents[database][collection] = make(map[string]repositorymodels.Document)
|
||||||
@@ -156,6 +189,18 @@ func (r *DataRepository) ensureStoreStateNoNullReferences() {
|
|||||||
delete(r.storeState.Documents[database][collection], document)
|
delete(r.storeState.Documents[database][collection], document)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.storeState.Triggers[database][collection] == nil {
|
||||||
|
r.storeState.Triggers[database][collection] = make(map[string]repositorymodels.Trigger)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.StoredProcedures[database][collection] == nil {
|
||||||
|
r.storeState.StoredProcedures[database][collection] = make(map[string]repositorymodels.StoredProcedure)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.storeState.UserDefinedFunctions[database][collection] == nil {
|
||||||
|
r.storeState.UserDefinedFunctions[database][collection] = make(map[string]repositorymodels.UserDefinedFunction)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,91 @@
|
|||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
func (r *DataRepository) GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
||||||
return r.storedProcedures, repositorymodels.StatusOk
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.StoredProcedures[databaseId][collectionId]), repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) GetStoredProcedure(databaseId string, collectionId string, spId string) (repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; ok {
|
||||||
|
return sp, repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) DeleteStoredProcedure(databaseId string, collectionId string, spId string) repositorymodels.RepositoryStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.StoredProcedures[databaseId][collectionId], spId)
|
||||||
|
|
||||||
|
return repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) CreateStoredProcedure(databaseId string, collectionId string, sp repositorymodels.StoredProcedure) (repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var database repositorymodels.Database
|
||||||
|
var collection repositorymodels.Collection
|
||||||
|
if sp.ID == "" {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok = r.storeState.StoredProcedures[databaseId][collectionId][sp.ID]; ok {
|
||||||
|
return repositorymodels.StoredProcedure{}, repositorymodels.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.TimeStamp = time.Now().Unix()
|
||||||
|
sp.ResourceID = resourceid.NewCombined(database.ResourceID, collection.ResourceID, resourceid.New())
|
||||||
|
sp.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||||
|
sp.Self = fmt.Sprintf("dbs/%s/colls/%s/sprocs/%s/", database.ResourceID, collection.ResourceID, sp.ResourceID)
|
||||||
|
|
||||||
|
r.storeState.StoredProcedures[databaseId][collectionId][sp.ID] = sp
|
||||||
|
|
||||||
|
return sp, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,91 @@
|
|||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
func (r *DataRepository) GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
||||||
return r.triggers, repositorymodels.StatusOk
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.Triggers[databaseId][collectionId]), repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) GetTrigger(databaseId string, collectionId string, triggerId string) (repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if trigger, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; ok {
|
||||||
|
return trigger, repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) DeleteTrigger(databaseId string, collectionId string, triggerId string) repositorymodels.RepositoryStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.Triggers[databaseId][collectionId], triggerId)
|
||||||
|
|
||||||
|
return repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) CreateTrigger(databaseId string, collectionId string, trigger repositorymodels.Trigger) (repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var database repositorymodels.Database
|
||||||
|
var collection repositorymodels.Collection
|
||||||
|
if trigger.ID == "" {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok = r.storeState.Triggers[databaseId][collectionId][trigger.ID]; ok {
|
||||||
|
return repositorymodels.Trigger{}, repositorymodels.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.TimeStamp = time.Now().Unix()
|
||||||
|
trigger.ResourceID = resourceid.NewCombined(database.ResourceID, collection.ResourceID, resourceid.New())
|
||||||
|
trigger.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||||
|
trigger.Self = fmt.Sprintf("dbs/%s/colls/%s/triggers/%s/", database.ResourceID, collection.ResourceID, trigger.ResourceID)
|
||||||
|
|
||||||
|
r.storeState.Triggers[databaseId][collectionId][trigger.ID] = trigger
|
||||||
|
|
||||||
|
return trigger, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,91 @@
|
|||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
func (r *DataRepository) GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
||||||
return r.userDefinedFunctions, repositorymodels.StatusOk
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.UserDefinedFunctions[databaseId][collectionId]), repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) GetUserDefinedFunction(databaseId string, collectionId string, udfId string) (repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if udf, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; ok {
|
||||||
|
return udf, repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) DeleteUserDefinedFunction(databaseId string, collectionId string, udfId string) repositorymodels.RepositoryStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; !ok {
|
||||||
|
return repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.UserDefinedFunctions[databaseId][collectionId], udfId)
|
||||||
|
|
||||||
|
return repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DataRepository) CreateUserDefinedFunction(databaseId string, collectionId string, udf repositorymodels.UserDefinedFunction) (repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var database repositorymodels.Database
|
||||||
|
var collection repositorymodels.Collection
|
||||||
|
if udf.ID == "" {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udf.ID]; ok {
|
||||||
|
return repositorymodels.UserDefinedFunction{}, repositorymodels.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
udf.TimeStamp = time.Now().Unix()
|
||||||
|
udf.ResourceID = resourceid.NewCombined(database.ResourceID, collection.ResourceID, resourceid.New())
|
||||||
|
udf.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||||
|
udf.Self = fmt.Sprintf("dbs/%s/colls/%s/udfs/%s/", database.ResourceID, collection.ResourceID, udf.ResourceID)
|
||||||
|
|
||||||
|
r.storeState.UserDefinedFunctions[databaseId][collectionId][udf.ID] = udf
|
||||||
|
|
||||||
|
return udf, repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,22 @@ const (
|
|||||||
BadRequest = 4
|
BadRequest = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TriggerOperation string
|
||||||
|
|
||||||
|
const (
|
||||||
|
All TriggerOperation = "All"
|
||||||
|
Create TriggerOperation = "Create"
|
||||||
|
Delete TriggerOperation = "Delete"
|
||||||
|
Replace TriggerOperation = "Replace"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TriggerType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Pre TriggerType = "Pre"
|
||||||
|
Post TriggerType = "Post"
|
||||||
|
)
|
||||||
|
|
||||||
type Collection struct {
|
type Collection struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
IndexingPolicy CollectionIndexingPolicy `json:"indexingPolicy"`
|
IndexingPolicy CollectionIndexingPolicy `json:"indexingPolicy"`
|
||||||
@@ -60,29 +76,29 @@ type UserDefinedFunction struct {
|
|||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
ResourceID string `json:"_rid"`
|
ResourceID string `json:"_rid"`
|
||||||
TimeStamp int `json:"_ts"`
|
TimeStamp int64 `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
ETag string `json:"_etag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoredProcedure struct {
|
type StoredProcedure struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
ResourceID string `json:"_rid"`
|
ResourceID string `json:"_rid"`
|
||||||
TimeStamp int `json:"_ts"`
|
TimeStamp int64 `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
ETag string `json:"_etag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Trigger struct {
|
type Trigger struct {
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
TriggerOperation string `json:"triggerOperation"`
|
TriggerOperation TriggerOperation `json:"triggerOperation"`
|
||||||
TriggerType string `json:"triggerType"`
|
TriggerType TriggerType `json:"triggerType"`
|
||||||
ResourceID string `json:"_rid"`
|
ResourceID string `json:"_rid"`
|
||||||
TimeStamp int `json:"_ts"`
|
TimeStamp int64 `json:"_ts"`
|
||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
Etag string `json:"_etag"`
|
ETag string `json:"_etag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Document map[string]interface{}
|
type Document map[string]interface{}
|
||||||
@@ -113,4 +129,13 @@ type State struct {
|
|||||||
|
|
||||||
// Map databaseId -> collectionId -> documentId -> Documents
|
// Map databaseId -> collectionId -> documentId -> Documents
|
||||||
Documents map[string]map[string]map[string]Document `json:"documents"`
|
Documents map[string]map[string]map[string]Document `json:"documents"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> triggerId -> Trigger
|
||||||
|
Triggers map[string]map[string]map[string]Trigger `json:"triggers"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> spId -> StoredProcedure
|
||||||
|
StoredProcedures map[string]map[string]map[string]StoredProcedure `json:"sprocs"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> udfId -> UserDefinedFunction
|
||||||
|
UserDefinedFunctions map[string]map[string]map[string]UserDefinedFunction `json:"udfs"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
func GetDefaultTlsConfig() *tls.Config {
|
func GetDefaultTlsConfig() *tls.Config {
|
||||||
cert, err := tls.X509KeyPair([]byte(certificate), []byte(certificateKey))
|
cert, err := tls.X509KeyPair([]byte(certificate), []byte(certificateKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to parse certificate and key:", err)
|
logger.ErrorLn("Failed to parse certificate and key:", err)
|
||||||
return &tls.Config{}
|
return &tls.Config{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,11 +123,14 @@ const (
|
|||||||
FunctionCallIsPrimitive FunctionCallType = "IsPrimitive"
|
FunctionCallIsPrimitive FunctionCallType = "IsPrimitive"
|
||||||
FunctionCallIsString FunctionCallType = "IsString"
|
FunctionCallIsString FunctionCallType = "IsString"
|
||||||
|
|
||||||
FunctionCallArrayConcat FunctionCallType = "ArrayConcat"
|
FunctionCallArrayConcat FunctionCallType = "ArrayConcat"
|
||||||
FunctionCallArrayLength FunctionCallType = "ArrayLength"
|
FunctionCallArrayContains FunctionCallType = "ArrayContains"
|
||||||
FunctionCallArraySlice FunctionCallType = "ArraySlice"
|
FunctionCallArrayContainsAny FunctionCallType = "ArrayContainsAny"
|
||||||
FunctionCallSetIntersect FunctionCallType = "SetIntersect"
|
FunctionCallArrayContainsAll FunctionCallType = "ArrayContainsAll"
|
||||||
FunctionCallSetUnion FunctionCallType = "SetUnion"
|
FunctionCallArrayLength FunctionCallType = "ArrayLength"
|
||||||
|
FunctionCallArraySlice FunctionCallType = "ArraySlice"
|
||||||
|
FunctionCallSetIntersect FunctionCallType = "SetIntersect"
|
||||||
|
FunctionCallSetUnion FunctionCallType = "SetUnion"
|
||||||
|
|
||||||
FunctionCallMathAbs FunctionCallType = "MathAbs"
|
FunctionCallMathAbs FunctionCallType = "MathAbs"
|
||||||
FunctionCallMathAcos FunctionCallType = "MathAcos"
|
FunctionCallMathAcos FunctionCallType = "MathAcos"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Parse_ArrayFunctions(t *testing.T) {
|
func Test_Parse_ArrayFunctions(t *testing.T) {
|
||||||
@@ -36,6 +37,119 @@ func Test_Parse_ArrayFunctions(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse function ARRAY_CONTAINS()", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT ARRAY_CONTAINS(c.a1, "value") FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "a1"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
testutils.SelectItem_Constant_String("value"),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse function ARRAY_CONTAINS() with partial match", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT ARRAY_CONTAINS(["a", "b"], "value", true) FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeArray,
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
testutils.SelectItem_Constant_String("a"),
|
||||||
|
testutils.SelectItem_Constant_String("b"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testutils.SelectItem_Constant_String("value"),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse function ARRAY_CONTAINS_ANY()", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT ARRAY_CONTAINS_ANY(["a", "b"], "value", true) FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeArray,
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
testutils.SelectItem_Constant_String("a"),
|
||||||
|
testutils.SelectItem_Constant_String("b"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testutils.SelectItem_Constant_String("value"),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse function ARRAY_CONTAINS_ALL()", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT ARRAY_CONTAINS_ALL(["a", "b"], "value", true) FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeArray,
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
testutils.SelectItem_Constant_String("a"),
|
||||||
|
testutils.SelectItem_Constant_String("b"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testutils.SelectItem_Constant_String("value"),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Should parse function ARRAY_LENGTH()", func(t *testing.T) {
|
t.Run("Should parse function ARRAY_LENGTH()", func(t *testing.T) {
|
||||||
testQueryParse(
|
testQueryParse(
|
||||||
t,
|
t,
|
||||||
@@ -75,20 +189,8 @@ func Test_Parse_ArrayFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "array"},
|
Path: []string{"c", "array"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(0),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(2),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
"github.com/pikami/cosmium/parsers/nosql"
|
"github.com/pikami/cosmium/parsers/nosql"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// For Parser Debugging
|
// For Parser Debugging
|
||||||
@@ -102,20 +103,8 @@ func Test_Parse(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_String("456"),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "456",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -457,6 +457,9 @@ AggregateFunctions <- AvgAggregateExpression
|
|||||||
/ SumAggregateExpression
|
/ SumAggregateExpression
|
||||||
|
|
||||||
ArrayFunctions <- ArrayConcatExpression
|
ArrayFunctions <- ArrayConcatExpression
|
||||||
|
/ ArrayContainsExpression
|
||||||
|
/ ArrayContainsAnyExpression
|
||||||
|
/ ArrayContainsAllExpression
|
||||||
/ ArrayLengthExpression
|
/ ArrayLengthExpression
|
||||||
/ ArraySliceExpression
|
/ ArraySliceExpression
|
||||||
/ SetIntersectExpression
|
/ SetIntersectExpression
|
||||||
@@ -626,6 +629,18 @@ ArrayConcatExpression <- "ARRAY_CONCAT"i ws "(" ws arrays:SelectItem others:(ws
|
|||||||
return createFunctionCall(parsers.FunctionCallArrayConcat, append([]interface{}{arrays}, others.([]interface{})...))
|
return createFunctionCall(parsers.FunctionCallArrayConcat, append([]interface{}{arrays}, others.([]interface{})...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayContainsExpression <- "ARRAY_CONTAINS"i ws "(" ws array:SelectItem ws "," ws item:SelectItem partialMatch:(ws "," ws ex:SelectItem { return ex, nil })? ws ")" {
|
||||||
|
return createFunctionCall(parsers.FunctionCallArrayContains, []interface{}{array, item, partialMatch})
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayContainsAnyExpression <- "ARRAY_CONTAINS_ANY"i ws "(" ws array:SelectItem items:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
||||||
|
return createFunctionCall(parsers.FunctionCallArrayContainsAny, append([]interface{}{array}, items.([]interface{})...))
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayContainsAllExpression <- "ARRAY_CONTAINS_ALL"i ws "(" ws array:SelectItem items:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
||||||
|
return createFunctionCall(parsers.FunctionCallArrayContainsAll, append([]interface{}{array}, items.([]interface{})...))
|
||||||
|
}
|
||||||
|
|
||||||
ArrayLengthExpression <- "ARRAY_LENGTH"i ws "(" ws array:SelectItem ws ")" {
|
ArrayLengthExpression <- "ARRAY_LENGTH"i ws "(" ws array:SelectItem ws ")" {
|
||||||
return createFunctionCall(parsers.FunctionCallArrayLength, []interface{}{array})
|
return createFunctionCall(parsers.FunctionCallArrayLength, []interface{}{array})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Execute_StringFunctions(t *testing.T) {
|
func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
@@ -23,20 +24,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -61,13 +50,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -93,13 +76,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
parsers.SelectItem{
|
||||||
Path: []string{"c", "pk"},
|
Path: []string{"c", "pk"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
@@ -128,20 +105,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -166,20 +131,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -204,20 +157,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -242,20 +183,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("2"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(1),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -352,13 +281,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(5),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -431,20 +354,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("old"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_String("new"),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "old",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "new",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -469,13 +380,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(3),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -524,13 +429,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(3),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -579,20 +478,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(1),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(5),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Parse_Were(t *testing.T) {
|
func Test_Parse_Were(t *testing.T) {
|
||||||
@@ -22,10 +23,7 @@ func Test_Parse_Were(t *testing.T) {
|
|||||||
Filters: parsers.ComparisonExpression{
|
Filters: parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -51,18 +49,12 @@ func Test_Parse_Were(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("12345"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "12345"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "pk"}},
|
Left: parsers.SelectItem{Path: []string{"c", "pk"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Int(123),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeInteger, Value: 123},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -87,10 +79,7 @@ func Test_Parse_Were(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.LogicalExpression{
|
parsers.LogicalExpression{
|
||||||
Operation: parsers.LogicalExpressionTypeOr,
|
Operation: parsers.LogicalExpressionTypeOr,
|
||||||
@@ -98,18 +87,12 @@ func Test_Parse_Were(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "123"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("456"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "456"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -135,43 +118,28 @@ func Test_Parse_Were(t *testing.T) {
|
|||||||
Filters: parsers.LogicalExpression{
|
Filters: parsers.LogicalExpression{
|
||||||
Expressions: []interface{}{
|
Expressions: []interface{}{
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "boolean"}},
|
Left: parsers.SelectItem{Path: []string{"c", "boolean"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
|
||||||
},
|
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "integer"}},
|
Left: parsers.SelectItem{Path: []string{"c", "integer"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Int(1),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeInteger, Value: 1},
|
|
||||||
},
|
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "float"}},
|
Left: parsers.SelectItem{Path: []string{"c", "float"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Float(6.9),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeFloat, Value: 6.9},
|
|
||||||
},
|
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("hello"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "hello"},
|
|
||||||
},
|
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "param"}},
|
Left: parsers.SelectItem{Path: []string{"c", "param"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Parameter("@param_id1"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: "@param_id1"},
|
|
||||||
},
|
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,86 @@ func (r rowContext) array_Concat(arguments []interface{}) []interface{} {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r rowContext) array_Contains(arguments []interface{}) bool {
|
||||||
|
array := r.parseArray(arguments[0])
|
||||||
|
if array == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
exprToSearch := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
||||||
|
|
||||||
|
partialSearch := false
|
||||||
|
if len(arguments) > 2 {
|
||||||
|
boolExpr := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
|
||||||
|
if boolValue, ok := boolExpr.(bool); ok {
|
||||||
|
partialSearch = boolValue
|
||||||
|
} else {
|
||||||
|
logger.ErrorLn("array_Contains - got parameters of wrong type")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range array {
|
||||||
|
if partialSearch {
|
||||||
|
if r.partialMatch(item, exprToSearch) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if reflect.DeepEqual(item, exprToSearch) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rowContext) array_Contains_Any(arguments []interface{}) bool {
|
||||||
|
array := r.parseArray(arguments[0])
|
||||||
|
if array == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSelectItems := arguments[1:]
|
||||||
|
|
||||||
|
for _, valueSelectItem := range valueSelectItems {
|
||||||
|
value := r.resolveSelectItem(valueSelectItem.(parsers.SelectItem))
|
||||||
|
for _, item := range array {
|
||||||
|
if reflect.DeepEqual(item, value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rowContext) array_Contains_All(arguments []interface{}) bool {
|
||||||
|
array := r.parseArray(arguments[0])
|
||||||
|
if array == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSelectItems := arguments[1:]
|
||||||
|
|
||||||
|
for _, valueSelectItem := range valueSelectItems {
|
||||||
|
value := r.resolveSelectItem(valueSelectItem.(parsers.SelectItem))
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, item := range array {
|
||||||
|
if reflect.DeepEqual(item, value) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (r rowContext) array_Length(arguments []interface{}) int {
|
func (r rowContext) array_Length(arguments []interface{}) int {
|
||||||
array := r.parseArray(arguments[0])
|
array := r.parseArray(arguments[0])
|
||||||
if array == nil {
|
if array == nil {
|
||||||
@@ -36,13 +116,13 @@ func (r rowContext) array_Slice(arguments []interface{}) []interface{} {
|
|||||||
lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
|
lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
logger.Error("array_Slice - got length parameters of wrong type")
|
logger.ErrorLn("array_Slice - got length parameters of wrong type")
|
||||||
return []interface{}{}
|
return []interface{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if start, ok = startEx.(int); !ok {
|
if start, ok = startEx.(int); !ok {
|
||||||
logger.Error("array_Slice - got start parameters of wrong type")
|
logger.ErrorLn("array_Slice - got start parameters of wrong type")
|
||||||
return []interface{}{}
|
return []interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +197,7 @@ func (r rowContext) parseArray(argument interface{}) []interface{} {
|
|||||||
|
|
||||||
arrValue := reflect.ValueOf(ex)
|
arrValue := reflect.ValueOf(ex)
|
||||||
if arrValue.Kind() != reflect.Slice {
|
if arrValue.Kind() != reflect.Slice {
|
||||||
logger.Error("parseArray got parameters of wrong type")
|
logger.ErrorLn("parseArray got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,3 +209,21 @@ func (r rowContext) parseArray(argument interface{}) []interface{} {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r rowContext) partialMatch(item interface{}, exprToSearch interface{}) bool {
|
||||||
|
itemValue := reflect.ValueOf(item)
|
||||||
|
exprValue := reflect.ValueOf(exprToSearch)
|
||||||
|
|
||||||
|
if itemValue.Kind() != reflect.Map || exprValue.Kind() != reflect.Map {
|
||||||
|
logger.ErrorLn("partialMatch got parameters of wrong type")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range exprValue.MapKeys() {
|
||||||
|
if itemValue.MapIndex(key).Interface() != exprValue.MapIndex(key).Interface() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Execute_ArrayFunctions(t *testing.T) {
|
func Test_Execute_ArrayFunctions(t *testing.T) {
|
||||||
@@ -52,6 +53,286 @@ func Test_Execute_ArrayFunctions(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function ARRAY_CONTAINS()", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"@categories": []interface{}{"coats", "jackets", "sweatshirts"},
|
||||||
|
"@objectArray": []interface{}{map[string]interface{}{"category": "shirts", "color": "blue"}},
|
||||||
|
"@fullMatchObject": map[string]interface{}{"category": "shirts", "color": "blue"},
|
||||||
|
"@partialMatchObject": map[string]interface{}{"category": "shirts"},
|
||||||
|
"@missingPartialMatchObject": map[string]interface{}{"category": "shorts", "color": "blue"},
|
||||||
|
},
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Alias: "ContainsItem",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@categories"),
|
||||||
|
testutils.SelectItem_Constant_String("coats"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "MissingItem",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@categories"),
|
||||||
|
testutils.SelectItem_Constant_String("hoodies"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "ContainsFullMatchObject",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@objectArray"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@fullMatchObject"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "MissingFullMatchObject",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@objectArray"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@partialMatchObject"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "ContainsPartialMatchObject",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@objectArray"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@partialMatchObject"),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "MissingPartialMatchObject",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContains,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@objectArray"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@missingPartialMatchObject"),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]memoryexecutor.RowType{map[string]interface{}{"id": "123"}},
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{
|
||||||
|
"ContainsItem": true,
|
||||||
|
"MissingItem": false,
|
||||||
|
"ContainsFullMatchObject": true,
|
||||||
|
"MissingFullMatchObject": false,
|
||||||
|
"ContainsPartialMatchObject": true,
|
||||||
|
"MissingPartialMatchObject": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function ARRAY_CONTAINS_ANY()", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"@mixedArray": []interface{}{1, true, "3", []int{1, 2, 3}},
|
||||||
|
"@numbers": []interface{}{1, 2, 3, 4},
|
||||||
|
"@emptyArray": []interface{}{},
|
||||||
|
"@arr123": []interface{}{1, 2, 3},
|
||||||
|
},
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Alias: "matchesEntireArray",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@mixedArray"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
testutils.SelectItem_Constant_String("3"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@arr123"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "matchesSomeValues",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(2),
|
||||||
|
testutils.SelectItem_Constant_Int(3),
|
||||||
|
testutils.SelectItem_Constant_Int(4),
|
||||||
|
testutils.SelectItem_Constant_Int(5),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "matchSingleValue",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "noMatches",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(5),
|
||||||
|
testutils.SelectItem_Constant_Int(6),
|
||||||
|
testutils.SelectItem_Constant_Int(7),
|
||||||
|
testutils.SelectItem_Constant_Int(8),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "emptyArray",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAny,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@emptyArray"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
testutils.SelectItem_Constant_Int(2),
|
||||||
|
testutils.SelectItem_Constant_Int(3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]memoryexecutor.RowType{map[string]interface{}{"id": "123"}},
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{
|
||||||
|
"matchesEntireArray": true,
|
||||||
|
"matchesSomeValues": true,
|
||||||
|
"matchSingleValue": true,
|
||||||
|
"noMatches": false,
|
||||||
|
"emptyArray": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function ARRAY_CONTAINS_ALL()", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"@mixedArray": []interface{}{1, true, "3", []interface{}{1, 2, 3}},
|
||||||
|
"@numbers": []interface{}{1, 2, 3, 4},
|
||||||
|
"@emptyArray": []interface{}{},
|
||||||
|
"@arr123": []interface{}{1, 2, 3},
|
||||||
|
},
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Alias: "matchesEntireArray",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@mixedArray"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
|
testutils.SelectItem_Constant_String("3"),
|
||||||
|
testutils.SelectItem_Constant_Parameter("@arr123"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "matchesSomeValues",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(2),
|
||||||
|
testutils.SelectItem_Constant_Int(3),
|
||||||
|
testutils.SelectItem_Constant_Int(4),
|
||||||
|
testutils.SelectItem_Constant_Int(5),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "matchSingleValue",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "noMatches",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@numbers"),
|
||||||
|
testutils.SelectItem_Constant_Int(5),
|
||||||
|
testutils.SelectItem_Constant_Int(6),
|
||||||
|
testutils.SelectItem_Constant_Int(7),
|
||||||
|
testutils.SelectItem_Constant_Int(8),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "emptyArray",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallArrayContainsAll,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
testutils.SelectItem_Constant_Parameter("@emptyArray"),
|
||||||
|
testutils.SelectItem_Constant_Int(1),
|
||||||
|
testutils.SelectItem_Constant_Int(2),
|
||||||
|
testutils.SelectItem_Constant_Int(3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]memoryexecutor.RowType{map[string]interface{}{"id": "123"}},
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{
|
||||||
|
"matchesEntireArray": true,
|
||||||
|
"matchesSomeValues": false,
|
||||||
|
"matchSingleValue": true,
|
||||||
|
"noMatches": false,
|
||||||
|
"emptyArray": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Should execute function ARRAY_LENGTH()", func(t *testing.T) {
|
t.Run("Should execute function ARRAY_LENGTH()", func(t *testing.T) {
|
||||||
testQueryExecute(
|
testQueryExecute(
|
||||||
t,
|
t,
|
||||||
@@ -105,20 +386,8 @@ func Test_Execute_ArrayFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "arr2"},
|
Path: []string{"c", "arr2"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(1),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(2),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (r rowContext) math_Abs(arguments []interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Abs - got parameters of wrong type")
|
logger.DebugLn("math_Abs - got parameters of wrong type")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,12 +32,12 @@ func (r rowContext) math_Acos(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Acos - got parameters of wrong type")
|
logger.DebugLn("math_Acos - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if val < -1 || val > 1 {
|
if val < -1 || val > 1 {
|
||||||
logger.Debug("math_Acos - value out of domain for acos")
|
logger.DebugLn("math_Acos - value out of domain for acos")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +50,12 @@ func (r rowContext) math_Asin(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Asin - got parameters of wrong type")
|
logger.DebugLn("math_Asin - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if val < -1 || val > 1 {
|
if val < -1 || val > 1 {
|
||||||
logger.Debug("math_Asin - value out of domain for acos")
|
logger.DebugLn("math_Asin - value out of domain for acos")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func (r rowContext) math_Atan(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Atan - got parameters of wrong type")
|
logger.DebugLn("math_Atan - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ func (r rowContext) math_Ceiling(arguments []interface{}) interface{} {
|
|||||||
case int:
|
case int:
|
||||||
return val
|
return val
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Ceiling - got parameters of wrong type")
|
logger.DebugLn("math_Ceiling - got parameters of wrong type")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ func (r rowContext) math_Cos(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Cos - got parameters of wrong type")
|
logger.DebugLn("math_Cos - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,12 +109,12 @@ func (r rowContext) math_Cot(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Cot - got parameters of wrong type")
|
logger.DebugLn("math_Cot - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
logger.Debug("math_Cot - cotangent undefined for zero")
|
logger.DebugLn("math_Cot - cotangent undefined for zero")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ func (r rowContext) math_Degrees(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Degrees - got parameters of wrong type")
|
logger.DebugLn("math_Degrees - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ func (r rowContext) math_Exp(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Exp - got parameters of wrong type")
|
logger.DebugLn("math_Exp - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ func (r rowContext) math_Floor(arguments []interface{}) interface{} {
|
|||||||
case int:
|
case int:
|
||||||
return val
|
return val
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Floor - got parameters of wrong type")
|
logger.DebugLn("math_Floor - got parameters of wrong type")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ func (r rowContext) math_IntBitNot(arguments []interface{}) interface{} {
|
|||||||
case int:
|
case int:
|
||||||
return ^val
|
return ^val
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_IntBitNot - got parameters of wrong type")
|
logger.DebugLn("math_IntBitNot - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,12 +181,12 @@ func (r rowContext) math_Log10(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Log10 - got parameters of wrong type")
|
logger.DebugLn("math_Log10 - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if val <= 0 {
|
if val <= 0 {
|
||||||
logger.Debug("math_Log10 - value must be greater than 0")
|
logger.DebugLn("math_Log10 - value must be greater than 0")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ func (r rowContext) math_Radians(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Radians - got parameters of wrong type")
|
logger.DebugLn("math_Radians - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ func (r rowContext) math_Round(arguments []interface{}) interface{} {
|
|||||||
case int:
|
case int:
|
||||||
return val
|
return val
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Round - got parameters of wrong type")
|
logger.DebugLn("math_Round - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ func (r rowContext) math_Sign(arguments []interface{}) interface{} {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Sign - got parameters of wrong type")
|
logger.DebugLn("math_Sign - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ func (r rowContext) math_Sin(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Sin - got parameters of wrong type")
|
logger.DebugLn("math_Sin - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ func (r rowContext) math_Sqrt(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Sqrt - got parameters of wrong type")
|
logger.DebugLn("math_Sqrt - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ func (r rowContext) math_Square(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Square - got parameters of wrong type")
|
logger.DebugLn("math_Square - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ func (r rowContext) math_Tan(arguments []interface{}) interface{} {
|
|||||||
|
|
||||||
val, valIsNumber := numToFloat64(ex)
|
val, valIsNumber := numToFloat64(ex)
|
||||||
if !valIsNumber {
|
if !valIsNumber {
|
||||||
logger.Debug("math_Tan - got parameters of wrong type")
|
logger.DebugLn("math_Tan - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ func (r rowContext) math_Trunc(arguments []interface{}) interface{} {
|
|||||||
case int:
|
case int:
|
||||||
return float64(val)
|
return float64(val)
|
||||||
default:
|
default:
|
||||||
logger.Debug("math_Trunc - got parameters of wrong type")
|
logger.DebugLn("math_Trunc - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,7 +325,7 @@ func (r rowContext) math_Atn2(arguments []interface{}) interface{} {
|
|||||||
x, xIsNumber := numToFloat64(ex2)
|
x, xIsNumber := numToFloat64(ex2)
|
||||||
|
|
||||||
if !yIsNumber || !xIsNumber {
|
if !yIsNumber || !xIsNumber {
|
||||||
logger.Debug("math_Atn2 - got parameters of wrong type")
|
logger.DebugLn("math_Atn2 - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +342,7 @@ func (r rowContext) math_IntAdd(arguments []interface{}) interface{} {
|
|||||||
ex2Number, ex2IsNumber := numToInt(ex2)
|
ex2Number, ex2IsNumber := numToInt(ex2)
|
||||||
|
|
||||||
if !ex1IsNumber || !ex2IsNumber {
|
if !ex1IsNumber || !ex2IsNumber {
|
||||||
logger.Debug("math_IntAdd - got parameters of wrong type")
|
logger.DebugLn("math_IntAdd - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +359,7 @@ func (r rowContext) math_IntBitAnd(arguments []interface{}) interface{} {
|
|||||||
ex2Int, ex2IsInt := numToInt(ex2)
|
ex2Int, ex2IsInt := numToInt(ex2)
|
||||||
|
|
||||||
if !ex1IsInt || !ex2IsInt {
|
if !ex1IsInt || !ex2IsInt {
|
||||||
logger.Debug("math_IntBitAnd - got parameters of wrong type")
|
logger.DebugLn("math_IntBitAnd - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ func (r rowContext) math_IntBitLeftShift(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := numToInt(ex2)
|
num2, num2IsInt := numToInt(ex2)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntBitLeftShift - got parameters of wrong type")
|
logger.DebugLn("math_IntBitLeftShift - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ func (r rowContext) math_IntBitOr(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntBitOr - got parameters of wrong type")
|
logger.DebugLn("math_IntBitOr - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ func (r rowContext) math_IntBitRightShift(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := numToInt(ex2)
|
num2, num2IsInt := numToInt(ex2)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntBitRightShift - got parameters of wrong type")
|
logger.DebugLn("math_IntBitRightShift - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +427,7 @@ func (r rowContext) math_IntBitXor(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntBitXor - got parameters of wrong type")
|
logger.DebugLn("math_IntBitXor - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,7 +444,7 @@ func (r rowContext) math_IntDiv(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt || num2 == 0 {
|
if !num1IsInt || !num2IsInt || num2 == 0 {
|
||||||
logger.Debug("math_IntDiv - got parameters of wrong type or divide by zero")
|
logger.DebugLn("math_IntDiv - got parameters of wrong type or divide by zero")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +461,7 @@ func (r rowContext) math_IntMul(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntMul - got parameters of wrong type")
|
logger.DebugLn("math_IntMul - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +478,7 @@ func (r rowContext) math_IntSub(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt {
|
if !num1IsInt || !num2IsInt {
|
||||||
logger.Debug("math_IntSub - got parameters of wrong type")
|
logger.DebugLn("math_IntSub - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +495,7 @@ func (r rowContext) math_IntMod(arguments []interface{}) interface{} {
|
|||||||
num2, num2IsInt := ex2.(int)
|
num2, num2IsInt := ex2.(int)
|
||||||
|
|
||||||
if !num1IsInt || !num2IsInt || num2 == 0 {
|
if !num1IsInt || !num2IsInt || num2 == 0 {
|
||||||
logger.Debug("math_IntMod - got parameters of wrong type or divide by zero")
|
logger.DebugLn("math_IntMod - got parameters of wrong type or divide by zero")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ func (r rowContext) math_Power(arguments []interface{}) interface{} {
|
|||||||
exponent, exponentIsNumber := numToFloat64(ex2)
|
exponent, exponentIsNumber := numToFloat64(ex2)
|
||||||
|
|
||||||
if !baseIsNumber || !exponentIsNumber {
|
if !baseIsNumber || !exponentIsNumber {
|
||||||
logger.Debug("math_Power - got parameters of wrong type")
|
logger.DebugLn("math_Power - got parameters of wrong type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,21 +530,21 @@ func (r rowContext) math_Log(arguments []interface{}) interface{} {
|
|||||||
baseValue, baseValueIsNumber := numToFloat64(baseValueObject)
|
baseValue, baseValueIsNumber := numToFloat64(baseValueObject)
|
||||||
|
|
||||||
if !baseValueIsNumber {
|
if !baseValueIsNumber {
|
||||||
logger.Debug("math_Log - base parameter must be a numeric value")
|
logger.DebugLn("math_Log - base parameter must be a numeric value")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if baseValue > 0 && baseValue != 1 {
|
if baseValue > 0 && baseValue != 1 {
|
||||||
base = baseValue
|
base = baseValue
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("math_Log - base must be greater than 0 and not equal to 1")
|
logger.DebugLn("math_Log - base must be greater than 0 and not equal to 1")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
num, numIsNumber := numToFloat64(ex)
|
num, numIsNumber := numToFloat64(ex)
|
||||||
if !numIsNumber || num <= 0 {
|
if !numIsNumber || num <= 0 {
|
||||||
logger.Debug("math_Log - parameter must be a positive numeric value")
|
logger.DebugLn("math_Log - parameter must be a positive numeric value")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,21 +563,21 @@ func (r rowContext) math_NumberBin(arguments []interface{}) interface{} {
|
|||||||
binSizeValue, binSizeValueIsNumber := numToFloat64(binSizeValueObject)
|
binSizeValue, binSizeValueIsNumber := numToFloat64(binSizeValueObject)
|
||||||
|
|
||||||
if !binSizeValueIsNumber {
|
if !binSizeValueIsNumber {
|
||||||
logger.Debug("math_NumberBin - base parameter must be a numeric value")
|
logger.DebugLn("math_NumberBin - base parameter must be a numeric value")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if binSizeValue != 0 {
|
if binSizeValue != 0 {
|
||||||
binSize = binSizeValue
|
binSize = binSizeValue
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("math_NumberBin - base must not be equal to 0")
|
logger.DebugLn("math_NumberBin - base must not be equal to 0")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
num, numIsNumber := numToFloat64(ex)
|
num, numIsNumber := numToFloat64(ex)
|
||||||
if !numIsNumber {
|
if !numIsNumber {
|
||||||
logger.Debug("math_NumberBin - parameter must be a numeric value")
|
logger.DebugLn("math_NumberBin - parameter must be a numeric value")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ func (r rowContext) filters_ComparisonExpression(expression parsers.ComparisonEx
|
|||||||
rightExpression, rightExpressionOk := expression.Right.(parsers.SelectItem)
|
rightExpression, rightExpressionOk := expression.Right.(parsers.SelectItem)
|
||||||
|
|
||||||
if !leftExpressionOk || !rightExpressionOk {
|
if !leftExpressionOk || !rightExpressionOk {
|
||||||
logger.Error("ComparisonExpression has incorrect Left or Right type")
|
logger.ErrorLn("ComparisonExpression has incorrect Left or Right type")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +351,7 @@ func (r rowContext) resolveSelectItem(selectItem parsers.SelectItem) interface{}
|
|||||||
return r.selectItem_SelectItemTypeFunctionCall(typedFunctionCall)
|
return r.selectItem_SelectItemTypeFunctionCall(typedFunctionCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Error("parsers.SelectItem has incorrect Value type (expected parsers.FunctionCall)")
|
logger.ErrorLn("parsers.SelectItem has incorrect Value type (expected parsers.FunctionCall)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ func (r rowContext) selectItem_SelectItemTypeConstant(selectItem parsers.SelectI
|
|||||||
var ok bool
|
var ok bool
|
||||||
if typedValue, ok = selectItem.Value.(parsers.Constant); !ok {
|
if typedValue, ok = selectItem.Value.(parsers.Constant); !ok {
|
||||||
// TODO: Handle error
|
// TODO: Handle error
|
||||||
logger.Error("parsers.Constant has incorrect Value type")
|
logger.ErrorLn("parsers.Constant has incorrect Value type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if typedValue.Type == parsers.ConstantTypeParameterConstant &&
|
if typedValue.Type == parsers.ConstantTypeParameterConstant &&
|
||||||
@@ -470,6 +470,12 @@ func (r rowContext) selectItem_SelectItemTypeFunctionCall(functionCall parsers.F
|
|||||||
|
|
||||||
case parsers.FunctionCallArrayConcat:
|
case parsers.FunctionCallArrayConcat:
|
||||||
return r.array_Concat(functionCall.Arguments)
|
return r.array_Concat(functionCall.Arguments)
|
||||||
|
case parsers.FunctionCallArrayContains:
|
||||||
|
return r.array_Contains(functionCall.Arguments)
|
||||||
|
case parsers.FunctionCallArrayContainsAny:
|
||||||
|
return r.array_Contains_Any(functionCall.Arguments)
|
||||||
|
case parsers.FunctionCallArrayContainsAll:
|
||||||
|
return r.array_Contains_All(functionCall.Arguments)
|
||||||
case parsers.FunctionCallArrayLength:
|
case parsers.FunctionCallArrayLength:
|
||||||
return r.array_Length(functionCall.Arguments)
|
return r.array_Length(functionCall.Arguments)
|
||||||
case parsers.FunctionCallArraySlice:
|
case parsers.FunctionCallArraySlice:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testQueryExecute(
|
func testQueryExecute(
|
||||||
@@ -111,20 +112,8 @@ func Test_Execute(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_String("456"),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "456",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func (r rowContext) strings_Left(arguments []interface{}) string {
|
|||||||
lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
logger.Error("strings_Left - got parameters of wrong type")
|
logger.ErrorLn("strings_Left - got parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ func (r rowContext) strings_Replicate(arguments []interface{}) string {
|
|||||||
timesEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
timesEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
||||||
|
|
||||||
if times, ok = timesEx.(int); !ok {
|
if times, ok = timesEx.(int); !ok {
|
||||||
logger.Error("strings_Replicate - got parameters of wrong type")
|
logger.ErrorLn("strings_Replicate - got parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ func (r rowContext) strings_Right(arguments []interface{}) string {
|
|||||||
lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
|
||||||
|
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
logger.Error("strings_Right - got parameters of wrong type")
|
logger.ErrorLn("strings_Right - got parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,11 +220,11 @@ func (r rowContext) strings_Substring(arguments []interface{}) string {
|
|||||||
lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
|
lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
|
||||||
|
|
||||||
if startPos, ok = startPosEx.(int); !ok {
|
if startPos, ok = startPosEx.(int); !ok {
|
||||||
logger.Error("strings_Substring - got start parameters of wrong type")
|
logger.ErrorLn("strings_Substring - got start parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if length, ok = lengthEx.(int); !ok {
|
if length, ok = lengthEx.(int); !ok {
|
||||||
logger.Error("strings_Substring - got length parameters of wrong type")
|
logger.ErrorLn("strings_Substring - got length parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ func (r rowContext) parseString(argument interface{}) string {
|
|||||||
return str1
|
return str1
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Error("StringEquals got parameters of wrong type")
|
logger.ErrorLn("StringEquals got parameters of wrong type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Execute_StringFunctions(t *testing.T) {
|
func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
@@ -33,20 +34,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "pk"},
|
Path: []string{"c", "pk"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("aaa"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "aaa",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -81,13 +70,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "pk"},
|
Path: []string{"c", "pk"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("aaa"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "aaa",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -119,20 +102,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String(" "),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(123),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: " ",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: 123,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
parsers.SelectItem{
|
||||||
Path: []string{"c", "pk"},
|
Path: []string{"c", "pk"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
@@ -171,20 +142,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("2"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -219,20 +178,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("3"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -267,20 +214,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "id"},
|
Path: []string{"c", "id"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("1"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Bool(true),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeBoolean,
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -315,20 +250,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("o"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(4),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "o",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -397,13 +320,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(3),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -506,20 +423,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_String("world"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_String("universe"),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeString,
|
|
||||||
Value: "universe",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -554,13 +459,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(3),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -629,13 +528,7 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(3),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -704,20 +597,8 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
|||||||
Path: []string{"c", "str"},
|
Path: []string{"c", "str"},
|
||||||
Type: parsers.SelectItemTypeField,
|
Type: parsers.SelectItemTypeField,
|
||||||
},
|
},
|
||||||
parsers.SelectItem{
|
testutils.SelectItem_Constant_Int(2),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
testutils.SelectItem_Constant_Int(4),
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
parsers.SelectItem{
|
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{
|
|
||||||
Type: parsers.ConstantTypeInteger,
|
|
||||||
Value: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
"github.com/pikami/cosmium/parsers"
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Execute_Where(t *testing.T) {
|
func Test_Execute_Where(t *testing.T) {
|
||||||
@@ -26,10 +27,7 @@ func Test_Execute_Where(t *testing.T) {
|
|||||||
Filters: parsers.ComparisonExpression{
|
Filters: parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mockData,
|
mockData,
|
||||||
@@ -52,10 +50,7 @@ func Test_Execute_Where(t *testing.T) {
|
|||||||
Filters: parsers.ComparisonExpression{
|
Filters: parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Parameter("@param_id"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: "@param_id"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Parameters: map[string]interface{}{
|
Parameters: map[string]interface{}{
|
||||||
"@param_id": "456",
|
"@param_id": "456",
|
||||||
@@ -83,18 +78,12 @@ func Test_Execute_Where(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("67890"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "67890"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "pk"}},
|
Left: parsers.SelectItem{Path: []string{"c", "pk"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Int(456),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeInteger, Value: 456},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -120,10 +109,7 @@ func Test_Execute_Where(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.LogicalExpression{
|
parsers.LogicalExpression{
|
||||||
Operation: parsers.LogicalExpressionTypeOr,
|
Operation: parsers.LogicalExpressionTypeOr,
|
||||||
@@ -131,18 +117,12 @@ func Test_Execute_Where(t *testing.T) {
|
|||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("123"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "123"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
Right: parsers.SelectItem{
|
Right: testutils.SelectItem_Constant_String("456"),
|
||||||
Type: parsers.SelectItemTypeConstant,
|
|
||||||
Value: parsers.Constant{Type: parsers.ConstantTypeString, Value: "456"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
53
test_utils/parser_model_gen.go
Normal file
53
test_utils/parser_model_gen.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package testutils
|
||||||
|
|
||||||
|
import "github.com/pikami/cosmium/parsers"
|
||||||
|
|
||||||
|
func SelectItem_Constant_String(value string) parsers.SelectItem {
|
||||||
|
return parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectItem_Constant_Int(value int) parsers.SelectItem {
|
||||||
|
return parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeInteger,
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectItem_Constant_Float(value float64) parsers.SelectItem {
|
||||||
|
return parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeFloat,
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectItem_Constant_Bool(value bool) parsers.SelectItem {
|
||||||
|
return parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeBoolean,
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelectItem_Constant_Parameter(name string) parsers.SelectItem {
|
||||||
|
return parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeParameterConstant,
|
||||||
|
Value: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user