diff --git a/api/handlers/collections.go b/api/handlers/collections.go index b250296..d3fc05f 100644 --- a/api/handlers/collections.go +++ b/api/handlers/collections.go @@ -5,13 +5,14 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllCollections(c *gin.Context) { databaseId := c.Param("databaseId") collections, status := repositories.GetAllCollections(databaseId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "DocumentCollections": collections, "_count": len(collections)}) return } @@ -24,12 +25,12 @@ func GetCollection(c *gin.Context) { id := c.Param("collId") collection, status := repositories.GetCollection(databaseId, id) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, collection) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -42,12 +43,12 @@ func DeleteCollection(c *gin.Context) { id := c.Param("collId") status := repositories.DeleteCollection(databaseId, id) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.Status(http.StatusNoContent) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -57,7 +58,7 @@ func DeleteCollection(c *gin.Context) { func CreateCollection(c *gin.Context) { databaseId := c.Param("databaseId") - var newCollection repositories.Collection + var newCollection repositorymodels.Collection if err := c.BindJSON(&newCollection); err != nil { c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()}) @@ -69,14 +70,14 @@ func CreateCollection(c *gin.Context) { return } - status := repositories.CreateCollection(databaseId, newCollection) - if status == repositories.Conflict { + createdCollection, status := repositories.CreateCollection(databaseId, newCollection) + if status == repositorymodels.Conflict { c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) return } - if status == repositories.StatusOk { - c.IndentedJSON(http.StatusCreated, newCollection) + if status == repositorymodels.StatusOk { + c.IndentedJSON(http.StatusCreated, createdCollection) return } diff --git a/api/handlers/databases.go b/api/handlers/databases.go index 588fdbf..92f91ba 100644 --- a/api/handlers/databases.go +++ b/api/handlers/databases.go @@ -5,11 +5,12 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllDatabases(c *gin.Context) { databases, status := repositories.GetAllDatabases() - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Databases": databases, "_count": len(databases)}) return } @@ -21,12 +22,12 @@ func GetDatabase(c *gin.Context) { id := c.Param("databaseId") database, status := repositories.GetDatabase(id) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, database) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -38,12 +39,12 @@ func DeleteDatabase(c *gin.Context) { id := c.Param("databaseId") status := repositories.DeleteDatabase(id) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.Status(http.StatusNoContent) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -52,7 +53,7 @@ func DeleteDatabase(c *gin.Context) { } func CreateDatabase(c *gin.Context) { - var newDatabase repositories.Database + var newDatabase repositorymodels.Database if err := c.BindJSON(&newDatabase); err != nil { c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()}) @@ -65,12 +66,12 @@ func CreateDatabase(c *gin.Context) { } status := repositories.CreateDatabase(newDatabase) - if status == repositories.Conflict { + if status == repositorymodels.Conflict { c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) return } - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusCreated, newDatabase) return } diff --git a/api/handlers/documents.go b/api/handlers/documents.go index 4d7945e..09fab03 100644 --- a/api/handlers/documents.go +++ b/api/handlers/documents.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/constants" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllDocuments(c *gin.Context) { @@ -13,7 +14,7 @@ func GetAllDocuments(c *gin.Context) { collectionId := c.Param("collId") documents, status := repositories.GetAllDocuments(databaseId, collectionId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Documents": documents, "_count": len(documents)}) return } @@ -27,12 +28,12 @@ func GetDocument(c *gin.Context) { documentId := c.Param("docId") document, status := repositories.GetDocument(databaseId, collectionId, documentId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, document) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -46,12 +47,12 @@ func DeleteDocument(c *gin.Context) { documentId := c.Param("docId") status := repositories.DeleteDocument(databaseId, collectionId, documentId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.Status(http.StatusNoContent) return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } @@ -78,7 +79,7 @@ func DocumentsPost(c *gin.Context) { // TODO: Handle these {"query":"select c.id, c._self, c._rid, c._ts, [c[\"pk\"]] as _partitionKeyValue from c"} docs, status := repositories.ExecuteQueryDocuments(databaseId, collectionId, query.(string)) - if status != repositories.StatusOk { + if status != repositorymodels.StatusOk { // TODO: Currently we return everything if the query fails GetAllDocuments(c) return @@ -94,12 +95,12 @@ func DocumentsPost(c *gin.Context) { } status := repositories.CreateDocument(databaseId, collectionId, requestBody) - if status == repositories.Conflict { + if status == repositorymodels.Conflict { c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) return } - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusCreated, requestBody) return } diff --git a/api/handlers/middleware/loggers.go b/api/handlers/middleware/loggers.go new file mode 100644 index 0000000..14c7858 --- /dev/null +++ b/api/handlers/middleware/loggers.go @@ -0,0 +1,30 @@ +package middleware + +import ( + "bytes" + "fmt" + "io" + + "github.com/gin-gonic/gin" +) + +func RequestLogger() gin.HandlerFunc { + return func(c *gin.Context) { + buf, _ := io.ReadAll(c.Request.Body) + rdr1 := io.NopCloser(bytes.NewBuffer(buf)) + rdr2 := io.NopCloser(bytes.NewBuffer(buf)) + + fmt.Println(readBody(rdr1)) + + c.Request.Body = rdr2 + c.Next() + } +} + +func readBody(reader io.Reader) string { + buf := new(bytes.Buffer) + buf.ReadFrom(reader) + + s := buf.String() + return s +} diff --git a/api/handlers/partition_key_ranges.go b/api/handlers/partition_key_ranges.go index d22248d..cd186eb 100644 --- a/api/handlers/partition_key_ranges.go +++ b/api/handlers/partition_key_ranges.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetPartitionKeyRanges(c *gin.Context) { @@ -12,7 +13,7 @@ func GetPartitionKeyRanges(c *gin.Context) { collectionId := c.Param("collId") partitionKeyRanges, status := repositories.GetPartitionKeyRanges(databaseId, collectionId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{ "_rid": "", "_count": len(partitionKeyRanges), @@ -21,7 +22,7 @@ func GetPartitionKeyRanges(c *gin.Context) { return } - if status == repositories.StatusNotFound { + if status == repositorymodels.StatusNotFound { c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) return } diff --git a/api/handlers/stored_procedures.go b/api/handlers/stored_procedures.go index 8aacf4a..b338bab 100644 --- a/api/handlers/stored_procedures.go +++ b/api/handlers/stored_procedures.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllStoredProcedures(c *gin.Context) { @@ -13,7 +14,7 @@ func GetAllStoredProcedures(c *gin.Context) { sps, status := repositories.GetAllStoredProcedures(databaseId, collectionId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "StoredProcedures": sps, "_count": len(sps)}) return } diff --git a/api/handlers/triggers.go b/api/handlers/triggers.go index 86c5914..42b3eaf 100644 --- a/api/handlers/triggers.go +++ b/api/handlers/triggers.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllTriggers(c *gin.Context) { @@ -13,7 +14,7 @@ func GetAllTriggers(c *gin.Context) { triggers, status := repositories.GetAllTriggers(databaseId, collectionId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Triggers": triggers, "_count": len(triggers)}) return } diff --git a/api/handlers/user_defined_functions.go b/api/handlers/user_defined_functions.go index deed399..880d765 100644 --- a/api/handlers/user_defined_functions.go +++ b/api/handlers/user_defined_functions.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) func GetAllUserDefinedFunctions(c *gin.Context) { @@ -13,7 +14,7 @@ func GetAllUserDefinedFunctions(c *gin.Context) { udfs, status := repositories.GetAllUserDefinedFunctions(databaseId, collectionId) - if status == repositories.StatusOk { + if status == repositorymodels.StatusOk { c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "UserDefinedFunctions": udfs, "_count": len(udfs)}) return } diff --git a/api/router.go b/api/router.go index 76fa31f..14ab16c 100644 --- a/api/router.go +++ b/api/router.go @@ -3,11 +3,14 @@ package api import ( "github.com/gin-gonic/gin" "github.com/pikami/cosmium/api/handlers" + "github.com/pikami/cosmium/api/handlers/middleware" ) func CreateRouter() *gin.Engine { router := gin.Default() + router.Use(middleware.RequestLogger()) + router.GET("/dbs/:databaseId/colls/:collId/pkranges", handlers.GetPartitionKeyRanges) router.POST("/dbs/:databaseId/colls/:collId/docs", handlers.DocumentsPost) diff --git a/api/tests/collections_test.go b/api/tests/collections_test.go index 2805a39..01632f9 100644 --- a/api/tests/collections_test.go +++ b/api/tests/collections_test.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" "github.com/stretchr/testify/assert" ) @@ -37,7 +38,7 @@ func Test_Collections(t *testing.T) { }) t.Run("Should return conflict when collection exists", func(t *testing.T) { - repositories.CreateCollection(testDatabaseName, repositories.Collection{ + repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{ ID: testCollectionName, }) @@ -57,7 +58,7 @@ func Test_Collections(t *testing.T) { t.Run("Collection Read", func(t *testing.T) { t.Run("Should read collection", func(t *testing.T) { - repositories.CreateCollection(testDatabaseName, repositories.Collection{ + repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{ ID: testCollectionName, }) @@ -90,7 +91,7 @@ func Test_Collections(t *testing.T) { t.Run("Collection Delete", func(t *testing.T) { t.Run("Should delete collection", func(t *testing.T) { - repositories.CreateCollection(testDatabaseName, repositories.Collection{ + repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{ ID: testCollectionName, }) diff --git a/api/tests/databases_test.go b/api/tests/databases_test.go index 996ed54..0512a9a 100644 --- a/api/tests/databases_test.go +++ b/api/tests/databases_test.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" "github.com/stretchr/testify/assert" ) @@ -34,7 +35,7 @@ func Test_Databases(t *testing.T) { }) t.Run("Should return conflict when database exists", func(t *testing.T) { - repositories.CreateDatabase(repositories.Database{ + repositories.CreateDatabase(repositorymodels.Database{ ID: testDatabaseName, }) @@ -54,7 +55,7 @@ func Test_Databases(t *testing.T) { t.Run("Database Read", func(t *testing.T) { t.Run("Should read database", func(t *testing.T) { - repositories.CreateDatabase(repositories.Database{ + repositories.CreateDatabase(repositorymodels.Database{ ID: testDatabaseName, }) @@ -87,7 +88,7 @@ func Test_Databases(t *testing.T) { t.Run("Database Delete", func(t *testing.T) { t.Run("Should delete database", func(t *testing.T) { - repositories.CreateDatabase(repositories.Database{ + repositories.CreateDatabase(repositorymodels.Database{ ID: testDatabaseName, }) diff --git a/api/tests/documents_test.go b/api/tests/documents_test.go index aed270c..e23b3ea 100644 --- a/api/tests/documents_test.go +++ b/api/tests/documents_test.go @@ -9,6 +9,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/pikami/cosmium/internal/repositories" + repositorymodels "github.com/pikami/cosmium/internal/repository_models" "github.com/stretchr/testify/assert" ) @@ -41,7 +42,7 @@ func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, q } func Test_Documents(t *testing.T) { - repositories.CreateCollection(testDatabaseName, repositories.Collection{ + repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{ ID: testCollectionName, PartitionKey: struct { Paths []string "json:\"paths\"" diff --git a/internal/repositories/collections.go b/internal/repositories/collections.go index 5b9df3e..2edd484 100644 --- a/internal/repositories/collections.go +++ b/internal/repositories/collections.go @@ -1,53 +1,60 @@ package repositories -var collections = []Collection{ +import ( + repositorymodels "github.com/pikami/cosmium/internal/repository_models" + structhidrators "github.com/pikami/cosmium/internal/struct_hidrators" +) + +var collections = []repositorymodels.Collection{ {ID: "db1"}, {ID: "db2"}, } -func GetAllCollections(databaseId string) ([]Collection, RepositoryStatus) { - dbCollections := make([]Collection, 0) +func GetAllCollections(databaseId string) ([]repositorymodels.Collection, repositorymodels.RepositoryStatus) { + dbCollections := make([]repositorymodels.Collection, 0) for _, coll := range collections { - if coll.internals.databaseId == databaseId { + if coll.Internals.DatabaseId == databaseId { dbCollections = append(dbCollections, coll) } } - return dbCollections, StatusOk + return dbCollections, repositorymodels.StatusOk } -func GetCollection(databaseId string, id string) (Collection, RepositoryStatus) { +func GetCollection(databaseId string, id string) (repositorymodels.Collection, repositorymodels.RepositoryStatus) { for _, coll := range collections { - if coll.internals.databaseId == databaseId && coll.ID == id { - return coll, StatusOk + if coll.Internals.DatabaseId == databaseId && coll.ID == id { + return coll, repositorymodels.StatusOk } } - return Collection{}, StatusNotFound + return repositorymodels.Collection{}, repositorymodels.StatusNotFound } -func DeleteCollection(databaseId string, id string) RepositoryStatus { +func DeleteCollection(databaseId string, id string) repositorymodels.RepositoryStatus { for index, coll := range collections { - if coll.internals.databaseId == databaseId && coll.ID == id { + if coll.Internals.DatabaseId == databaseId && coll.ID == id { collections = append(collections[:index], collections[index+1:]...) - return StatusOk + return repositorymodels.StatusOk } } - return StatusNotFound + return repositorymodels.StatusNotFound } -func CreateCollection(databaseId string, newCollection Collection) RepositoryStatus { +func CreateCollection(databaseId string, newCollection repositorymodels.Collection) (repositorymodels.Collection, repositorymodels.RepositoryStatus) { for _, coll := range collections { - if coll.internals.databaseId == databaseId && coll.ID == newCollection.ID { - return Conflict + if coll.Internals.DatabaseId == databaseId && coll.ID == newCollection.ID { + return repositorymodels.Collection{}, repositorymodels.Conflict } } - newCollection.internals = struct{ databaseId string }{ - databaseId: databaseId, + newCollection = structhidrators.Hidrate(newCollection).(repositorymodels.Collection) + + newCollection.Internals = struct{ DatabaseId string }{ + DatabaseId: databaseId, } collections = append(collections, newCollection) - return StatusOk + return newCollection, repositorymodels.StatusOk } diff --git a/internal/repositories/databases.go b/internal/repositories/databases.go index ff6b79d..3a14aa1 100644 --- a/internal/repositories/databases.go +++ b/internal/repositories/databases.go @@ -1,42 +1,44 @@ package repositories -var databases = []Database{ +import repositorymodels "github.com/pikami/cosmium/internal/repository_models" + +var databases = []repositorymodels.Database{ {ID: "db1"}, {ID: "db2"}, } -func GetAllDatabases() ([]Database, RepositoryStatus) { - return databases, StatusOk +func GetAllDatabases() ([]repositorymodels.Database, repositorymodels.RepositoryStatus) { + return databases, repositorymodels.StatusOk } -func GetDatabase(id string) (Database, RepositoryStatus) { +func GetDatabase(id string) (repositorymodels.Database, repositorymodels.RepositoryStatus) { for _, db := range databases { if db.ID == id { - return db, StatusOk + return db, repositorymodels.StatusOk } } - return Database{}, StatusNotFound + return repositorymodels.Database{}, repositorymodels.StatusNotFound } -func DeleteDatabase(id string) RepositoryStatus { +func DeleteDatabase(id string) repositorymodels.RepositoryStatus { for index, db := range databases { if db.ID == id { databases = append(databases[:index], databases[index+1:]...) - return StatusOk + return repositorymodels.StatusOk } } - return StatusNotFound + return repositorymodels.StatusNotFound } -func CreateDatabase(newDatabase Database) RepositoryStatus { +func CreateDatabase(newDatabase repositorymodels.Database) repositorymodels.RepositoryStatus { for _, db := range databases { if db.ID == newDatabase.ID { - return Conflict + return repositorymodels.Conflict } } databases = append(databases, newDatabase) - return StatusOk + return repositorymodels.StatusOk } diff --git a/internal/repositories/documents.go b/internal/repositories/documents.go index 980f93a..79cb44f 100644 --- a/internal/repositories/documents.go +++ b/internal/repositories/documents.go @@ -4,15 +4,16 @@ import ( "log" "strings" + 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" ) -var documents = []Document{} +var documents = []repositorymodels.Document{} -func GetAllDocuments(databaseId string, collectionId string) ([]Document, RepositoryStatus) { - filteredDocuments := make([]Document, 0) +func GetAllDocuments(databaseId string, collectionId string) ([]repositorymodels.Document, repositorymodels.RepositoryStatus) { + filteredDocuments := make([]repositorymodels.Document, 0) for _, doc := range documents { docDbId := doc["_internal"].(map[string]interface{})["databaseId"] @@ -24,10 +25,10 @@ func GetAllDocuments(databaseId string, collectionId string) ([]Document, Reposi } } - return filteredDocuments, StatusOk + return filteredDocuments, repositorymodels.StatusOk } -func GetDocument(databaseId string, collectionId string, documentId string) (Document, RepositoryStatus) { +func GetDocument(databaseId string, collectionId string, documentId string) (repositorymodels.Document, repositorymodels.RepositoryStatus) { for _, doc := range documents { docDbId := doc["_internal"].(map[string]interface{})["databaseId"] docCollId := doc["_internal"].(map[string]interface{})["collectionId"] @@ -35,14 +36,14 @@ func GetDocument(databaseId string, collectionId string, documentId string) (Doc if docDbId == databaseId && docCollId == collectionId && docId == documentId { doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"] - return doc, StatusOk + return doc, repositorymodels.StatusOk } } - return Document{}, StatusNotFound + return repositorymodels.Document{}, repositorymodels.StatusNotFound } -func DeleteDocument(databaseId string, collectionId string, documentId string) RepositoryStatus { +func DeleteDocument(databaseId string, collectionId string, documentId string) repositorymodels.RepositoryStatus { for index, doc := range documents { docDbId := doc["_internal"].(map[string]interface{})["databaseId"] docCollId := doc["_internal"].(map[string]interface{})["collectionId"] @@ -50,21 +51,21 @@ func DeleteDocument(databaseId string, collectionId string, documentId string) R if docDbId == databaseId && docCollId == collectionId && docId == documentId { documents = append(documents[:index], documents[index+1:]...) - return StatusOk + return repositorymodels.StatusOk } } - return StatusNotFound + return repositorymodels.StatusNotFound } -func CreateDocument(databaseId string, collectionId string, document map[string]interface{}) RepositoryStatus { +func CreateDocument(databaseId string, collectionId string, document map[string]interface{}) repositorymodels.RepositoryStatus { if document["id"] == "" { - return BadRequest + return repositorymodels.BadRequest } collection, status := GetCollection(databaseId, collectionId) - if status != StatusOk { - return StatusNotFound + if status != repositorymodels.StatusOk { + return repositorymodels.StatusNotFound } for _, doc := range documents { @@ -73,7 +74,7 @@ func CreateDocument(databaseId string, collectionId string, document map[string] docId := doc["id"] if docDbId == databaseId && docCollId == collectionId && docId == document["id"] { - return Conflict + return repositorymodels.Conflict } } @@ -99,18 +100,18 @@ func CreateDocument(databaseId string, collectionId string, document map[string] } documents = append(documents, document) - return StatusOk + return repositorymodels.StatusOk } -func ExecuteQueryDocuments(databaseId string, collectionId string, query string) ([]memoryexecutor.RowType, RepositoryStatus) { +func ExecuteQueryDocuments(databaseId string, collectionId string, query string) ([]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, BadRequest + return nil, repositorymodels.BadRequest } collectionDocuments, status := GetAllDocuments(databaseId, collectionId) - if status != StatusOk { + if status != repositorymodels.StatusOk { return nil, status } @@ -119,5 +120,5 @@ func ExecuteQueryDocuments(databaseId string, collectionId string, query string) covDocs = append(covDocs, map[string]interface{}(doc)) } - return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), StatusOk + return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), repositorymodels.StatusOk } diff --git a/internal/repositories/models.go b/internal/repositories/models.go deleted file mode 100644 index e7dc73e..0000000 --- a/internal/repositories/models.go +++ /dev/null @@ -1,106 +0,0 @@ -package repositories - -type Database struct { - ID string `json:"id"` -} - -type RepositoryStatus int - -const ( - StatusOk = 1 - StatusNotFound = 2 - Conflict = 3 - BadRequest = 4 -) - -type Collection struct { - ID string `json:"id"` - IndexingPolicy struct { - IndexingMode string `json:"indexingMode"` - Automatic bool `json:"automatic"` - IncludedPaths []struct { - Path string `json:"path"` - Indexes []struct { - Kind string `json:"kind"` - DataType string `json:"dataType"` - Precision int `json:"precision"` - } `json:"indexes"` - } `json:"includedPaths"` - ExcludedPaths []any `json:"excludedPaths"` - } `json:"indexingPolicy"` - PartitionKey struct { - Paths []string `json:"paths"` - Kind string `json:"kind"` - Version int `json:"Version"` - } `json:"partitionKey"` - Rid string `json:"_rid"` - Ts int `json:"_ts"` - Self string `json:"_self"` - Etag string `json:"_etag"` - Docs string `json:"_docs"` - Sprocs string `json:"_sprocs"` - Triggers string `json:"_triggers"` - Udfs string `json:"_udfs"` - Conflicts string `json:"_conflicts"` - internals struct { - databaseId string - } -} - -type UserDefinedFunction struct { - Body string `json:"body"` - ID string `json:"id"` - Rid string `json:"_rid"` - Ts int `json:"_ts"` - Self string `json:"_self"` - Etag string `json:"_etag"` - internals struct { - databaseId string - collectionId string - } -} - -type StoredProcedure struct { - Body string `json:"body"` - ID string `json:"id"` - Rid string `json:"_rid"` - Ts int `json:"_ts"` - Self string `json:"_self"` - Etag string `json:"_etag"` - internals struct { - databaseId string - collectionId string - } -} - -type Trigger struct { - Body string `json:"body"` - ID string `json:"id"` - TriggerOperation string `json:"triggerOperation"` - TriggerType string `json:"triggerType"` - Rid string `json:"_rid"` - Ts int `json:"_ts"` - Self string `json:"_self"` - Etag string `json:"_etag"` - internals struct { - databaseId string - collectionId string - } -} - -type Document map[string]interface{} - -type PartitionKeyRange struct { - Rid string `json:"_rid"` - ID string `json:"id"` - Etag string `json:"_etag"` - MinInclusive string `json:"minInclusive"` - MaxExclusive string `json:"maxExclusive"` - RidPrefix int `json:"ridPrefix"` - Self string `json:"_self"` - ThroughputFraction int `json:"throughputFraction"` - Status string `json:"status"` - Parents []any `json:"parents"` - Ts int `json:"_ts"` - Lsn int `json:"lsn"` -} diff --git a/internal/repositories/partition_key_ranges.go b/internal/repositories/partition_key_ranges.go index c341bc7..73f0ac9 100644 --- a/internal/repositories/partition_key_ranges.go +++ b/internal/repositories/partition_key_ranges.go @@ -1,8 +1,10 @@ package repositories -func GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionKeyRange, RepositoryStatus) { +import repositorymodels "github.com/pikami/cosmium/internal/repository_models" + +func GetPartitionKeyRanges(databaseId string, collectionId string) ([]repositorymodels.PartitionKeyRange, repositorymodels.RepositoryStatus) { // I have no idea what this is tbh - return []PartitionKeyRange{ + return []repositorymodels.PartitionKeyRange{ { Rid: "ZxlyAP7rKwACAAAAAAAAUA==", ID: "0", @@ -17,5 +19,5 @@ func GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionK Ts: 1707431241, Lsn: 17, }, - }, StatusOk + }, repositorymodels.StatusOk } diff --git a/internal/repositories/stored_procedures.go b/internal/repositories/stored_procedures.go index 43bcf30..ad242f9 100644 --- a/internal/repositories/stored_procedures.go +++ b/internal/repositories/stored_procedures.go @@ -1,15 +1,17 @@ package repositories -var storedProcedures = []StoredProcedure{} +import repositorymodels "github.com/pikami/cosmium/internal/repository_models" -func GetAllStoredProcedures(databaseId string, collectionId string) ([]StoredProcedure, RepositoryStatus) { - sps := make([]StoredProcedure, 0) +var storedProcedures = []repositorymodels.StoredProcedure{} + +func GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) { + sps := make([]repositorymodels.StoredProcedure, 0) for _, coll := range storedProcedures { - if coll.internals.databaseId == databaseId && coll.internals.collectionId == collectionId { + if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId { sps = append(sps, coll) } } - return sps, StatusOk + return sps, repositorymodels.StatusOk } diff --git a/internal/repositories/triggers.go b/internal/repositories/triggers.go index 9d8d4ab..5e445d4 100644 --- a/internal/repositories/triggers.go +++ b/internal/repositories/triggers.go @@ -1,15 +1,17 @@ package repositories -var triggers = []Trigger{} +import repositorymodels "github.com/pikami/cosmium/internal/repository_models" -func GetAllTriggers(databaseId string, collectionId string) ([]Trigger, RepositoryStatus) { - filteredTriggers := make([]Trigger, 0) +var triggers = []repositorymodels.Trigger{} + +func GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) { + filteredTriggers := make([]repositorymodels.Trigger, 0) for _, coll := range triggers { - if coll.internals.databaseId == databaseId && coll.internals.collectionId == collectionId { + if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId { filteredTriggers = append(filteredTriggers, coll) } } - return filteredTriggers, StatusOk + return filteredTriggers, repositorymodels.StatusOk } diff --git a/internal/repositories/user_defined_functions.go b/internal/repositories/user_defined_functions.go index cf46e66..2dd2e17 100644 --- a/internal/repositories/user_defined_functions.go +++ b/internal/repositories/user_defined_functions.go @@ -1,15 +1,17 @@ package repositories -var userDefinedFunctions = []UserDefinedFunction{} +import repositorymodels "github.com/pikami/cosmium/internal/repository_models" -func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]UserDefinedFunction, RepositoryStatus) { - udfs := make([]UserDefinedFunction, 0) +var userDefinedFunctions = []repositorymodels.UserDefinedFunction{} + +func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) { + udfs := make([]repositorymodels.UserDefinedFunction, 0) for _, coll := range userDefinedFunctions { - if coll.internals.databaseId == databaseId && coll.internals.collectionId == collectionId { + if coll.Internals.DatabaseId == databaseId && coll.Internals.CollectionId == collectionId { udfs = append(udfs, coll) } } - return udfs, StatusOk + return udfs, repositorymodels.StatusOk } diff --git a/internal/repository_models/models.go b/internal/repository_models/models.go new file mode 100644 index 0000000..ac16270 --- /dev/null +++ b/internal/repository_models/models.go @@ -0,0 +1,112 @@ +package repositorymodels + +type Database struct { + ID string `json:"id"` +} + +type RepositoryStatus int + +const ( + StatusOk = 1 + StatusNotFound = 2 + Conflict = 3 + BadRequest = 4 +) + +type Collection struct { + ID string `json:"id"` + IndexingPolicy CollectionIndexingPolicy `json:"indexingPolicy"` + PartitionKey CollectionPartitionKey `json:"partitionKey"` + Rid string `json:"_rid"` + Ts int `json:"_ts"` + Self string `json:"_self"` + Etag string `json:"_etag"` + Docs string `json:"_docs"` + Sprocs string `json:"_sprocs"` + Triggers string `json:"_triggers"` + Udfs string `json:"_udfs"` + Conflicts string `json:"_conflicts"` + Internals struct { + DatabaseId string + } +} + +type CollectionIndexingPolicy struct { + IndexingMode string `json:"indexingMode"` + Automatic bool `json:"automatic"` + IncludedPaths []CollectionIndexingPolicyPath `json:"includedPaths"` + ExcludedPaths []CollectionIndexingPolicyPath `json:"excludedPaths"` +} + +type CollectionIndexingPolicyPath struct { + Path string `json:"path"` + Indexes []struct { + Kind string `json:"kind"` + DataType string `json:"dataType"` + Precision int `json:"precision"` + } `json:"indexes"` +} + +type CollectionPartitionKey struct { + Paths []string `json:"paths"` + Kind string `json:"kind"` + Version int `json:"Version"` +} + +type UserDefinedFunction struct { + Body string `json:"body"` + ID string `json:"id"` + Rid string `json:"_rid"` + Ts int `json:"_ts"` + Self string `json:"_self"` + Etag string `json:"_etag"` + Internals struct { + DatabaseId string + CollectionId string + } +} + +type StoredProcedure struct { + Body string `json:"body"` + ID string `json:"id"` + Rid string `json:"_rid"` + Ts int `json:"_ts"` + Self string `json:"_self"` + Etag string `json:"_etag"` + Internals struct { + DatabaseId string + CollectionId string + } +} + +type Trigger struct { + Body string `json:"body"` + ID string `json:"id"` + TriggerOperation string `json:"triggerOperation"` + TriggerType string `json:"triggerType"` + Rid string `json:"_rid"` + Ts int `json:"_ts"` + Self string `json:"_self"` + Etag string `json:"_etag"` + Internals struct { + DatabaseId string + CollectionId string + } +} + +type Document map[string]interface{} + +type PartitionKeyRange struct { + Rid string `json:"_rid"` + ID string `json:"id"` + Etag string `json:"_etag"` + MinInclusive string `json:"minInclusive"` + MaxExclusive string `json:"maxExclusive"` + RidPrefix int `json:"ridPrefix"` + Self string `json:"_self"` + ThroughputFraction int `json:"throughputFraction"` + Status string `json:"status"` + Parents []any `json:"parents"` + Ts int `json:"_ts"` + Lsn int `json:"lsn"` +} diff --git a/internal/struct_hidrators/collection_defaults.go b/internal/struct_hidrators/collection_defaults.go new file mode 100644 index 0000000..220c9eb --- /dev/null +++ b/internal/struct_hidrators/collection_defaults.go @@ -0,0 +1,32 @@ +package structhidrators + +import ( + repositorymodels "github.com/pikami/cosmium/internal/repository_models" +) + +var defaultCollection repositorymodels.Collection = repositorymodels.Collection{ + IndexingPolicy: repositorymodels.CollectionIndexingPolicy{ + IndexingMode: "consistent", + Automatic: true, + IncludedPaths: []repositorymodels.CollectionIndexingPolicyPath{ + {Path: "/*"}, + }, + ExcludedPaths: []repositorymodels.CollectionIndexingPolicyPath{ + {Path: "/\"_etag\"/?"}, + }, + }, + PartitionKey: repositorymodels.CollectionPartitionKey{ + Paths: []string{"/_partitionKey"}, + Kind: "Hash", + Version: 2, + }, + Rid: "nFFFFFFFFFF=", + Ts: 0, + Self: "", + Etag: "\"00000000-0000-0000-0000-000000000000\"", + Docs: "docs/", + Sprocs: "sprocs/", + Triggers: "triggers/", + Udfs: "udfs/", + Conflicts: "conflicts/", +} diff --git a/internal/struct_hidrators/hidrate.go b/internal/struct_hidrators/hidrate.go new file mode 100644 index 0000000..d9acb88 --- /dev/null +++ b/internal/struct_hidrators/hidrate.go @@ -0,0 +1,60 @@ +package structhidrators + +import ( + "reflect" + + repositorymodels "github.com/pikami/cosmium/internal/repository_models" +) + +func Hidrate(input interface{}) interface{} { + if reflect.TypeOf(input) == reflect.TypeOf(repositorymodels.Collection{}) { + return hidrate(input, defaultCollection) + } + return input +} + +func hidrate(input interface{}, defaults interface{}) interface{} { + inputVal := reflect.ValueOf(input) + defaultsVal := reflect.ValueOf(defaults) + + if inputVal.Kind() != reflect.Struct || defaultsVal.Kind() != reflect.Struct { + panic("Both input and defaults must be structs") + } + + output := reflect.New(inputVal.Type()).Elem() + for i := 0; i < inputVal.NumField(); i++ { + inputField := inputVal.Field(i) + defaultField := defaultsVal.Field(i) + + if inputField.Kind() == reflect.Struct && defaultField.Kind() == reflect.Struct { + filledNested := hidrate(inputField.Interface(), defaultField.Interface()) + output.Field(i).Set(reflect.ValueOf(filledNested)) + } else { + if isEmptyValue(inputField) { + output.Field(i).Set(defaultField) + } else { + output.Field(i).Set(inputField) + } + } + } + + return output.Interface() +} + +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +}