mirror of
https://github.com/pikami/cosmium.git
synced 2025-03-13 21:36:01 +00:00
DataStore is interface now. Liskov would be proud.
This commit is contained in:
parent
bd4fe5abec
commit
221f029a1d
4
Makefile
4
Makefile
@ -51,6 +51,10 @@ build-sharedlib-linux-amd64:
|
|||||||
@echo "Building shared library for Linux x64..."
|
@echo "Building shared library for Linux x64..."
|
||||||
@GOOS=linux GOARCH=amd64 $(GOBUILD) $(SHARED_LIB_OPT) -o $(DIST_DIR)/$(BINARY_NAME)-linux-amd64.so $(SHARED_LIB_LOCATION)
|
@GOOS=linux GOARCH=amd64 $(GOBUILD) $(SHARED_LIB_OPT) -o $(DIST_DIR)/$(BINARY_NAME)-linux-amd64.so $(SHARED_LIB_LOCATION)
|
||||||
|
|
||||||
|
build-sharedlib-darwin-arm64:
|
||||||
|
@echo "Building shared library for macOS ARM..."
|
||||||
|
@GOOS=darwin GOARCH=arm64 $(GOBUILD) $(SHARED_LIB_OPT) -o $(DIST_DIR)/$(BINARY_NAME)-darwin-arm64.so $(SHARED_LIB_LOCATION)
|
||||||
|
|
||||||
build-sharedlib-tests: build-sharedlib-linux-amd64
|
build-sharedlib-tests: build-sharedlib-linux-amd64
|
||||||
@echo "Building shared library tests..."
|
@echo "Building shared library tests..."
|
||||||
@$(SHARED_LIB_TEST_CC) $(SHARED_LIB_TEST_CFLAGS) -o $(SHARED_LIB_TEST_TARGET) $(SHARED_LIB_TEST_SOURCES)
|
@$(SHARED_LIB_TEST_CC) $(SHARED_LIB_TEST_CFLAGS) -o $(SHARED_LIB_TEST_TARGET) $(SHARED_LIB_TEST_SOURCES)
|
||||||
|
@ -3,7 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApiServer struct {
|
type ApiServer struct {
|
||||||
@ -14,7 +14,7 @@ type ApiServer struct {
|
|||||||
config *config.ServerConfig
|
config *config.ServerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApiServer(dataRepository *repositories.DataRepository, config *config.ServerConfig) *ApiServer {
|
func NewApiServer(dataStore datastore.DataStore, config *config.ServerConfig) *ApiServer {
|
||||||
stopChan := make(chan interface{})
|
stopChan := make(chan interface{})
|
||||||
onServerShutdownChan := make(chan interface{})
|
onServerShutdownChan := make(chan interface{})
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ func NewApiServer(dataRepository *repositories.DataRepository, config *config.Se
|
|||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
apiServer.CreateRouter(dataRepository)
|
apiServer.CreateRouter(dataStore)
|
||||||
|
|
||||||
return apiServer
|
return apiServer
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllCollections(c *gin.Context) {
|
func (h *Handlers) GetAllCollections(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
|
|
||||||
collections, status := h.repository.GetAllCollections(databaseId)
|
collections, status := h.dataStore.GetAllCollections(databaseId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
database, _ := h.repository.GetDatabase(databaseId)
|
database, _ := h.dataStore.GetDatabase(databaseId)
|
||||||
|
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(collections)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(collections)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{
|
c.IndentedJSON(http.StatusOK, gin.H{
|
||||||
@ -31,13 +31,13 @@ func (h *Handlers) GetCollection(c *gin.Context) {
|
|||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
id := c.Param("collId")
|
id := c.Param("collId")
|
||||||
|
|
||||||
collection, status := h.repository.GetCollection(databaseId, id)
|
collection, status := h.dataStore.GetCollection(databaseId, id)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, collection)
|
c.IndentedJSON(http.StatusOK, collection)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -49,13 +49,13 @@ func (h *Handlers) DeleteCollection(c *gin.Context) {
|
|||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
id := c.Param("collId")
|
id := c.Param("collId")
|
||||||
|
|
||||||
status := h.repository.DeleteCollection(databaseId, id)
|
status := h.dataStore.DeleteCollection(databaseId, id)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ func (h *Handlers) DeleteCollection(c *gin.Context) {
|
|||||||
|
|
||||||
func (h *Handlers) CreateCollection(c *gin.Context) {
|
func (h *Handlers) CreateCollection(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
var newCollection repositorymodels.Collection
|
var newCollection datastore.Collection
|
||||||
|
|
||||||
if err := c.BindJSON(&newCollection); err != nil {
|
if err := c.BindJSON(&newCollection); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
||||||
@ -77,13 +77,13 @@ func (h *Handlers) CreateCollection(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdCollection, status := h.repository.CreateCollection(databaseId, newCollection)
|
createdCollection, status := h.dataStore.CreateCollection(databaseId, newCollection)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdCollection)
|
c.IndentedJSON(http.StatusCreated, createdCollection)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) CosmiumExport(c *gin.Context) {
|
func (h *Handlers) CosmiumExport(c *gin.Context) {
|
||||||
repositoryState, err := h.repository.GetState()
|
dataStoreState, err := h.dataStore.DumpToJson()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data(http.StatusOK, "application/json", []byte(repositoryState))
|
c.Data(http.StatusOK, "application/json", []byte(dataStoreState))
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllDatabases(c *gin.Context) {
|
func (h *Handlers) GetAllDatabases(c *gin.Context) {
|
||||||
databases, status := h.repository.GetAllDatabases()
|
databases, status := h.dataStore.GetAllDatabases()
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(databases)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(databases)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{
|
c.IndentedJSON(http.StatusOK, gin.H{
|
||||||
"_rid": "",
|
"_rid": "",
|
||||||
@ -26,13 +26,13 @@ func (h *Handlers) GetAllDatabases(c *gin.Context) {
|
|||||||
func (h *Handlers) GetDatabase(c *gin.Context) {
|
func (h *Handlers) GetDatabase(c *gin.Context) {
|
||||||
id := c.Param("databaseId")
|
id := c.Param("databaseId")
|
||||||
|
|
||||||
database, status := h.repository.GetDatabase(id)
|
database, status := h.dataStore.GetDatabase(id)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, database)
|
c.IndentedJSON(http.StatusOK, database)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -43,13 +43,13 @@ func (h *Handlers) GetDatabase(c *gin.Context) {
|
|||||||
func (h *Handlers) DeleteDatabase(c *gin.Context) {
|
func (h *Handlers) DeleteDatabase(c *gin.Context) {
|
||||||
id := c.Param("databaseId")
|
id := c.Param("databaseId")
|
||||||
|
|
||||||
status := h.repository.DeleteDatabase(id)
|
status := h.dataStore.DeleteDatabase(id)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ func (h *Handlers) DeleteDatabase(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) CreateDatabase(c *gin.Context) {
|
func (h *Handlers) CreateDatabase(c *gin.Context) {
|
||||||
var newDatabase repositorymodels.Database
|
var newDatabase datastore.Database
|
||||||
|
|
||||||
if err := c.BindJSON(&newDatabase); err != nil {
|
if err := c.BindJSON(&newDatabase); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
||||||
@ -70,13 +70,13 @@ func (h *Handlers) CreateDatabase(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdDatabase, status := h.repository.CreateDatabase(newDatabase)
|
createdDatabase, status := h.dataStore.CreateDatabase(newDatabase)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdDatabase)
|
c.IndentedJSON(http.StatusCreated, createdDatabase)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,20 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodels "github.com/pikami/cosmium/api/api_models"
|
apimodels "github.com/pikami/cosmium/api/api_models"
|
||||||
"github.com/pikami/cosmium/internal/constants"
|
"github.com/pikami/cosmium/internal/constants"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/logger"
|
"github.com/pikami/cosmium/internal/logger"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
"github.com/pikami/cosmium/parsers/nosql"
|
||||||
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllDocuments(c *gin.Context) {
|
func (h *Handlers) GetAllDocuments(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
documents, status := h.repository.GetAllDocuments(databaseId, collectionId)
|
documents, status := h.dataStore.GetAllDocuments(databaseId, collectionId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
collection, _ := h.repository.GetCollection(databaseId, collectionId)
|
collection, _ := h.dataStore.GetCollection(databaseId, collectionId)
|
||||||
|
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(documents)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(documents)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{
|
c.IndentedJSON(http.StatusOK, gin.H{
|
||||||
@ -39,13 +42,13 @@ func (h *Handlers) GetDocument(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
documentId := c.Param("docId")
|
documentId := c.Param("docId")
|
||||||
|
|
||||||
document, status := h.repository.GetDocument(databaseId, collectionId, documentId)
|
document, status := h.dataStore.GetDocument(databaseId, collectionId, documentId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, document)
|
c.IndentedJSON(http.StatusOK, document)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -58,13 +61,13 @@ func (h *Handlers) DeleteDocument(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
documentId := c.Param("docId")
|
documentId := c.Param("docId")
|
||||||
|
|
||||||
status := h.repository.DeleteDocument(databaseId, collectionId, documentId)
|
status := h.dataStore.DeleteDocument(databaseId, collectionId, documentId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -72,7 +75,7 @@ func (h *Handlers) DeleteDocument(c *gin.Context) {
|
|||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Maybe move "replace" logic to repository
|
// TODO: Maybe move "replace" logic to data store
|
||||||
func (h *Handlers) ReplaceDocument(c *gin.Context) {
|
func (h *Handlers) ReplaceDocument(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
@ -84,19 +87,19 @@ func (h *Handlers) ReplaceDocument(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := h.repository.DeleteDocument(databaseId, collectionId, documentId)
|
status := h.dataStore.DeleteDocument(databaseId, collectionId, documentId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdDocument, status := h.repository.CreateDocument(databaseId, collectionId, requestBody)
|
createdDocument, status := h.dataStore.CreateDocument(databaseId, collectionId, requestBody)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdDocument)
|
c.IndentedJSON(http.StatusCreated, createdDocument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -109,8 +112,8 @@ func (h *Handlers) PatchDocument(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
documentId := c.Param("docId")
|
documentId := c.Param("docId")
|
||||||
|
|
||||||
document, status := h.repository.GetDocument(databaseId, collectionId, documentId)
|
document, status := h.dataStore.GetDocument(databaseId, collectionId, documentId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -160,19 +163,19 @@ func (h *Handlers) PatchDocument(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status = h.repository.DeleteDocument(databaseId, collectionId, documentId)
|
status = h.dataStore.DeleteDocument(databaseId, collectionId, documentId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdDocument, status := h.repository.CreateDocument(databaseId, collectionId, modifiedDocument)
|
createdDocument, status := h.dataStore.CreateDocument(databaseId, collectionId, modifiedDocument)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdDocument)
|
c.IndentedJSON(http.StatusCreated, createdDocument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -210,16 +213,16 @@ func (h *Handlers) DocumentsPost(c *gin.Context) {
|
|||||||
|
|
||||||
isUpsert, _ := strconv.ParseBool(c.GetHeader("x-ms-documentdb-is-upsert"))
|
isUpsert, _ := strconv.ParseBool(c.GetHeader("x-ms-documentdb-is-upsert"))
|
||||||
if isUpsert {
|
if isUpsert {
|
||||||
h.repository.DeleteDocument(databaseId, collectionId, requestBody["id"].(string))
|
h.dataStore.DeleteDocument(databaseId, collectionId, requestBody["id"].(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
createdDocument, status := h.repository.CreateDocument(databaseId, collectionId, requestBody)
|
createdDocument, status := h.dataStore.CreateDocument(databaseId, collectionId, requestBody)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdDocument)
|
c.IndentedJSON(http.StatusCreated, createdDocument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -253,14 +256,15 @@ func (h *Handlers) handleDocumentQuery(c *gin.Context, requestBody map[string]in
|
|||||||
queryParameters = parametersToMap(paramsArray)
|
queryParameters = parametersToMap(paramsArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
docs, status := h.repository.ExecuteQueryDocuments(databaseId, collectionId, requestBody["query"].(string), queryParameters)
|
queryText := requestBody["query"].(string)
|
||||||
if status != repositorymodels.StatusOk {
|
docs, status := h.executeQueryDocuments(databaseId, collectionId, queryText, queryParameters)
|
||||||
|
if status != datastore.StatusOk {
|
||||||
// TODO: Currently we return everything if the query fails
|
// TODO: Currently we return everything if the query fails
|
||||||
h.GetAllDocuments(c)
|
h.GetAllDocuments(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
collection, _ := h.repository.GetCollection(databaseId, collectionId)
|
collection, _ := h.dataStore.GetCollection(databaseId, collectionId)
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(docs)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(docs)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{
|
c.IndentedJSON(http.StatusOK, gin.H{
|
||||||
"_rid": collection.ResourceID,
|
"_rid": collection.ResourceID,
|
||||||
@ -283,9 +287,9 @@ func (h *Handlers) handleBatchRequest(c *gin.Context) {
|
|||||||
for idx, operation := range batchOperations {
|
for idx, operation := range batchOperations {
|
||||||
switch operation.OperationType {
|
switch operation.OperationType {
|
||||||
case apimodels.BatchOperationTypeCreate:
|
case apimodels.BatchOperationTypeCreate:
|
||||||
createdDocument, status := h.repository.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
createdDocument, status := h.dataStore.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
||||||
responseCode := repositoryStatusToResponseCode(status)
|
responseCode := dataStoreStatusToResponseCode(status)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
responseCode = http.StatusCreated
|
responseCode = http.StatusCreated
|
||||||
}
|
}
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
@ -293,25 +297,25 @@ func (h *Handlers) handleBatchRequest(c *gin.Context) {
|
|||||||
ResourceBody: createdDocument,
|
ResourceBody: createdDocument,
|
||||||
}
|
}
|
||||||
case apimodels.BatchOperationTypeDelete:
|
case apimodels.BatchOperationTypeDelete:
|
||||||
status := h.repository.DeleteDocument(databaseId, collectionId, operation.Id)
|
status := h.dataStore.DeleteDocument(databaseId, collectionId, operation.Id)
|
||||||
responseCode := repositoryStatusToResponseCode(status)
|
responseCode := dataStoreStatusToResponseCode(status)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
responseCode = http.StatusNoContent
|
responseCode = http.StatusNoContent
|
||||||
}
|
}
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
StatusCode: responseCode,
|
StatusCode: responseCode,
|
||||||
}
|
}
|
||||||
case apimodels.BatchOperationTypeReplace:
|
case apimodels.BatchOperationTypeReplace:
|
||||||
deleteStatus := h.repository.DeleteDocument(databaseId, collectionId, operation.Id)
|
deleteStatus := h.dataStore.DeleteDocument(databaseId, collectionId, operation.Id)
|
||||||
if deleteStatus == repositorymodels.StatusNotFound {
|
if deleteStatus == datastore.StatusNotFound {
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
StatusCode: http.StatusNotFound,
|
StatusCode: http.StatusNotFound,
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
createdDocument, createStatus := h.repository.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
createdDocument, createStatus := h.dataStore.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
||||||
responseCode := repositoryStatusToResponseCode(createStatus)
|
responseCode := dataStoreStatusToResponseCode(createStatus)
|
||||||
if createStatus == repositorymodels.StatusOk {
|
if createStatus == datastore.StatusOk {
|
||||||
responseCode = http.StatusCreated
|
responseCode = http.StatusCreated
|
||||||
}
|
}
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
@ -320,10 +324,10 @@ func (h *Handlers) handleBatchRequest(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
case apimodels.BatchOperationTypeUpsert:
|
case apimodels.BatchOperationTypeUpsert:
|
||||||
documentId := operation.ResourceBody["id"].(string)
|
documentId := operation.ResourceBody["id"].(string)
|
||||||
h.repository.DeleteDocument(databaseId, collectionId, documentId)
|
h.dataStore.DeleteDocument(databaseId, collectionId, documentId)
|
||||||
createdDocument, createStatus := h.repository.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
createdDocument, createStatus := h.dataStore.CreateDocument(databaseId, collectionId, operation.ResourceBody)
|
||||||
responseCode := repositoryStatusToResponseCode(createStatus)
|
responseCode := dataStoreStatusToResponseCode(createStatus)
|
||||||
if createStatus == repositorymodels.StatusOk {
|
if createStatus == datastore.StatusOk {
|
||||||
responseCode = http.StatusCreated
|
responseCode = http.StatusCreated
|
||||||
}
|
}
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
@ -331,9 +335,9 @@ func (h *Handlers) handleBatchRequest(c *gin.Context) {
|
|||||||
ResourceBody: createdDocument,
|
ResourceBody: createdDocument,
|
||||||
}
|
}
|
||||||
case apimodels.BatchOperationTypeRead:
|
case apimodels.BatchOperationTypeRead:
|
||||||
document, status := h.repository.GetDocument(databaseId, collectionId, operation.Id)
|
document, status := h.dataStore.GetDocument(databaseId, collectionId, operation.Id)
|
||||||
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
batchOperationResults[idx] = apimodels.BatchOperationResult{
|
||||||
StatusCode: repositoryStatusToResponseCode(status),
|
StatusCode: dataStoreStatusToResponseCode(status),
|
||||||
ResourceBody: document,
|
ResourceBody: document,
|
||||||
}
|
}
|
||||||
case apimodels.BatchOperationTypePatch:
|
case apimodels.BatchOperationTypePatch:
|
||||||
@ -352,17 +356,43 @@ func (h *Handlers) handleBatchRequest(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, batchOperationResults)
|
c.JSON(http.StatusOK, batchOperationResults)
|
||||||
}
|
}
|
||||||
|
|
||||||
func repositoryStatusToResponseCode(status repositorymodels.RepositoryStatus) int {
|
func dataStoreStatusToResponseCode(status datastore.DataStoreStatus) int {
|
||||||
switch status {
|
switch status {
|
||||||
case repositorymodels.StatusOk:
|
case datastore.StatusOk:
|
||||||
return http.StatusOK
|
return http.StatusOK
|
||||||
case repositorymodels.StatusNotFound:
|
case datastore.StatusNotFound:
|
||||||
return http.StatusNotFound
|
return http.StatusNotFound
|
||||||
case repositorymodels.Conflict:
|
case datastore.Conflict:
|
||||||
return http.StatusConflict
|
return http.StatusConflict
|
||||||
case repositorymodels.BadRequest:
|
case datastore.BadRequest:
|
||||||
return http.StatusBadRequest
|
return http.StatusBadRequest
|
||||||
default:
|
default:
|
||||||
return http.StatusInternalServerError
|
return http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) executeQueryDocuments(databaseId string, collectionId string, query string, queryParameters map[string]interface{}) ([]memoryexecutor.RowType, datastore.DataStoreStatus) {
|
||||||
|
parsedQuery, err := nosql.Parse("", []byte(query))
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to parse query: %s\nerr: %v", query, err)
|
||||||
|
return nil, datastore.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionDocuments, status := h.dataStore.GetAllDocuments(databaseId, collectionId)
|
||||||
|
if status != datastore.StatusOk {
|
||||||
|
return nil, status
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Investigate, this could cause unnecessary memory usage
|
||||||
|
covDocs := make([]memoryexecutor.RowType, 0)
|
||||||
|
for _, doc := range collectionDocuments {
|
||||||
|
covDocs = append(covDocs, map[string]interface{}(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
if typedQuery, ok := parsedQuery.(parsers.SelectStmt); ok {
|
||||||
|
typedQuery.Parameters = queryParameters
|
||||||
|
return memoryexecutor.ExecuteQuery(typedQuery, covDocs), datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, datastore.BadRequest
|
||||||
|
}
|
||||||
|
@ -2,17 +2,17 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
repository *repositories.DataRepository
|
dataStore datastore.DataStore
|
||||||
config *config.ServerConfig
|
config *config.ServerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandlers(dataRepository *repositories.DataRepository, config *config.ServerConfig) *Handlers {
|
func NewHandlers(dataStore datastore.DataStore, config *config.ServerConfig) *Handlers {
|
||||||
return &Handlers{
|
return &Handlers{
|
||||||
repository: dataRepository,
|
dataStore: dataStore,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ func (h *Handlers) GetPartitionKeyRanges(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
partitionKeyRanges, status := h.repository.GetPartitionKeyRanges(databaseId, collectionId)
|
partitionKeyRanges, status := h.dataStore.GetPartitionKeyRanges(databaseId, collectionId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Header("etag", "\"420\"")
|
c.Header("etag", "\"420\"")
|
||||||
c.Header("lsn", "420")
|
c.Header("lsn", "420")
|
||||||
c.Header("x-ms-cosmos-llsn", "420")
|
c.Header("x-ms-cosmos-llsn", "420")
|
||||||
@ -27,7 +27,7 @@ func (h *Handlers) GetPartitionKeyRanges(c *gin.Context) {
|
|||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(partitionKeyRanges)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(partitionKeyRanges)))
|
||||||
|
|
||||||
collectionRid := collectionId
|
collectionRid := collectionId
|
||||||
collection, _ := h.repository.GetCollection(databaseId, collectionId)
|
collection, _ := h.dataStore.GetCollection(databaseId, collectionId)
|
||||||
if collection.ResourceID != "" {
|
if collection.ResourceID != "" {
|
||||||
collectionRid = collection.ResourceID
|
collectionRid = collection.ResourceID
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ func (h *Handlers) GetPartitionKeyRanges(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllStoredProcedures(c *gin.Context) {
|
func (h *Handlers) GetAllStoredProcedures(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
sps, status := h.repository.GetAllStoredProcedures(databaseId, collectionId)
|
sps, status := h.dataStore.GetAllStoredProcedures(databaseId, collectionId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(sps)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(sps)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "StoredProcedures": sps, "_count": len(sps)})
|
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "StoredProcedures": sps, "_count": len(sps)})
|
||||||
return
|
return
|
||||||
@ -28,14 +28,14 @@ func (h *Handlers) GetStoredProcedure(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
spId := c.Param("spId")
|
spId := c.Param("spId")
|
||||||
|
|
||||||
sp, status := h.repository.GetStoredProcedure(databaseId, collectionId, spId)
|
sp, status := h.dataStore.GetStoredProcedure(databaseId, collectionId, spId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, sp)
|
c.IndentedJSON(http.StatusOK, sp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,13 +48,13 @@ func (h *Handlers) DeleteStoredProcedure(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
spId := c.Param("spId")
|
spId := c.Param("spId")
|
||||||
|
|
||||||
status := h.repository.DeleteStoredProcedure(databaseId, collectionId, spId)
|
status := h.dataStore.DeleteStoredProcedure(databaseId, collectionId, spId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -67,25 +67,25 @@ func (h *Handlers) ReplaceStoredProcedure(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
spId := c.Param("spId")
|
spId := c.Param("spId")
|
||||||
|
|
||||||
var sp repositorymodels.StoredProcedure
|
var sp datastore.StoredProcedure
|
||||||
if err := c.BindJSON(&sp); err != nil {
|
if err := c.BindJSON(&sp); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := h.repository.DeleteStoredProcedure(databaseId, collectionId, spId)
|
status := h.dataStore.DeleteStoredProcedure(databaseId, collectionId, spId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdSP, status := h.repository.CreateStoredProcedure(databaseId, collectionId, sp)
|
createdSP, status := h.dataStore.CreateStoredProcedure(databaseId, collectionId, sp)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, createdSP)
|
c.IndentedJSON(http.StatusOK, createdSP)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,19 +97,19 @@ func (h *Handlers) CreateStoredProcedure(c *gin.Context) {
|
|||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
var sp repositorymodels.StoredProcedure
|
var sp datastore.StoredProcedure
|
||||||
if err := c.BindJSON(&sp); err != nil {
|
if err := c.BindJSON(&sp); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdSP, status := h.repository.CreateStoredProcedure(databaseId, collectionId, sp)
|
createdSP, status := h.dataStore.CreateStoredProcedure(databaseId, collectionId, sp)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdSP)
|
c.IndentedJSON(http.StatusCreated, createdSP)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllTriggers(c *gin.Context) {
|
func (h *Handlers) GetAllTriggers(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
triggers, status := h.repository.GetAllTriggers(databaseId, collectionId)
|
triggers, status := h.dataStore.GetAllTriggers(databaseId, collectionId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(triggers)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(triggers)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Triggers": triggers, "_count": len(triggers)})
|
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Triggers": triggers, "_count": len(triggers)})
|
||||||
return
|
return
|
||||||
@ -28,14 +28,14 @@ func (h *Handlers) GetTrigger(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
triggerId := c.Param("triggerId")
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
trigger, status := h.repository.GetTrigger(databaseId, collectionId, triggerId)
|
trigger, status := h.dataStore.GetTrigger(databaseId, collectionId, triggerId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, trigger)
|
c.IndentedJSON(http.StatusOK, trigger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,13 +48,13 @@ func (h *Handlers) DeleteTrigger(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
triggerId := c.Param("triggerId")
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
status := h.repository.DeleteTrigger(databaseId, collectionId, triggerId)
|
status := h.dataStore.DeleteTrigger(databaseId, collectionId, triggerId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -67,25 +67,25 @@ func (h *Handlers) ReplaceTrigger(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
triggerId := c.Param("triggerId")
|
triggerId := c.Param("triggerId")
|
||||||
|
|
||||||
var trigger repositorymodels.Trigger
|
var trigger datastore.Trigger
|
||||||
if err := c.BindJSON(&trigger); err != nil {
|
if err := c.BindJSON(&trigger); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := h.repository.DeleteTrigger(databaseId, collectionId, triggerId)
|
status := h.dataStore.DeleteTrigger(databaseId, collectionId, triggerId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdTrigger, status := h.repository.CreateTrigger(databaseId, collectionId, trigger)
|
createdTrigger, status := h.dataStore.CreateTrigger(databaseId, collectionId, trigger)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, createdTrigger)
|
c.IndentedJSON(http.StatusOK, createdTrigger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,19 +97,19 @@ func (h *Handlers) CreateTrigger(c *gin.Context) {
|
|||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
var trigger repositorymodels.Trigger
|
var trigger datastore.Trigger
|
||||||
if err := c.BindJSON(&trigger); err != nil {
|
if err := c.BindJSON(&trigger); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdTrigger, status := h.repository.CreateTrigger(databaseId, collectionId, trigger)
|
createdTrigger, status := h.dataStore.CreateTrigger(databaseId, collectionId, trigger)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdTrigger)
|
c.IndentedJSON(http.StatusCreated, createdTrigger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handlers) GetAllUserDefinedFunctions(c *gin.Context) {
|
func (h *Handlers) GetAllUserDefinedFunctions(c *gin.Context) {
|
||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
udfs, status := h.repository.GetAllUserDefinedFunctions(databaseId, collectionId)
|
udfs, status := h.dataStore.GetAllUserDefinedFunctions(databaseId, collectionId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(udfs)))
|
c.Header("x-ms-item-count", fmt.Sprintf("%d", len(udfs)))
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "UserDefinedFunctions": udfs, "_count": len(udfs)})
|
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "UserDefinedFunctions": udfs, "_count": len(udfs)})
|
||||||
return
|
return
|
||||||
@ -28,14 +28,14 @@ func (h *Handlers) GetUserDefinedFunction(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
udfId := c.Param("udfId")
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
udf, status := h.repository.GetUserDefinedFunction(databaseId, collectionId, udfId)
|
udf, status := h.dataStore.GetUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, udf)
|
c.IndentedJSON(http.StatusOK, udf)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,13 +48,13 @@ func (h *Handlers) DeleteUserDefinedFunction(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
udfId := c.Param("udfId")
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
status := h.repository.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
status := h.dataStore.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -67,25 +67,25 @@ func (h *Handlers) ReplaceUserDefinedFunction(c *gin.Context) {
|
|||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
udfId := c.Param("udfId")
|
udfId := c.Param("udfId")
|
||||||
|
|
||||||
var udf repositorymodels.UserDefinedFunction
|
var udf datastore.UserDefinedFunction
|
||||||
if err := c.BindJSON(&udf); err != nil {
|
if err := c.BindJSON(&udf); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status := h.repository.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
status := h.dataStore.DeleteUserDefinedFunction(databaseId, collectionId, udfId)
|
||||||
if status == repositorymodels.StatusNotFound {
|
if status == datastore.StatusNotFound {
|
||||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdUdf, status := h.repository.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
createdUdf, status := h.dataStore.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusOK, createdUdf)
|
c.IndentedJSON(http.StatusOK, createdUdf)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,19 +97,19 @@ func (h *Handlers) CreateUserDefinedFunction(c *gin.Context) {
|
|||||||
databaseId := c.Param("databaseId")
|
databaseId := c.Param("databaseId")
|
||||||
collectionId := c.Param("collId")
|
collectionId := c.Param("collId")
|
||||||
|
|
||||||
var udf repositorymodels.UserDefinedFunction
|
var udf datastore.UserDefinedFunction
|
||||||
if err := c.BindJSON(&udf); err != nil {
|
if err := c.BindJSON(&udf); err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Invalid body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdUdf, status := h.repository.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
createdUdf, status := h.dataStore.CreateUserDefinedFunction(databaseId, collectionId, udf)
|
||||||
if status == repositorymodels.Conflict {
|
if status == datastore.Conflict {
|
||||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == repositorymodels.StatusOk {
|
if status == datastore.StatusOk {
|
||||||
c.IndentedJSON(http.StatusCreated, createdUdf)
|
c.IndentedJSON(http.StatusCreated, createdUdf)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pikami/cosmium/api/handlers"
|
"github.com/pikami/cosmium/api/handlers"
|
||||||
"github.com/pikami/cosmium/api/handlers/middleware"
|
"github.com/pikami/cosmium/api/handlers/middleware"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/logger"
|
"github.com/pikami/cosmium/internal/logger"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
|
||||||
tlsprovider "github.com/pikami/cosmium/internal/tls_provider"
|
tlsprovider "github.com/pikami/cosmium/internal/tls_provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ginMux sync.Mutex
|
var ginMux sync.Mutex
|
||||||
|
|
||||||
func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
|
func (s *ApiServer) CreateRouter(dataStore datastore.DataStore) {
|
||||||
routeHandlers := handlers.NewHandlers(repository, s.config)
|
routeHandlers := handlers.NewHandlers(dataStore, s.config)
|
||||||
|
|
||||||
ginMux.Lock()
|
ginMux.Lock()
|
||||||
gin.DefaultWriter = logger.InfoWriter()
|
gin.DefaultWriter = logger.InfoWriter()
|
||||||
|
@ -17,7 +17,7 @@ func Test_Authentication(t *testing.T) {
|
|||||||
defer ts.Server.Close()
|
defer ts.Server.Close()
|
||||||
|
|
||||||
t.Run("Should get 200 when correct account key is used", func(t *testing.T) {
|
t.Run("Should get 200 when correct account key is used", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
client, err := azcosmos.NewClientFromConnectionString(
|
client, err := azcosmos.NewClientFromConnectionString(
|
||||||
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, config.DefaultAccountKey),
|
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, config.DefaultAccountKey),
|
||||||
&azcosmos.ClientOptions{},
|
&azcosmos.ClientOptions{},
|
||||||
@ -33,7 +33,7 @@ func Test_Authentication(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should get 401 when wrong account key is used", func(t *testing.T) {
|
t.Run("Should get 401 when wrong account key is used", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
client, err := azcosmos.NewClientFromConnectionString(
|
client, err := azcosmos.NewClientFromConnectionString(
|
||||||
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, "AAAA"),
|
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, "AAAA"),
|
||||||
&azcosmos.ClientOptions{},
|
&azcosmos.ClientOptions{},
|
||||||
@ -70,7 +70,7 @@ func Test_Authentication_Disabled(t *testing.T) {
|
|||||||
defer ts.Server.Close()
|
defer ts.Server.Close()
|
||||||
|
|
||||||
t.Run("Should get 200 when wrong account key is used, but authentication is dissabled", func(t *testing.T) {
|
t.Run("Should get 200 when wrong account key is used, but authentication is dissabled", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
client, err := azcosmos.NewClientFromConnectionString(
|
client, err := azcosmos.NewClientFromConnectionString(
|
||||||
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, "AAAA"),
|
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, "AAAA"),
|
||||||
&azcosmos.ClientOptions{},
|
&azcosmos.ClientOptions{},
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
ts.Repository.CreateDatabase(repositorymodels.Database{ID: testDatabaseName})
|
ts.DataStore.CreateDatabase(datastore.Database{ID: testDatabaseName})
|
||||||
databaseClient, err := client.NewDatabase(testDatabaseName)
|
databaseClient, err := client.NewDatabase(testDatabaseName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return conflict when collection exists", func(t *testing.T) {
|
t.Run("Should return conflict when collection exists", func(t *testing.T) {
|
||||||
ts.Repository.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
ts.DataStore.CreateCollection(testDatabaseName, datastore.Collection{
|
||||||
ID: testCollectionName,
|
ID: testCollectionName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Collection Read", func(t *testing.T) {
|
t.Run("Collection Read", func(t *testing.T) {
|
||||||
t.Run("Should read collection", func(t *testing.T) {
|
t.Run("Should read collection", func(t *testing.T) {
|
||||||
ts.Repository.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
ts.DataStore.CreateCollection(testDatabaseName, datastore.Collection{
|
||||||
ID: testCollectionName,
|
ID: testCollectionName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return not found when collection does not exist", func(t *testing.T) {
|
t.Run("Should return not found when collection does not exist", func(t *testing.T) {
|
||||||
ts.Repository.DeleteCollection(testDatabaseName, testCollectionName)
|
ts.DataStore.DeleteCollection(testDatabaseName, testCollectionName)
|
||||||
|
|
||||||
collectionResponse, err := databaseClient.NewContainer(testCollectionName)
|
collectionResponse, err := databaseClient.NewContainer(testCollectionName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@ -92,7 +92,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Collection Delete", func(t *testing.T) {
|
t.Run("Collection Delete", func(t *testing.T) {
|
||||||
t.Run("Should delete collection", func(t *testing.T) {
|
t.Run("Should delete collection", func(t *testing.T) {
|
||||||
ts.Repository.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
ts.DataStore.CreateCollection(testDatabaseName, datastore.Collection{
|
||||||
ID: testCollectionName,
|
ID: testCollectionName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ func Test_Collections(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return not found when collection does not exist", func(t *testing.T) {
|
t.Run("Should return not found when collection does not exist", func(t *testing.T) {
|
||||||
ts.Repository.DeleteCollection(testDatabaseName, testCollectionName)
|
ts.DataStore.DeleteCollection(testDatabaseName, testCollectionName)
|
||||||
|
|
||||||
collectionResponse, err := databaseClient.NewContainer(testCollectionName)
|
collectionResponse, err := databaseClient.NewContainer(testCollectionName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@ -5,29 +5,30 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/api"
|
"github.com/pikami/cosmium/api"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
|
mapdatastore "github.com/pikami/cosmium/internal/datastore/map_datastore"
|
||||||
"github.com/pikami/cosmium/internal/logger"
|
"github.com/pikami/cosmium/internal/logger"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestServer struct {
|
type TestServer struct {
|
||||||
Server *httptest.Server
|
Server *httptest.Server
|
||||||
Repository *repositories.DataRepository
|
DataStore datastore.DataStore
|
||||||
URL string
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestServerCustomConfig(config *config.ServerConfig) *TestServer {
|
func runTestServerCustomConfig(config *config.ServerConfig) *TestServer {
|
||||||
repository := repositories.NewDataRepository(repositories.RepositoryOptions{})
|
dataStore := mapdatastore.NewMapDataStore(mapdatastore.MapDataStoreOptions{})
|
||||||
|
|
||||||
api := api.NewApiServer(repository, config)
|
api := api.NewApiServer(dataStore, config)
|
||||||
|
|
||||||
server := httptest.NewServer(api.GetRouter())
|
server := httptest.NewServer(api.GetRouter())
|
||||||
|
|
||||||
config.DatabaseEndpoint = server.URL
|
config.DatabaseEndpoint = server.URL
|
||||||
|
|
||||||
return &TestServer{
|
return &TestServer{
|
||||||
Server: server,
|
Server: server,
|
||||||
Repository: repository,
|
DataStore: dataStore,
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Database Create", func(t *testing.T) {
|
t.Run("Database Create", func(t *testing.T) {
|
||||||
t.Run("Should create database", func(t *testing.T) {
|
t.Run("Should create database", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
|
|
||||||
createResponse, err := client.CreateDatabase(context.TODO(), azcosmos.DatabaseProperties{
|
createResponse, err := client.CreateDatabase(context.TODO(), azcosmos.DatabaseProperties{
|
||||||
ID: testDatabaseName,
|
ID: testDatabaseName,
|
||||||
@ -37,7 +37,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return conflict when database exists", func(t *testing.T) {
|
t.Run("Should return conflict when database exists", func(t *testing.T) {
|
||||||
ts.Repository.CreateDatabase(repositorymodels.Database{
|
ts.DataStore.CreateDatabase(datastore.Database{
|
||||||
ID: testDatabaseName,
|
ID: testDatabaseName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Database Read", func(t *testing.T) {
|
t.Run("Database Read", func(t *testing.T) {
|
||||||
t.Run("Should read database", func(t *testing.T) {
|
t.Run("Should read database", func(t *testing.T) {
|
||||||
ts.Repository.CreateDatabase(repositorymodels.Database{
|
ts.DataStore.CreateDatabase(datastore.Database{
|
||||||
ID: testDatabaseName,
|
ID: testDatabaseName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return not found when database does not exist", func(t *testing.T) {
|
t.Run("Should return not found when database does not exist", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
|
|
||||||
databaseResponse, err := client.NewDatabase(testDatabaseName)
|
databaseResponse, err := client.NewDatabase(testDatabaseName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@ -90,7 +90,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Database Delete", func(t *testing.T) {
|
t.Run("Database Delete", func(t *testing.T) {
|
||||||
t.Run("Should delete database", func(t *testing.T) {
|
t.Run("Should delete database", func(t *testing.T) {
|
||||||
ts.Repository.CreateDatabase(repositorymodels.Database{
|
ts.DataStore.CreateDatabase(datastore.Database{
|
||||||
ID: testDatabaseName,
|
ID: testDatabaseName,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ func Test_Databases(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should return not found when database does not exist", func(t *testing.T) {
|
t.Run("Should return not found when database does not exist", func(t *testing.T) {
|
||||||
ts.Repository.DeleteDatabase(testDatabaseName)
|
ts.DataStore.DeleteDatabase(testDatabaseName)
|
||||||
|
|
||||||
databaseResponse, err := client.NewDatabase(testDatabaseName)
|
databaseResponse, err := client.NewDatabase(testDatabaseName)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,8 +56,8 @@ func testCosmosQuery(t *testing.T,
|
|||||||
func documents_InitializeDb(t *testing.T) (*TestServer, *azcosmos.ContainerClient) {
|
func documents_InitializeDb(t *testing.T) (*TestServer, *azcosmos.ContainerClient) {
|
||||||
ts := runTestServer()
|
ts := runTestServer()
|
||||||
|
|
||||||
ts.Repository.CreateDatabase(repositorymodels.Database{ID: testDatabaseName})
|
ts.DataStore.CreateDatabase(datastore.Database{ID: testDatabaseName})
|
||||||
ts.Repository.CreateCollection(testDatabaseName, repositorymodels.Collection{
|
ts.DataStore.CreateCollection(testDatabaseName, datastore.Collection{
|
||||||
ID: testCollectionName,
|
ID: testCollectionName,
|
||||||
PartitionKey: struct {
|
PartitionKey: struct {
|
||||||
Paths []string "json:\"paths\""
|
Paths []string "json:\"paths\""
|
||||||
@ -67,8 +67,8 @@ func documents_InitializeDb(t *testing.T) (*TestServer, *azcosmos.ContainerClien
|
|||||||
Paths: []string{"/pk"},
|
Paths: []string{"/pk"},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
ts.Repository.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "12345", "pk": "123", "isCool": false, "arr": []int{1, 2, 3}})
|
ts.DataStore.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "12345", "pk": "123", "isCool": false, "arr": []int{1, 2, 3}})
|
||||||
ts.Repository.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "67890", "pk": "456", "isCool": true, "arr": []int{6, 7, 8}})
|
ts.DataStore.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "67890", "pk": "456", "isCool": true, "arr": []int{6, 7, 8}})
|
||||||
|
|
||||||
client, err := azcosmos.NewClientFromConnectionString(
|
client, err := azcosmos.NewClientFromConnectionString(
|
||||||
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, config.DefaultAccountKey),
|
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, config.DefaultAccountKey),
|
||||||
@ -408,7 +408,7 @@ func Test_Documents_TransactionalBatch(t *testing.T) {
|
|||||||
json.Unmarshal(operationResponse.ResourceBody, &itemResponseBody)
|
json.Unmarshal(operationResponse.ResourceBody, &itemResponseBody)
|
||||||
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
||||||
|
|
||||||
createdDoc, _ := ts.Repository.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
createdDoc, _ := ts.DataStore.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
||||||
assert.Equal(t, newItem["id"], createdDoc["id"])
|
assert.Equal(t, newItem["id"], createdDoc["id"])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -426,8 +426,8 @@ func Test_Documents_TransactionalBatch(t *testing.T) {
|
|||||||
assert.NotNil(t, operationResponse)
|
assert.NotNil(t, operationResponse)
|
||||||
assert.Equal(t, int32(http.StatusNoContent), operationResponse.StatusCode)
|
assert.Equal(t, int32(http.StatusNoContent), operationResponse.StatusCode)
|
||||||
|
|
||||||
_, status := ts.Repository.GetDocument(testDatabaseName, testCollectionName, "12345")
|
_, status := ts.DataStore.GetDocument(testDatabaseName, testCollectionName, "12345")
|
||||||
assert.Equal(t, repositorymodels.StatusNotFound, int(status))
|
assert.Equal(t, datastore.StatusNotFound, int(status))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should execute REPLACE transactional batch", func(t *testing.T) {
|
t.Run("Should execute REPLACE transactional batch", func(t *testing.T) {
|
||||||
@ -457,7 +457,7 @@ func Test_Documents_TransactionalBatch(t *testing.T) {
|
|||||||
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
||||||
assert.Equal(t, newItem["pk"], itemResponseBody["pk"])
|
assert.Equal(t, newItem["pk"], itemResponseBody["pk"])
|
||||||
|
|
||||||
updatedDoc, _ := ts.Repository.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
updatedDoc, _ := ts.DataStore.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
||||||
assert.Equal(t, newItem["id"], updatedDoc["id"])
|
assert.Equal(t, newItem["id"], updatedDoc["id"])
|
||||||
assert.Equal(t, newItem["pk"], updatedDoc["pk"])
|
assert.Equal(t, newItem["pk"], updatedDoc["pk"])
|
||||||
})
|
})
|
||||||
@ -489,7 +489,7 @@ func Test_Documents_TransactionalBatch(t *testing.T) {
|
|||||||
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
assert.Equal(t, newItem["id"], itemResponseBody["id"])
|
||||||
assert.Equal(t, newItem["pk"], itemResponseBody["pk"])
|
assert.Equal(t, newItem["pk"], itemResponseBody["pk"])
|
||||||
|
|
||||||
updatedDoc, _ := ts.Repository.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
updatedDoc, _ := ts.DataStore.GetDocument(testDatabaseName, testCollectionName, newItem["id"].(string))
|
||||||
assert.Equal(t, newItem["id"], updatedDoc["id"])
|
assert.Equal(t, newItem["id"], updatedDoc["id"])
|
||||||
assert.Equal(t, newItem["pk"], updatedDoc["pk"])
|
assert.Equal(t, newItem["pk"], updatedDoc["pk"])
|
||||||
})
|
})
|
||||||
|
@ -7,27 +7,28 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/api"
|
"github.com/pikami/cosmium/api"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
|
mapdatastore "github.com/pikami/cosmium/internal/datastore/map_datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
configuration := config.ParseFlags()
|
configuration := config.ParseFlags()
|
||||||
|
|
||||||
repository := repositories.NewDataRepository(repositories.RepositoryOptions{
|
var dataStore datastore.DataStore = mapdatastore.NewMapDataStore(mapdatastore.MapDataStoreOptions{
|
||||||
InitialDataFilePath: configuration.InitialDataFilePath,
|
InitialDataFilePath: configuration.InitialDataFilePath,
|
||||||
PersistDataFilePath: configuration.PersistDataFilePath,
|
PersistDataFilePath: configuration.PersistDataFilePath,
|
||||||
})
|
})
|
||||||
|
|
||||||
server := api.NewApiServer(repository, &configuration)
|
server := api.NewApiServer(dataStore, &configuration)
|
||||||
err := server.Start()
|
err := server.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForExit(server, repository, configuration)
|
waitForExit(server, dataStore, configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForExit(server *api.ApiServer, repository *repositories.DataRepository, config config.ServerConfig) {
|
func waitForExit(server *api.ApiServer, dataStore datastore.DataStore, config config.ServerConfig) {
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
@ -37,7 +38,5 @@ func waitForExit(server *api.ApiServer, repository *repositories.DataRepository,
|
|||||||
// Stop the server
|
// Stop the server
|
||||||
server.Stop()
|
server.Stop()
|
||||||
|
|
||||||
if config.PersistDataFilePath != "" {
|
dataStore.Close()
|
||||||
repository.SaveStateFS(config.PersistDataFilePath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
44
internal/datastore/datastore.go
Normal file
44
internal/datastore/datastore.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package datastore
|
||||||
|
|
||||||
|
type DataStore interface {
|
||||||
|
GetAllDatabases() ([]Database, DataStoreStatus)
|
||||||
|
GetDatabase(databaseId string) (Database, DataStoreStatus)
|
||||||
|
DeleteDatabase(databaseId string) DataStoreStatus
|
||||||
|
CreateDatabase(newDatabase Database) (Database, DataStoreStatus)
|
||||||
|
|
||||||
|
GetAllCollections(databaseId string) ([]Collection, DataStoreStatus)
|
||||||
|
GetCollection(databaseId string, collectionId string) (Collection, DataStoreStatus)
|
||||||
|
DeleteCollection(databaseId string, collectionId string) DataStoreStatus
|
||||||
|
CreateCollection(databaseId string, newCollection Collection) (Collection, DataStoreStatus)
|
||||||
|
|
||||||
|
GetAllDocuments(databaseId string, collectionId string) ([]Document, DataStoreStatus)
|
||||||
|
GetDocumentIterator(databaseId string, collectionId string) (DocumentIterator, DataStoreStatus)
|
||||||
|
GetDocument(databaseId string, collectionId string, documentId string) (Document, DataStoreStatus)
|
||||||
|
DeleteDocument(databaseId string, collectionId string, documentId string) DataStoreStatus
|
||||||
|
CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (Document, DataStoreStatus)
|
||||||
|
|
||||||
|
GetAllTriggers(databaseId string, collectionId string) ([]Trigger, DataStoreStatus)
|
||||||
|
GetTrigger(databaseId string, collectionId string, triggerId string) (Trigger, DataStoreStatus)
|
||||||
|
DeleteTrigger(databaseId string, collectionId string, triggerId string) DataStoreStatus
|
||||||
|
CreateTrigger(databaseId string, collectionId string, trigger Trigger) (Trigger, DataStoreStatus)
|
||||||
|
|
||||||
|
GetAllStoredProcedures(databaseId string, collectionId string) ([]StoredProcedure, DataStoreStatus)
|
||||||
|
GetStoredProcedure(databaseId string, collectionId string, storedProcedureId string) (StoredProcedure, DataStoreStatus)
|
||||||
|
DeleteStoredProcedure(databaseId string, collectionId string, storedProcedureId string) DataStoreStatus
|
||||||
|
CreateStoredProcedure(databaseId string, collectionId string, storedProcedure StoredProcedure) (StoredProcedure, DataStoreStatus)
|
||||||
|
|
||||||
|
GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]UserDefinedFunction, DataStoreStatus)
|
||||||
|
GetUserDefinedFunction(databaseId string, collectionId string, udfId string) (UserDefinedFunction, DataStoreStatus)
|
||||||
|
DeleteUserDefinedFunction(databaseId string, collectionId string, udfId string) DataStoreStatus
|
||||||
|
CreateUserDefinedFunction(databaseId string, collectionId string, udf UserDefinedFunction) (UserDefinedFunction, DataStoreStatus)
|
||||||
|
|
||||||
|
GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionKeyRange, DataStoreStatus)
|
||||||
|
|
||||||
|
Close()
|
||||||
|
DumpToJson() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DocumentIterator interface {
|
||||||
|
Next() (Document, DataStoreStatus)
|
||||||
|
HasMore() bool
|
||||||
|
}
|
21
internal/datastore/map_datastore/array_document_iterator.go
Normal file
21
internal/datastore/map_datastore/array_document_iterator.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package mapdatastore
|
||||||
|
|
||||||
|
import "github.com/pikami/cosmium/internal/datastore"
|
||||||
|
|
||||||
|
type ArrayDocumentIterator struct {
|
||||||
|
documents []datastore.Document
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ArrayDocumentIterator) Next() (datastore.Document, datastore.DataStoreStatus) {
|
||||||
|
i.index++
|
||||||
|
if i.index >= len(i.documents) {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.documents[i.index], datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ArrayDocumentIterator) HasMore() bool {
|
||||||
|
return i.index < len(i.documents)-1
|
||||||
|
}
|
@ -1,52 +1,52 @@
|
|||||||
package repositories
|
package mapdatastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
structhidrators "github.com/pikami/cosmium/internal/struct_hidrators"
|
structhidrators "github.com/pikami/cosmium/internal/struct_hidrators"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllCollections(databaseId string) ([]repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetAllCollections(databaseId string) ([]datastore.Collection, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
return make([]repositorymodels.Collection, 0), repositorymodels.StatusNotFound
|
return make([]datastore.Collection, 0), datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return maps.Values(r.storeState.Collections[databaseId]), repositorymodels.StatusOk
|
return maps.Values(r.storeState.Collections[databaseId]), datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) GetCollection(databaseId string, collectionId string) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetCollection(databaseId string, collectionId string) (datastore.Collection, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
return datastore.Collection{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
return datastore.Collection{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.storeState.Collections[databaseId][collectionId], repositorymodels.StatusOk
|
return r.storeState.Collections[databaseId][collectionId], datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) DeleteCollection(databaseId string, collectionId string) repositorymodels.RepositoryStatus {
|
func (r *MapDataStore) DeleteCollection(databaseId string, collectionId string) datastore.DataStoreStatus {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(r.storeState.Collections[databaseId], collectionId)
|
delete(r.storeState.Collections[databaseId], collectionId)
|
||||||
@ -55,24 +55,24 @@ func (r *DataRepository) DeleteCollection(databaseId string, collectionId string
|
|||||||
delete(r.storeState.StoredProcedures[databaseId], collectionId)
|
delete(r.storeState.StoredProcedures[databaseId], collectionId)
|
||||||
delete(r.storeState.UserDefinedFunctions[databaseId], collectionId)
|
delete(r.storeState.UserDefinedFunctions[databaseId], collectionId)
|
||||||
|
|
||||||
return repositorymodels.StatusOk
|
return datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) CreateCollection(databaseId string, newCollection repositorymodels.Collection) (repositorymodels.Collection, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) CreateCollection(databaseId string, newCollection datastore.Collection) (datastore.Collection, datastore.DataStoreStatus) {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
var database repositorymodels.Database
|
var database datastore.Database
|
||||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.Collection{}, repositorymodels.StatusNotFound
|
return datastore.Collection{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok = r.storeState.Collections[databaseId][newCollection.ID]; ok {
|
if _, ok = r.storeState.Collections[databaseId][newCollection.ID]; ok {
|
||||||
return repositorymodels.Collection{}, repositorymodels.Conflict
|
return datastore.Collection{}, datastore.Conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
newCollection = structhidrators.Hidrate(newCollection).(repositorymodels.Collection)
|
newCollection = structhidrators.Hidrate(newCollection).(datastore.Collection)
|
||||||
|
|
||||||
newCollection.TimeStamp = time.Now().Unix()
|
newCollection.TimeStamp = time.Now().Unix()
|
||||||
newCollection.ResourceID = resourceid.NewCombined(database.ResourceID, resourceid.New(resourceid.ResourceTypeCollection))
|
newCollection.ResourceID = resourceid.NewCombined(database.ResourceID, resourceid.New(resourceid.ResourceTypeCollection))
|
||||||
@ -80,10 +80,10 @@ func (r *DataRepository) CreateCollection(databaseId string, newCollection repos
|
|||||||
newCollection.Self = fmt.Sprintf("dbs/%s/colls/%s/", database.ResourceID, newCollection.ResourceID)
|
newCollection.Self = fmt.Sprintf("dbs/%s/colls/%s/", database.ResourceID, newCollection.ResourceID)
|
||||||
|
|
||||||
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]datastore.Document)
|
||||||
r.storeState.Triggers[databaseId][newCollection.ID] = make(map[string]repositorymodels.Trigger)
|
r.storeState.Triggers[databaseId][newCollection.ID] = make(map[string]datastore.Trigger)
|
||||||
r.storeState.StoredProcedures[databaseId][newCollection.ID] = make(map[string]repositorymodels.StoredProcedure)
|
r.storeState.StoredProcedures[databaseId][newCollection.ID] = make(map[string]datastore.StoredProcedure)
|
||||||
r.storeState.UserDefinedFunctions[databaseId][newCollection.ID] = make(map[string]repositorymodels.UserDefinedFunction)
|
r.storeState.UserDefinedFunctions[databaseId][newCollection.ID] = make(map[string]datastore.UserDefinedFunction)
|
||||||
|
|
||||||
return newCollection, repositorymodels.StatusOk
|
return newCollection, datastore.StatusOk
|
||||||
}
|
}
|
@ -1,39 +1,39 @@
|
|||||||
package repositories
|
package mapdatastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllDatabases() ([]repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetAllDatabases() ([]datastore.Database, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
return maps.Values(r.storeState.Databases), repositorymodels.StatusOk
|
return maps.Values(r.storeState.Databases), datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) GetDatabase(id string) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetDatabase(id string) (datastore.Database, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
if database, ok := r.storeState.Databases[id]; ok {
|
if database, ok := r.storeState.Databases[id]; ok {
|
||||||
return database, repositorymodels.StatusOk
|
return database, datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.Database{}, repositorymodels.StatusNotFound
|
return datastore.Database{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) DeleteDatabase(id string) repositorymodels.RepositoryStatus {
|
func (r *MapDataStore) DeleteDatabase(id string) datastore.DataStoreStatus {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[id]; !ok {
|
if _, ok := r.storeState.Databases[id]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(r.storeState.Databases, id)
|
delete(r.storeState.Databases, id)
|
||||||
@ -43,15 +43,15 @@ func (r *DataRepository) DeleteDatabase(id string) repositorymodels.RepositorySt
|
|||||||
delete(r.storeState.StoredProcedures, id)
|
delete(r.storeState.StoredProcedures, id)
|
||||||
delete(r.storeState.UserDefinedFunctions, id)
|
delete(r.storeState.UserDefinedFunctions, id)
|
||||||
|
|
||||||
return repositorymodels.StatusOk
|
return datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) CreateDatabase(newDatabase repositorymodels.Database) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) CreateDatabase(newDatabase datastore.Database) (datastore.Database, datastore.DataStoreStatus) {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[newDatabase.ID]; ok {
|
if _, ok := r.storeState.Databases[newDatabase.ID]; ok {
|
||||||
return repositorymodels.Database{}, repositorymodels.Conflict
|
return datastore.Database{}, datastore.Conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
newDatabase.TimeStamp = time.Now().Unix()
|
newDatabase.TimeStamp = time.Now().Unix()
|
||||||
@ -60,11 +60,11 @@ func (r *DataRepository) CreateDatabase(newDatabase repositorymodels.Database) (
|
|||||||
newDatabase.Self = fmt.Sprintf("dbs/%s/", newDatabase.ResourceID)
|
newDatabase.Self = fmt.Sprintf("dbs/%s/", newDatabase.ResourceID)
|
||||||
|
|
||||||
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]datastore.Collection)
|
||||||
r.storeState.Documents[newDatabase.ID] = make(map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents[newDatabase.ID] = make(map[string]map[string]datastore.Document)
|
||||||
r.storeState.Triggers[newDatabase.ID] = make(map[string]map[string]repositorymodels.Trigger)
|
r.storeState.Triggers[newDatabase.ID] = make(map[string]map[string]datastore.Trigger)
|
||||||
r.storeState.StoredProcedures[newDatabase.ID] = make(map[string]map[string]repositorymodels.StoredProcedure)
|
r.storeState.StoredProcedures[newDatabase.ID] = make(map[string]map[string]datastore.StoredProcedure)
|
||||||
r.storeState.UserDefinedFunctions[newDatabase.ID] = make(map[string]map[string]repositorymodels.UserDefinedFunction)
|
r.storeState.UserDefinedFunctions[newDatabase.ID] = make(map[string]map[string]datastore.UserDefinedFunction)
|
||||||
|
|
||||||
return newDatabase, repositorymodels.StatusOk
|
return newDatabase, datastore.StatusOk
|
||||||
}
|
}
|
113
internal/datastore/map_datastore/documents.go
Normal file
113
internal/datastore/map_datastore/documents.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package mapdatastore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetAllDocuments(databaseId string, collectionId string) ([]datastore.Document, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return make([]datastore.Document, 0), datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return make([]datastore.Document, 0), datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.Documents[databaseId][collectionId]), datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetDocument(databaseId string, collectionId string, documentId string) (datastore.Document, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.storeState.Documents[databaseId][collectionId][documentId], datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) DeleteDocument(databaseId string, collectionId string, documentId string) datastore.DataStoreStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.Documents[databaseId][collectionId], documentId)
|
||||||
|
|
||||||
|
return datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (datastore.Document, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var documentId string
|
||||||
|
var database datastore.Database
|
||||||
|
var collection datastore.Collection
|
||||||
|
if documentId, ok = document["id"].(string); !ok || documentId == "" {
|
||||||
|
documentId = fmt.Sprint(uuid.New())
|
||||||
|
document["id"] = documentId
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.Document{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; ok {
|
||||||
|
return datastore.Document{}, datastore.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
document["_ts"] = time.Now().Unix()
|
||||||
|
document["_rid"] = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeDocument))
|
||||||
|
document["_etag"] = fmt.Sprintf("\"%s\"", uuid.New())
|
||||||
|
document["_self"] = fmt.Sprintf("dbs/%s/colls/%s/docs/%s/", database.ResourceID, collection.ResourceID, document["_rid"])
|
||||||
|
|
||||||
|
r.storeState.Documents[databaseId][collectionId][documentId] = document
|
||||||
|
|
||||||
|
return document, datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetDocumentIterator(databaseId string, collectionId string) (datastore.DocumentIterator, datastore.DataStoreStatus) {
|
||||||
|
documents, status := r.GetAllDocuments(databaseId, collectionId)
|
||||||
|
if status != datastore.StatusOk {
|
||||||
|
return nil, status
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ArrayDocumentIterator{
|
||||||
|
documents: documents,
|
||||||
|
index: -1,
|
||||||
|
}, datastore.StatusOk
|
||||||
|
}
|
34
internal/datastore/map_datastore/map_datastore.go
Normal file
34
internal/datastore/map_datastore/map_datastore.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package mapdatastore
|
||||||
|
|
||||||
|
import "github.com/pikami/cosmium/internal/datastore"
|
||||||
|
|
||||||
|
type MapDataStore struct {
|
||||||
|
storeState State
|
||||||
|
|
||||||
|
initialDataFilePath string
|
||||||
|
persistDataFilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapDataStoreOptions struct {
|
||||||
|
InitialDataFilePath string
|
||||||
|
PersistDataFilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMapDataStore(options MapDataStoreOptions) *MapDataStore {
|
||||||
|
dataStore := &MapDataStore{
|
||||||
|
storeState: State{
|
||||||
|
Databases: make(map[string]datastore.Database),
|
||||||
|
Collections: make(map[string]map[string]datastore.Collection),
|
||||||
|
Documents: make(map[string]map[string]map[string]datastore.Document),
|
||||||
|
Triggers: make(map[string]map[string]map[string]datastore.Trigger),
|
||||||
|
StoredProcedures: make(map[string]map[string]map[string]datastore.StoredProcedure),
|
||||||
|
UserDefinedFunctions: make(map[string]map[string]map[string]datastore.UserDefinedFunction),
|
||||||
|
},
|
||||||
|
initialDataFilePath: options.InitialDataFilePath,
|
||||||
|
persistDataFilePath: options.PersistDataFilePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStore.InitializeDataStore()
|
||||||
|
|
||||||
|
return dataStore
|
||||||
|
}
|
@ -1,15 +1,15 @@
|
|||||||
package repositories
|
package mapdatastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// I have no idea what this is tbh
|
// I have no idea what this is tbh
|
||||||
func (r *DataRepository) GetPartitionKeyRanges(databaseId string, collectionId string) ([]repositorymodels.PartitionKeyRange, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetPartitionKeyRanges(databaseId string, collectionId string) ([]datastore.PartitionKeyRange, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ func (r *DataRepository) GetPartitionKeyRanges(databaseId string, collectionId s
|
|||||||
pkrSelf := fmt.Sprintf("dbs/%s/colls/%s/pkranges/%s/", databaseRid, collectionRid, pkrResourceId)
|
pkrSelf := fmt.Sprintf("dbs/%s/colls/%s/pkranges/%s/", databaseRid, collectionRid, pkrResourceId)
|
||||||
etag := fmt.Sprintf("\"%s\"", uuid.New())
|
etag := fmt.Sprintf("\"%s\"", uuid.New())
|
||||||
|
|
||||||
return []repositorymodels.PartitionKeyRange{
|
return []datastore.PartitionKeyRange{
|
||||||
{
|
{
|
||||||
ResourceID: pkrResourceId,
|
ResourceID: pkrResourceId,
|
||||||
ID: "0",
|
ID: "0",
|
||||||
@ -45,5 +45,5 @@ func (r *DataRepository) GetPartitionKeyRanges(databaseId string, collectionId s
|
|||||||
TimeStamp: timestamp,
|
TimeStamp: timestamp,
|
||||||
Lsn: 17,
|
Lsn: 17,
|
||||||
},
|
},
|
||||||
}, repositorymodels.StatusOk
|
}, datastore.StatusOk
|
||||||
}
|
}
|
@ -1,16 +1,39 @@
|
|||||||
package repositories
|
package mapdatastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/logger"
|
"github.com/pikami/cosmium/internal/logger"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *DataRepository) InitializeRepository() {
|
type State struct {
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
|
// Map databaseId -> Database
|
||||||
|
Databases map[string]datastore.Database `json:"databases"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> Collection
|
||||||
|
Collections map[string]map[string]datastore.Collection `json:"collections"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> documentId -> Documents
|
||||||
|
Documents map[string]map[string]map[string]datastore.Document `json:"documents"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> triggerId -> Trigger
|
||||||
|
Triggers map[string]map[string]map[string]datastore.Trigger `json:"triggers"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> spId -> StoredProcedure
|
||||||
|
StoredProcedures map[string]map[string]map[string]datastore.StoredProcedure `json:"sprocs"`
|
||||||
|
|
||||||
|
// Map databaseId -> collectionId -> udfId -> UserDefinedFunction
|
||||||
|
UserDefinedFunctions map[string]map[string]map[string]datastore.UserDefinedFunction `json:"udfs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) InitializeDataStore() {
|
||||||
if r.initialDataFilePath != "" {
|
if r.initialDataFilePath != "" {
|
||||||
r.LoadStateFS(r.initialDataFilePath)
|
r.LoadStateFS(r.initialDataFilePath)
|
||||||
return
|
return
|
||||||
@ -32,7 +55,7 @@ func (r *DataRepository) InitializeRepository() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) LoadStateFS(filePath string) {
|
func (r *MapDataStore) LoadStateFS(filePath string) {
|
||||||
data, err := os.ReadFile(filePath)
|
data, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error reading state JSON file: %v", err)
|
log.Fatalf("Error reading state JSON file: %v", err)
|
||||||
@ -45,11 +68,11 @@ func (r *DataRepository) LoadStateFS(filePath string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) LoadStateJSON(jsonData string) error {
|
func (r *MapDataStore) LoadStateJSON(jsonData string) error {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
var state repositorymodels.State
|
var state State
|
||||||
if err := json.Unmarshal([]byte(jsonData), &state); err != nil {
|
if err := json.Unmarshal([]byte(jsonData), &state); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -71,7 +94,7 @@ func (r *DataRepository) LoadStateJSON(jsonData string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) SaveStateFS(filePath string) {
|
func (r *MapDataStore) SaveStateFS(filePath string) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
@ -92,7 +115,7 @@ func (r *DataRepository) SaveStateFS(filePath string) {
|
|||||||
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) GetState() (string, error) {
|
func (r *MapDataStore) DumpToJson() (string, error) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
@ -103,16 +126,23 @@ func (r *DataRepository) GetState() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return string(data), nil
|
return string(data), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) Close() {
|
||||||
|
if r.persistDataFilePath != "" {
|
||||||
|
r.SaveStateFS(r.persistDataFilePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLength(v interface{}) int {
|
func getLength(v interface{}) int {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case repositorymodels.Database,
|
case datastore.Database,
|
||||||
repositorymodels.Collection,
|
datastore.Collection,
|
||||||
repositorymodels.Document,
|
datastore.Document,
|
||||||
repositorymodels.Trigger,
|
datastore.Trigger,
|
||||||
repositorymodels.StoredProcedure,
|
datastore.StoredProcedure,
|
||||||
repositorymodels.UserDefinedFunction:
|
datastore.UserDefinedFunction:
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,55 +163,55 @@ func getLength(v interface{}) int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) ensureStoreStateNoNullReferences() {
|
func (r *MapDataStore) ensureStoreStateNoNullReferences() {
|
||||||
if r.storeState.Databases == nil {
|
if r.storeState.Databases == nil {
|
||||||
r.storeState.Databases = make(map[string]repositorymodels.Database)
|
r.storeState.Databases = make(map[string]datastore.Database)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Collections == nil {
|
if r.storeState.Collections == nil {
|
||||||
r.storeState.Collections = make(map[string]map[string]repositorymodels.Collection)
|
r.storeState.Collections = make(map[string]map[string]datastore.Collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Documents == nil {
|
if r.storeState.Documents == nil {
|
||||||
r.storeState.Documents = make(map[string]map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents = make(map[string]map[string]map[string]datastore.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Triggers == nil {
|
if r.storeState.Triggers == nil {
|
||||||
r.storeState.Triggers = make(map[string]map[string]map[string]repositorymodels.Trigger)
|
r.storeState.Triggers = make(map[string]map[string]map[string]datastore.Trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.StoredProcedures == nil {
|
if r.storeState.StoredProcedures == nil {
|
||||||
r.storeState.StoredProcedures = make(map[string]map[string]map[string]repositorymodels.StoredProcedure)
|
r.storeState.StoredProcedures = make(map[string]map[string]map[string]datastore.StoredProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.UserDefinedFunctions == nil {
|
if r.storeState.UserDefinedFunctions == nil {
|
||||||
r.storeState.UserDefinedFunctions = make(map[string]map[string]map[string]repositorymodels.UserDefinedFunction)
|
r.storeState.UserDefinedFunctions = make(map[string]map[string]map[string]datastore.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]datastore.Collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Documents[database] == nil {
|
if r.storeState.Documents[database] == nil {
|
||||||
r.storeState.Documents[database] = make(map[string]map[string]repositorymodels.Document)
|
r.storeState.Documents[database] = make(map[string]map[string]datastore.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Triggers[database] == nil {
|
if r.storeState.Triggers[database] == nil {
|
||||||
r.storeState.Triggers[database] = make(map[string]map[string]repositorymodels.Trigger)
|
r.storeState.Triggers[database] = make(map[string]map[string]datastore.Trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.StoredProcedures[database] == nil {
|
if r.storeState.StoredProcedures[database] == nil {
|
||||||
r.storeState.StoredProcedures[database] = make(map[string]map[string]repositorymodels.StoredProcedure)
|
r.storeState.StoredProcedures[database] = make(map[string]map[string]datastore.StoredProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.UserDefinedFunctions[database] == nil {
|
if r.storeState.UserDefinedFunctions[database] == nil {
|
||||||
r.storeState.UserDefinedFunctions[database] = make(map[string]map[string]repositorymodels.UserDefinedFunction)
|
r.storeState.UserDefinedFunctions[database] = make(map[string]map[string]datastore.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]datastore.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
for document := range r.storeState.Documents[database][collection] {
|
for document := range r.storeState.Documents[database][collection] {
|
||||||
@ -191,15 +221,15 @@ func (r *DataRepository) ensureStoreStateNoNullReferences() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.Triggers[database][collection] == nil {
|
if r.storeState.Triggers[database][collection] == nil {
|
||||||
r.storeState.Triggers[database][collection] = make(map[string]repositorymodels.Trigger)
|
r.storeState.Triggers[database][collection] = make(map[string]datastore.Trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.StoredProcedures[database][collection] == nil {
|
if r.storeState.StoredProcedures[database][collection] == nil {
|
||||||
r.storeState.StoredProcedures[database][collection] = make(map[string]repositorymodels.StoredProcedure)
|
r.storeState.StoredProcedures[database][collection] = make(map[string]datastore.StoredProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.storeState.UserDefinedFunctions[database][collection] == nil {
|
if r.storeState.UserDefinedFunctions[database][collection] == nil {
|
||||||
r.storeState.UserDefinedFunctions[database][collection] = make(map[string]repositorymodels.UserDefinedFunction)
|
r.storeState.UserDefinedFunctions[database][collection] = make(map[string]datastore.UserDefinedFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
91
internal/datastore/map_datastore/stored_procedures.go
Normal file
91
internal/datastore/map_datastore/stored_procedures.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package mapdatastore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetAllStoredProcedures(databaseId string, collectionId string) ([]datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.StoredProcedures[databaseId][collectionId]), datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetStoredProcedure(databaseId string, collectionId string, spId string) (datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; ok {
|
||||||
|
return sp, datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) DeleteStoredProcedure(databaseId string, collectionId string, spId string) datastore.DataStoreStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.StoredProcedures[databaseId][collectionId], spId)
|
||||||
|
|
||||||
|
return datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) CreateStoredProcedure(databaseId string, collectionId string, sp datastore.StoredProcedure) (datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var database datastore.Database
|
||||||
|
var collection datastore.Collection
|
||||||
|
if sp.ID == "" {
|
||||||
|
return datastore.StoredProcedure{}, datastore.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok = r.storeState.StoredProcedures[databaseId][collectionId][sp.ID]; ok {
|
||||||
|
return datastore.StoredProcedure{}, datastore.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.TimeStamp = time.Now().Unix()
|
||||||
|
sp.ResourceID = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeStoredProcedure))
|
||||||
|
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, datastore.StatusOk
|
||||||
|
}
|
@ -1,83 +1,83 @@
|
|||||||
package repositories
|
package mapdatastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *DataRepository) GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetAllTriggers(databaseId string, collectionId string) ([]datastore.Trigger, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
return maps.Values(r.storeState.Triggers[databaseId][collectionId]), repositorymodels.StatusOk
|
return maps.Values(r.storeState.Triggers[databaseId][collectionId]), datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) GetTrigger(databaseId string, collectionId string, triggerId string) (repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) GetTrigger(databaseId string, collectionId string, triggerId string) (datastore.Trigger, datastore.DataStoreStatus) {
|
||||||
r.storeState.RLock()
|
r.storeState.RLock()
|
||||||
defer r.storeState.RUnlock()
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
return datastore.Trigger{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
return datastore.Trigger{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if trigger, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; ok {
|
if trigger, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; ok {
|
||||||
return trigger, repositorymodels.StatusOk
|
return trigger, datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
return datastore.Trigger{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) DeleteTrigger(databaseId string, collectionId string, triggerId string) repositorymodels.RepositoryStatus {
|
func (r *MapDataStore) DeleteTrigger(databaseId string, collectionId string, triggerId string) datastore.DataStoreStatus {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; !ok {
|
if _, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; !ok {
|
||||||
return repositorymodels.StatusNotFound
|
return datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(r.storeState.Triggers[databaseId][collectionId], triggerId)
|
delete(r.storeState.Triggers[databaseId][collectionId], triggerId)
|
||||||
|
|
||||||
return repositorymodels.StatusOk
|
return datastore.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DataRepository) CreateTrigger(databaseId string, collectionId string, trigger repositorymodels.Trigger) (repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
|
func (r *MapDataStore) CreateTrigger(databaseId string, collectionId string, trigger datastore.Trigger) (datastore.Trigger, datastore.DataStoreStatus) {
|
||||||
r.storeState.Lock()
|
r.storeState.Lock()
|
||||||
defer r.storeState.Unlock()
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
var database repositorymodels.Database
|
var database datastore.Database
|
||||||
var collection repositorymodels.Collection
|
var collection datastore.Collection
|
||||||
if trigger.ID == "" {
|
if trigger.ID == "" {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.BadRequest
|
return datastore.Trigger{}, datastore.BadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
return datastore.Trigger{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.StatusNotFound
|
return datastore.Trigger{}, datastore.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok = r.storeState.Triggers[databaseId][collectionId][trigger.ID]; ok {
|
if _, ok = r.storeState.Triggers[databaseId][collectionId][trigger.ID]; ok {
|
||||||
return repositorymodels.Trigger{}, repositorymodels.Conflict
|
return datastore.Trigger{}, datastore.Conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger.TimeStamp = time.Now().Unix()
|
trigger.TimeStamp = time.Now().Unix()
|
||||||
@ -87,5 +87,5 @@ func (r *DataRepository) CreateTrigger(databaseId string, collectionId string, t
|
|||||||
|
|
||||||
r.storeState.Triggers[databaseId][collectionId][trigger.ID] = trigger
|
r.storeState.Triggers[databaseId][collectionId][trigger.ID] = trigger
|
||||||
|
|
||||||
return trigger, repositorymodels.StatusOk
|
return trigger, datastore.StatusOk
|
||||||
}
|
}
|
91
internal/datastore/map_datastore/user_defined_functions.go
Normal file
91
internal/datastore/map_datastore/user_defined_functions.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package mapdatastore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
|
"github.com/pikami/cosmium/internal/resourceid"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
return maps.Values(r.storeState.UserDefinedFunctions[databaseId][collectionId]), datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) GetUserDefinedFunction(databaseId string, collectionId string, udfId string) (datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.RLock()
|
||||||
|
defer r.storeState.RUnlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if udf, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; ok {
|
||||||
|
return udf, datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) DeleteUserDefinedFunction(databaseId string, collectionId string, udfId string) datastore.DataStoreStatus {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; !ok {
|
||||||
|
return datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(r.storeState.UserDefinedFunctions[databaseId][collectionId], udfId)
|
||||||
|
|
||||||
|
return datastore.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MapDataStore) CreateUserDefinedFunction(databaseId string, collectionId string, udf datastore.UserDefinedFunction) (datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||||
|
r.storeState.Lock()
|
||||||
|
defer r.storeState.Unlock()
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var database datastore.Database
|
||||||
|
var collection datastore.Collection
|
||||||
|
if udf.ID == "" {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udf.ID]; ok {
|
||||||
|
return datastore.UserDefinedFunction{}, datastore.Conflict
|
||||||
|
}
|
||||||
|
|
||||||
|
udf.TimeStamp = time.Now().Unix()
|
||||||
|
udf.ResourceID = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeUserDefinedFunction))
|
||||||
|
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, datastore.StatusOk
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
package repositorymodels
|
package datastore
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
@ -10,7 +8,7 @@ type Database struct {
|
|||||||
Self string `json:"_self"`
|
Self string `json:"_self"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepositoryStatus int
|
type DataStoreStatus int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusOk = 1
|
StatusOk = 1
|
||||||
@ -117,25 +115,3 @@ type PartitionKeyRange struct {
|
|||||||
TimeStamp int64 `json:"_ts"`
|
TimeStamp int64 `json:"_ts"`
|
||||||
Lsn int `json:"lsn"`
|
Lsn int `json:"lsn"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
|
||||||
sync.RWMutex
|
|
||||||
|
|
||||||
// Map databaseId -> Database
|
|
||||||
Databases map[string]Database `json:"databases"`
|
|
||||||
|
|
||||||
// Map databaseId -> collectionId -> Collection
|
|
||||||
Collections map[string]map[string]Collection `json:"collections"`
|
|
||||||
|
|
||||||
// Map databaseId -> collectionId -> documentId -> Documents
|
|
||||||
Documents map[string]map[string]map[string]Document `json:"documents"`
|
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
package repositories
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
|
||||||
"github.com/pikami/cosmium/internal/resourceid"
|
|
||||||
"github.com/pikami/cosmium/parsers"
|
|
||||||
"github.com/pikami/cosmium/parsers/nosql"
|
|
||||||
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *DataRepository) GetAllDocuments(databaseId string, collectionId string) ([]repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
|
||||||
r.storeState.RLock()
|
|
||||||
defer r.storeState.RUnlock()
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
|
||||||
return make([]repositorymodels.Document, 0), repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
|
||||||
return make([]repositorymodels.Document, 0), repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return maps.Values(r.storeState.Documents[databaseId][collectionId]), repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DataRepository) GetDocument(databaseId string, collectionId string, documentId string) (repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
|
||||||
r.storeState.RLock()
|
|
||||||
defer r.storeState.RUnlock()
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.storeState.Documents[databaseId][collectionId][documentId], repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DataRepository) DeleteDocument(databaseId string, collectionId string, documentId 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.Documents[databaseId][collectionId][documentId]; !ok {
|
|
||||||
return repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(r.storeState.Documents[databaseId][collectionId], documentId)
|
|
||||||
|
|
||||||
return repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DataRepository) CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (repositorymodels.Document, repositorymodels.RepositoryStatus) {
|
|
||||||
r.storeState.Lock()
|
|
||||||
defer r.storeState.Unlock()
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
var documentId string
|
|
||||||
var database repositorymodels.Database
|
|
||||||
var collection repositorymodels.Collection
|
|
||||||
if documentId, ok = document["id"].(string); !ok || documentId == "" {
|
|
||||||
documentId = fmt.Sprint(uuid.New())
|
|
||||||
document["id"] = documentId
|
|
||||||
}
|
|
||||||
|
|
||||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.StatusNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; ok {
|
|
||||||
return repositorymodels.Document{}, repositorymodels.Conflict
|
|
||||||
}
|
|
||||||
|
|
||||||
document["_ts"] = time.Now().Unix()
|
|
||||||
document["_rid"] = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeDocument))
|
|
||||||
document["_etag"] = fmt.Sprintf("\"%s\"", uuid.New())
|
|
||||||
document["_self"] = fmt.Sprintf("dbs/%s/colls/%s/docs/%s/", database.ResourceID, collection.ResourceID, document["_rid"])
|
|
||||||
|
|
||||||
r.storeState.Documents[databaseId][collectionId][documentId] = document
|
|
||||||
|
|
||||||
return document, repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DataRepository) ExecuteQueryDocuments(databaseId string, collectionId string, query string, queryParameters map[string]interface{}) ([]memoryexecutor.RowType, repositorymodels.RepositoryStatus) {
|
|
||||||
parsedQuery, err := nosql.Parse("", []byte(query))
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to parse query: %s\nerr: %v", query, err)
|
|
||||||
return nil, repositorymodels.BadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
collectionDocuments, status := r.GetAllDocuments(databaseId, collectionId)
|
|
||||||
if status != repositorymodels.StatusOk {
|
|
||||||
return nil, status
|
|
||||||
}
|
|
||||||
|
|
||||||
covDocs := make([]memoryexecutor.RowType, 0)
|
|
||||||
for _, doc := range collectionDocuments {
|
|
||||||
covDocs = append(covDocs, map[string]interface{}(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
if typedQuery, ok := parsedQuery.(parsers.SelectStmt); ok {
|
|
||||||
typedQuery.Parameters = queryParameters
|
|
||||||
return memoryexecutor.ExecuteQuery(typedQuery, covDocs), repositorymodels.StatusOk
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, repositorymodels.BadRequest
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package repositories
|
|
||||||
|
|
||||||
import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
|
||||||
|
|
||||||
type DataRepository struct {
|
|
||||||
storeState repositorymodels.State
|
|
||||||
|
|
||||||
initialDataFilePath string
|
|
||||||
persistDataFilePath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryOptions struct {
|
|
||||||
InitialDataFilePath string
|
|
||||||
PersistDataFilePath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDataRepository(options RepositoryOptions) *DataRepository {
|
|
||||||
repository := &DataRepository{
|
|
||||||
storeState: repositorymodels.State{
|
|
||||||
Databases: make(map[string]repositorymodels.Database),
|
|
||||||
Collections: make(map[string]map[string]repositorymodels.Collection),
|
|
||||||
Documents: make(map[string]map[string]map[string]repositorymodels.Document),
|
|
||||||
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,
|
|
||||||
persistDataFilePath: options.PersistDataFilePath,
|
|
||||||
}
|
|
||||||
|
|
||||||
repository.InitializeRepository()
|
|
||||||
|
|
||||||
return repository
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package repositories
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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(collection.ResourceID, resourceid.New(resourceid.ResourceTypeStoredProcedure))
|
|
||||||
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,91 +0,0 @@
|
|||||||
package repositories
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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(collection.ResourceID, resourceid.New(resourceid.ResourceTypeUserDefinedFunction))
|
|
||||||
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
|
|
||||||
}
|
|
@ -1,21 +1,19 @@
|
|||||||
package structhidrators
|
package structhidrators
|
||||||
|
|
||||||
import (
|
import "github.com/pikami/cosmium/internal/datastore"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
|
||||||
)
|
|
||||||
|
|
||||||
var defaultCollection repositorymodels.Collection = repositorymodels.Collection{
|
var defaultCollection datastore.Collection = datastore.Collection{
|
||||||
IndexingPolicy: repositorymodels.CollectionIndexingPolicy{
|
IndexingPolicy: datastore.CollectionIndexingPolicy{
|
||||||
IndexingMode: "consistent",
|
IndexingMode: "consistent",
|
||||||
Automatic: true,
|
Automatic: true,
|
||||||
IncludedPaths: []repositorymodels.CollectionIndexingPolicyPath{
|
IncludedPaths: []datastore.CollectionIndexingPolicyPath{
|
||||||
{Path: "/*"},
|
{Path: "/*"},
|
||||||
},
|
},
|
||||||
ExcludedPaths: []repositorymodels.CollectionIndexingPolicyPath{
|
ExcludedPaths: []datastore.CollectionIndexingPolicyPath{
|
||||||
{Path: "/\"_etag\"/?"},
|
{Path: "/\"_etag\"/?"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PartitionKey: repositorymodels.CollectionPartitionKey{
|
PartitionKey: datastore.CollectionPartitionKey{
|
||||||
Paths: []string{"/_partitionKey"},
|
Paths: []string{"/_partitionKey"},
|
||||||
Kind: "Hash",
|
Kind: "Hash",
|
||||||
Version: 2,
|
Version: 2,
|
||||||
|
@ -3,11 +3,11 @@ package structhidrators
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Hidrate(input interface{}) interface{} {
|
func Hidrate(input interface{}) interface{} {
|
||||||
if reflect.TypeOf(input) == reflect.TypeOf(repositorymodels.Collection{}) {
|
if reflect.TypeOf(input) == reflect.TypeOf(datastore.Collection{}) {
|
||||||
return hidrate(input, defaultCollection)
|
return hidrate(input, defaultCollection)
|
||||||
}
|
}
|
||||||
return input
|
return input
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export CreateCollection
|
//export CreateCollection
|
||||||
@ -20,15 +20,15 @@ func CreateCollection(serverName *C.char, databaseId *C.char, collectionJson *C.
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var collection repositorymodels.Collection
|
var collection datastore.Collection
|
||||||
err := json.NewDecoder(strings.NewReader(collectionStr)).Decode(&collection)
|
err := json.NewDecoder(strings.NewReader(collectionStr)).Decode(&collection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ResponseFailedToParseRequest
|
return ResponseFailedToParseRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
_, code := serverInstance.repository.CreateCollection(databaseIdStr, collection)
|
_, code := serverInstance.dataStore.CreateCollection(databaseIdStr, collection)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export GetCollection
|
//export GetCollection
|
||||||
@ -43,8 +43,8 @@ func GetCollection(serverName *C.char, databaseId *C.char, collectionId *C.char)
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
collection, code := serverInstance.repository.GetCollection(databaseIdStr, collectionIdStr)
|
collection, code := serverInstance.dataStore.GetCollection(databaseIdStr, collectionIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,8 +66,8 @@ func GetAllCollections(serverName *C.char, databaseId *C.char) *C.char {
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
collections, code := serverInstance.repository.GetAllCollections(databaseIdStr)
|
collections, code := serverInstance.dataStore.GetAllCollections(databaseIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ func DeleteCollection(serverName *C.char, databaseId *C.char, collectionId *C.ch
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
code := serverInstance.repository.DeleteCollection(databaseIdStr, collectionIdStr)
|
code := serverInstance.dataStore.DeleteCollection(databaseIdStr, collectionIdStr)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export CreateDatabase
|
//export CreateDatabase
|
||||||
@ -19,15 +19,15 @@ func CreateDatabase(serverName *C.char, databaseJson *C.char) int {
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var database repositorymodels.Database
|
var database datastore.Database
|
||||||
err := json.NewDecoder(strings.NewReader(databaseStr)).Decode(&database)
|
err := json.NewDecoder(strings.NewReader(databaseStr)).Decode(&database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ResponseFailedToParseRequest
|
return ResponseFailedToParseRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
_, code := serverInstance.repository.CreateDatabase(database)
|
_, code := serverInstance.dataStore.CreateDatabase(database)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export GetDatabase
|
//export GetDatabase
|
||||||
@ -41,8 +41,8 @@ func GetDatabase(serverName *C.char, databaseId *C.char) *C.char {
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
database, code := serverInstance.repository.GetDatabase(databaseIdStr)
|
database, code := serverInstance.dataStore.GetDatabase(databaseIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +63,8 @@ func GetAllDatabases(serverName *C.char) *C.char {
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
databases, code := serverInstance.repository.GetAllDatabases()
|
databases, code := serverInstance.dataStore.GetAllDatabases()
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ func DeleteDatabase(serverName *C.char, databaseId *C.char) int {
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
code := serverInstance.repository.DeleteDatabase(databaseIdStr)
|
code := serverInstance.dataStore.DeleteDatabase(databaseIdStr)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export CreateDocument
|
//export CreateDocument
|
||||||
@ -21,15 +21,15 @@ func CreateDocument(serverName *C.char, databaseId *C.char, collectionId *C.char
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var document repositorymodels.Document
|
var document datastore.Document
|
||||||
err := json.NewDecoder(strings.NewReader(documentStr)).Decode(&document)
|
err := json.NewDecoder(strings.NewReader(documentStr)).Decode(&document)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ResponseFailedToParseRequest
|
return ResponseFailedToParseRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
_, code := serverInstance.repository.CreateDocument(databaseIdStr, collectionIdStr, document)
|
_, code := serverInstance.dataStore.CreateDocument(databaseIdStr, collectionIdStr, document)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export GetDocument
|
//export GetDocument
|
||||||
@ -45,8 +45,8 @@ func GetDocument(serverName *C.char, databaseId *C.char, collectionId *C.char, d
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
document, code := serverInstance.repository.GetDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
document, code := serverInstance.dataStore.GetDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,8 +69,8 @@ func GetAllDocuments(serverName *C.char, databaseId *C.char, collectionId *C.cha
|
|||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
documents, code := serverInstance.repository.GetAllDocuments(databaseIdStr, collectionIdStr)
|
documents, code := serverInstance.dataStore.GetAllDocuments(databaseIdStr, collectionIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,19 +95,19 @@ func UpdateDocument(serverName *C.char, databaseId *C.char, collectionId *C.char
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var document repositorymodels.Document
|
var document datastore.Document
|
||||||
err := json.Unmarshal([]byte(documentStr), &document)
|
err := json.Unmarshal([]byte(documentStr), &document)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ResponseFailedToParseRequest
|
return ResponseFailedToParseRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
code := serverInstance.repository.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
code := serverInstance.dataStore.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
||||||
if code != repositorymodels.StatusOk {
|
if code != datastore.StatusOk {
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, code = serverInstance.repository.CreateDocument(databaseIdStr, collectionIdStr, document)
|
_, code = serverInstance.dataStore.CreateDocument(databaseIdStr, collectionIdStr, document)
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export DeleteDocument
|
//export DeleteDocument
|
||||||
@ -123,7 +123,7 @@ func DeleteDocument(serverName *C.char, databaseId *C.char, collectionId *C.char
|
|||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
code := serverInstance.repository.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
code := serverInstance.dataStore.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
|
||||||
|
|
||||||
return repositoryStatusToResponseCode(code)
|
return dataStoreStatusToResponseCode(code)
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,12 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pikami/cosmium/api"
|
"github.com/pikami/cosmium/api"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
"github.com/pikami/cosmium/internal/datastore"
|
||||||
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerInstance struct {
|
type ServerInstance struct {
|
||||||
server *api.ApiServer
|
server *api.ApiServer
|
||||||
repository *repositories.DataRepository
|
dataStore datastore.DataStore
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -21,17 +20,18 @@ var (
|
|||||||
const (
|
const (
|
||||||
ResponseSuccess = 0
|
ResponseSuccess = 0
|
||||||
|
|
||||||
ResponseUnknown = 100
|
ResponseUnknown = 100
|
||||||
ResponseFailedToParseConfiguration = 101
|
ResponseFailedToParseConfiguration = 101
|
||||||
ResponseFailedToLoadState = 102
|
ResponseFailedToLoadState = 102
|
||||||
ResponseFailedToParseRequest = 103
|
ResponseFailedToParseRequest = 103
|
||||||
ResponseServerInstanceAlreadyExists = 104
|
ResponseServerInstanceAlreadyExists = 104
|
||||||
ResponseServerInstanceNotFound = 105
|
ResponseServerInstanceNotFound = 105
|
||||||
ResponseFailedToStartServer = 106
|
ResponseFailedToStartServer = 106
|
||||||
|
ResponseCurentDataStoreDoesNotSupportStateLoading = 107
|
||||||
|
|
||||||
ResponseRepositoryNotFound = 200
|
ResponseDataStoreNotFound = 200
|
||||||
ResponseRepositoryConflict = 201
|
ResponseDataStoreConflict = 201
|
||||||
ResponseRepositoryBadRequest = 202
|
ResponseDataStoreBadRequest = 202
|
||||||
)
|
)
|
||||||
|
|
||||||
func getInstance(serverName string) (*ServerInstance, bool) {
|
func getInstance(serverName string) (*ServerInstance, bool) {
|
||||||
@ -61,16 +61,16 @@ func removeInstance(serverName string) {
|
|||||||
delete(serverInstances, serverName)
|
delete(serverInstances, serverName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func repositoryStatusToResponseCode(status repositorymodels.RepositoryStatus) int {
|
func dataStoreStatusToResponseCode(status datastore.DataStoreStatus) int {
|
||||||
switch status {
|
switch status {
|
||||||
case repositorymodels.StatusOk:
|
case datastore.StatusOk:
|
||||||
return ResponseSuccess
|
return ResponseSuccess
|
||||||
case repositorymodels.StatusNotFound:
|
case datastore.StatusNotFound:
|
||||||
return ResponseRepositoryNotFound
|
return ResponseDataStoreNotFound
|
||||||
case repositorymodels.Conflict:
|
case datastore.Conflict:
|
||||||
return ResponseRepositoryConflict
|
return ResponseDataStoreConflict
|
||||||
case repositorymodels.BadRequest:
|
case datastore.BadRequest:
|
||||||
return ResponseRepositoryBadRequest
|
return ResponseDataStoreBadRequest
|
||||||
default:
|
default:
|
||||||
return ResponseUnknown
|
return ResponseUnknown
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pikami/cosmium/api"
|
"github.com/pikami/cosmium/api"
|
||||||
"github.com/pikami/cosmium/api/config"
|
"github.com/pikami/cosmium/api/config"
|
||||||
"github.com/pikami/cosmium/internal/repositories"
|
mapdatastore "github.com/pikami/cosmium/internal/datastore/map_datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export CreateServerInstance
|
//export CreateServerInstance
|
||||||
@ -32,20 +32,20 @@ func CreateServerInstance(serverName *C.char, configurationJSON *C.char) int {
|
|||||||
configuration.ApplyDefaultsToEmptyFields()
|
configuration.ApplyDefaultsToEmptyFields()
|
||||||
configuration.PopulateCalculatedFields()
|
configuration.PopulateCalculatedFields()
|
||||||
|
|
||||||
repository := repositories.NewDataRepository(repositories.RepositoryOptions{
|
dataStore := mapdatastore.NewMapDataStore(mapdatastore.MapDataStoreOptions{
|
||||||
InitialDataFilePath: configuration.InitialDataFilePath,
|
InitialDataFilePath: configuration.InitialDataFilePath,
|
||||||
PersistDataFilePath: configuration.PersistDataFilePath,
|
PersistDataFilePath: configuration.PersistDataFilePath,
|
||||||
})
|
})
|
||||||
|
|
||||||
server := api.NewApiServer(repository, &configuration)
|
server := api.NewApiServer(dataStore, &configuration)
|
||||||
err = server.Start()
|
err = server.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ResponseFailedToStartServer
|
return ResponseFailedToStartServer
|
||||||
}
|
}
|
||||||
|
|
||||||
addInstance(serverNameStr, &ServerInstance{
|
addInstance(serverNameStr, &ServerInstance{
|
||||||
server: server,
|
server: server,
|
||||||
repository: repository,
|
dataStore: dataStore,
|
||||||
})
|
})
|
||||||
|
|
||||||
return ResponseSuccess
|
return ResponseSuccess
|
||||||
@ -69,7 +69,7 @@ func GetServerInstanceState(serverName *C.char) *C.char {
|
|||||||
serverNameStr := C.GoString(serverName)
|
serverNameStr := C.GoString(serverName)
|
||||||
|
|
||||||
if serverInstance, ok := getInstance(serverNameStr); ok {
|
if serverInstance, ok := getInstance(serverNameStr); ok {
|
||||||
stateJSON, err := serverInstance.repository.GetState()
|
stateJSON, err := serverInstance.dataStore.DumpToJson()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -85,11 +85,14 @@ func LoadServerInstanceState(serverName *C.char, stateJSON *C.char) int {
|
|||||||
stateJSONStr := C.GoString(stateJSON)
|
stateJSONStr := C.GoString(stateJSON)
|
||||||
|
|
||||||
if serverInstance, ok := getInstance(serverNameStr); ok {
|
if serverInstance, ok := getInstance(serverNameStr); ok {
|
||||||
err := serverInstance.repository.LoadStateJSON(stateJSONStr)
|
if mapDS, ok := serverInstance.dataStore.(*mapdatastore.MapDataStore); ok {
|
||||||
if err != nil {
|
err := mapDS.LoadStateJSON(stateJSONStr)
|
||||||
return ResponseFailedToLoadState
|
if err != nil {
|
||||||
|
return ResponseFailedToLoadState
|
||||||
|
}
|
||||||
|
return ResponseSuccess
|
||||||
}
|
}
|
||||||
return ResponseSuccess
|
return ResponseCurentDataStoreDoesNotSupportStateLoading
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponseServerInstanceNotFound
|
return ResponseServerInstanceNotFound
|
||||||
|
Loading…
x
Reference in New Issue
Block a user