Move out repository models; Hidrate collection on create

This commit is contained in:
Pijus Kamandulis 2024-02-12 21:38:03 +02:00
parent 88526dcdcc
commit 9c56d01d27
23 changed files with 372 additions and 213 deletions

View File

@ -5,13 +5,14 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllCollections(c *gin.Context) { func GetAllCollections(c *gin.Context) {
databaseId := c.Param("databaseId") databaseId := c.Param("databaseId")
collections, status := repositories.GetAllCollections(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)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "DocumentCollections": collections, "_count": len(collections)})
return return
} }
@ -24,12 +25,12 @@ func GetCollection(c *gin.Context) {
id := c.Param("collId") id := c.Param("collId")
collection, status := repositories.GetCollection(databaseId, id) collection, status := repositories.GetCollection(databaseId, id)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusOK, collection) c.IndentedJSON(http.StatusOK, collection)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }
@ -42,12 +43,12 @@ func DeleteCollection(c *gin.Context) {
id := c.Param("collId") id := c.Param("collId")
status := repositories.DeleteCollection(databaseId, id) status := repositories.DeleteCollection(databaseId, id)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }
@ -57,7 +58,7 @@ func DeleteCollection(c *gin.Context) {
func CreateCollection(c *gin.Context) { func CreateCollection(c *gin.Context) {
databaseId := c.Param("databaseId") databaseId := c.Param("databaseId")
var newCollection repositories.Collection var newCollection repositorymodels.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()})
@ -69,14 +70,14 @@ func CreateCollection(c *gin.Context) {
return return
} }
status := repositories.CreateCollection(databaseId, newCollection) createdCollection, status := repositories.CreateCollection(databaseId, newCollection)
if status == repositories.Conflict { if status == repositorymodels.Conflict {
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
return return
} }
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusCreated, newCollection) c.IndentedJSON(http.StatusCreated, createdCollection)
return return
} }

View File

@ -5,11 +5,12 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllDatabases(c *gin.Context) { func GetAllDatabases(c *gin.Context) {
databases, status := repositories.GetAllDatabases() databases, status := repositories.GetAllDatabases()
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Databases": databases, "_count": len(databases)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Databases": databases, "_count": len(databases)})
return return
} }
@ -21,12 +22,12 @@ func GetDatabase(c *gin.Context) {
id := c.Param("databaseId") id := c.Param("databaseId")
database, status := repositories.GetDatabase(id) database, status := repositories.GetDatabase(id)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusOK, database) c.IndentedJSON(http.StatusOK, database)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }
@ -38,12 +39,12 @@ func DeleteDatabase(c *gin.Context) {
id := c.Param("databaseId") id := c.Param("databaseId")
status := repositories.DeleteDatabase(id) status := repositories.DeleteDatabase(id)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }
@ -52,7 +53,7 @@ func DeleteDatabase(c *gin.Context) {
} }
func CreateDatabase(c *gin.Context) { func CreateDatabase(c *gin.Context) {
var newDatabase repositories.Database var newDatabase repositorymodels.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()})
@ -65,12 +66,12 @@ func CreateDatabase(c *gin.Context) {
} }
status := repositories.CreateDatabase(newDatabase) status := repositories.CreateDatabase(newDatabase)
if status == repositories.Conflict { if status == repositorymodels.Conflict {
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
return return
} }
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusCreated, newDatabase) c.IndentedJSON(http.StatusCreated, newDatabase)
return return
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/constants" "github.com/pikami/cosmium/internal/constants"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllDocuments(c *gin.Context) { func GetAllDocuments(c *gin.Context) {
@ -13,7 +14,7 @@ func GetAllDocuments(c *gin.Context) {
collectionId := c.Param("collId") collectionId := c.Param("collId")
documents, status := repositories.GetAllDocuments(databaseId, collectionId) 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)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Documents": documents, "_count": len(documents)})
return return
} }
@ -27,12 +28,12 @@ func GetDocument(c *gin.Context) {
documentId := c.Param("docId") documentId := c.Param("docId")
document, status := repositories.GetDocument(databaseId, collectionId, documentId) document, status := repositories.GetDocument(databaseId, collectionId, documentId)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusOK, document) c.IndentedJSON(http.StatusOK, document)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }
@ -46,12 +47,12 @@ func DeleteDocument(c *gin.Context) {
documentId := c.Param("docId") documentId := c.Param("docId")
status := repositories.DeleteDocument(databaseId, collectionId, documentId) status := repositories.DeleteDocument(databaseId, collectionId, documentId)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return 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"} // 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)) 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 // TODO: Currently we return everything if the query fails
GetAllDocuments(c) GetAllDocuments(c)
return return
@ -94,12 +95,12 @@ func DocumentsPost(c *gin.Context) {
} }
status := repositories.CreateDocument(databaseId, collectionId, requestBody) status := repositories.CreateDocument(databaseId, collectionId, requestBody)
if status == repositories.Conflict { if status == repositorymodels.Conflict {
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"}) c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
return return
} }
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusCreated, requestBody) c.IndentedJSON(http.StatusCreated, requestBody)
return return
} }

View File

@ -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
}

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetPartitionKeyRanges(c *gin.Context) { func GetPartitionKeyRanges(c *gin.Context) {
@ -12,7 +13,7 @@ func GetPartitionKeyRanges(c *gin.Context) {
collectionId := c.Param("collId") collectionId := c.Param("collId")
partitionKeyRanges, status := repositories.GetPartitionKeyRanges(databaseId, collectionId) partitionKeyRanges, status := repositories.GetPartitionKeyRanges(databaseId, collectionId)
if status == repositories.StatusOk { if status == repositorymodels.StatusOk {
c.IndentedJSON(http.StatusOK, gin.H{ c.IndentedJSON(http.StatusOK, gin.H{
"_rid": "", "_rid": "",
"_count": len(partitionKeyRanges), "_count": len(partitionKeyRanges),
@ -21,7 +22,7 @@ func GetPartitionKeyRanges(c *gin.Context) {
return return
} }
if status == repositories.StatusNotFound { if status == repositorymodels.StatusNotFound {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"}) c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
return return
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllStoredProcedures(c *gin.Context) { func GetAllStoredProcedures(c *gin.Context) {
@ -13,7 +14,7 @@ func GetAllStoredProcedures(c *gin.Context) {
sps, status := repositories.GetAllStoredProcedures(databaseId, collectionId) 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)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "StoredProcedures": sps, "_count": len(sps)})
return return
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllTriggers(c *gin.Context) { func GetAllTriggers(c *gin.Context) {
@ -13,7 +14,7 @@ func GetAllTriggers(c *gin.Context) {
triggers, status := repositories.GetAllTriggers(databaseId, collectionId) 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)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Triggers": triggers, "_count": len(triggers)})
return return
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
) )
func GetAllUserDefinedFunctions(c *gin.Context) { func GetAllUserDefinedFunctions(c *gin.Context) {
@ -13,7 +14,7 @@ func GetAllUserDefinedFunctions(c *gin.Context) {
udfs, status := repositories.GetAllUserDefinedFunctions(databaseId, collectionId) 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)}) c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "UserDefinedFunctions": udfs, "_count": len(udfs)})
return return
} }

View File

@ -3,11 +3,14 @@ package api
import ( 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"
) )
func CreateRouter() *gin.Engine { func CreateRouter() *gin.Engine {
router := gin.Default() router := gin.Default()
router.Use(middleware.RequestLogger())
router.GET("/dbs/:databaseId/colls/:collId/pkranges", handlers.GetPartitionKeyRanges) router.GET("/dbs/:databaseId/colls/:collId/pkranges", handlers.GetPartitionKeyRanges)
router.POST("/dbs/:databaseId/colls/:collId/docs", handlers.DocumentsPost) router.POST("/dbs/:databaseId/colls/:collId/docs", handlers.DocumentsPost)

View File

@ -10,6 +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/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
"github.com/stretchr/testify/assert" "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) { t.Run("Should return conflict when collection exists", func(t *testing.T) {
repositories.CreateCollection(testDatabaseName, repositories.Collection{ repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
ID: testCollectionName, ID: testCollectionName,
}) })
@ -57,7 +58,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) {
repositories.CreateCollection(testDatabaseName, repositories.Collection{ repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
ID: testCollectionName, ID: testCollectionName,
}) })
@ -90,7 +91,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) {
repositories.CreateCollection(testDatabaseName, repositories.Collection{ repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
ID: testCollectionName, ID: testCollectionName,
}) })

View File

@ -10,6 +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/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
"github.com/stretchr/testify/assert" "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) { t.Run("Should return conflict when database exists", func(t *testing.T) {
repositories.CreateDatabase(repositories.Database{ repositories.CreateDatabase(repositorymodels.Database{
ID: testDatabaseName, ID: testDatabaseName,
}) })
@ -54,7 +55,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) {
repositories.CreateDatabase(repositories.Database{ repositories.CreateDatabase(repositorymodels.Database{
ID: testDatabaseName, ID: testDatabaseName,
}) })
@ -87,7 +88,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) {
repositories.CreateDatabase(repositories.Database{ repositories.CreateDatabase(repositorymodels.Database{
ID: testDatabaseName, ID: testDatabaseName,
}) })

View File

@ -9,6 +9,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
"github.com/pikami/cosmium/internal/repositories" "github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -41,7 +42,7 @@ func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, q
} }
func Test_Documents(t *testing.T) { func Test_Documents(t *testing.T) {
repositories.CreateCollection(testDatabaseName, repositories.Collection{ repositories.CreateCollection(testDatabaseName, repositorymodels.Collection{
ID: testCollectionName, ID: testCollectionName,
PartitionKey: struct { PartitionKey: struct {
Paths []string "json:\"paths\"" Paths []string "json:\"paths\""

View File

@ -1,53 +1,60 @@
package repositories 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: "db1"},
{ID: "db2"}, {ID: "db2"},
} }
func GetAllCollections(databaseId string) ([]Collection, RepositoryStatus) { func GetAllCollections(databaseId string) ([]repositorymodels.Collection, repositorymodels.RepositoryStatus) {
dbCollections := make([]Collection, 0) dbCollections := make([]repositorymodels.Collection, 0)
for _, coll := range collections { for _, coll := range collections {
if coll.internals.databaseId == databaseId { if coll.Internals.DatabaseId == databaseId {
dbCollections = append(dbCollections, coll) 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 { for _, coll := range collections {
if coll.internals.databaseId == databaseId && coll.ID == id { if coll.Internals.DatabaseId == databaseId && coll.ID == id {
return coll, StatusOk 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 { 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:]...) 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 { for _, coll := range collections {
if coll.internals.databaseId == databaseId && coll.ID == newCollection.ID { if coll.Internals.DatabaseId == databaseId && coll.ID == newCollection.ID {
return Conflict return repositorymodels.Collection{}, repositorymodels.Conflict
} }
} }
newCollection.internals = struct{ databaseId string }{ newCollection = structhidrators.Hidrate(newCollection).(repositorymodels.Collection)
databaseId: databaseId,
newCollection.Internals = struct{ DatabaseId string }{
DatabaseId: databaseId,
} }
collections = append(collections, newCollection) collections = append(collections, newCollection)
return StatusOk return newCollection, repositorymodels.StatusOk
} }

View File

@ -1,42 +1,44 @@
package repositories package repositories
var databases = []Database{ import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
var databases = []repositorymodels.Database{
{ID: "db1"}, {ID: "db1"},
{ID: "db2"}, {ID: "db2"},
} }
func GetAllDatabases() ([]Database, RepositoryStatus) { func GetAllDatabases() ([]repositorymodels.Database, repositorymodels.RepositoryStatus) {
return databases, StatusOk return databases, repositorymodels.StatusOk
} }
func GetDatabase(id string) (Database, RepositoryStatus) { func GetDatabase(id string) (repositorymodels.Database, repositorymodels.RepositoryStatus) {
for _, db := range databases { for _, db := range databases {
if db.ID == id { 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 { for index, db := range databases {
if db.ID == id { if db.ID == id {
databases = append(databases[:index], databases[index+1:]...) 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 { for _, db := range databases {
if db.ID == newDatabase.ID { if db.ID == newDatabase.ID {
return Conflict return repositorymodels.Conflict
} }
} }
databases = append(databases, newDatabase) databases = append(databases, newDatabase)
return StatusOk return repositorymodels.StatusOk
} }

View File

@ -4,15 +4,16 @@ import (
"log" "log"
"strings" "strings"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
"github.com/pikami/cosmium/parsers/nosql" "github.com/pikami/cosmium/parsers/nosql"
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor" memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
) )
var documents = []Document{} var documents = []repositorymodels.Document{}
func GetAllDocuments(databaseId string, collectionId string) ([]Document, RepositoryStatus) { func GetAllDocuments(databaseId string, collectionId string) ([]repositorymodels.Document, repositorymodels.RepositoryStatus) {
filteredDocuments := make([]Document, 0) filteredDocuments := make([]repositorymodels.Document, 0)
for _, doc := range documents { for _, doc := range documents {
docDbId := doc["_internal"].(map[string]interface{})["databaseId"] 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 { for _, doc := range documents {
docDbId := doc["_internal"].(map[string]interface{})["databaseId"] docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
docCollId := doc["_internal"].(map[string]interface{})["collectionId"] 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 { if docDbId == databaseId && docCollId == collectionId && docId == documentId {
doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"] 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 { for index, doc := range documents {
docDbId := doc["_internal"].(map[string]interface{})["databaseId"] docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
docCollId := doc["_internal"].(map[string]interface{})["collectionId"] 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 { if docDbId == databaseId && docCollId == collectionId && docId == documentId {
documents = append(documents[:index], documents[index+1:]...) 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"] == "" { if document["id"] == "" {
return BadRequest return repositorymodels.BadRequest
} }
collection, status := GetCollection(databaseId, collectionId) collection, status := GetCollection(databaseId, collectionId)
if status != StatusOk { if status != repositorymodels.StatusOk {
return StatusNotFound return repositorymodels.StatusNotFound
} }
for _, doc := range documents { for _, doc := range documents {
@ -73,7 +74,7 @@ func CreateDocument(databaseId string, collectionId string, document map[string]
docId := doc["id"] docId := doc["id"]
if docDbId == databaseId && docCollId == collectionId && docId == document["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) 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)) parsedQuery, err := nosql.Parse("", []byte(query))
if err != nil { if err != nil {
log.Printf("Failed to parse query: %s\nerr: %v", query, err) log.Printf("Failed to parse query: %s\nerr: %v", query, err)
return nil, BadRequest return nil, repositorymodels.BadRequest
} }
collectionDocuments, status := GetAllDocuments(databaseId, collectionId) collectionDocuments, status := GetAllDocuments(databaseId, collectionId)
if status != StatusOk { if status != repositorymodels.StatusOk {
return nil, status return nil, status
} }
@ -119,5 +120,5 @@ func ExecuteQueryDocuments(databaseId string, collectionId string, query string)
covDocs = append(covDocs, map[string]interface{}(doc)) covDocs = append(covDocs, map[string]interface{}(doc))
} }
return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), StatusOk return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), repositorymodels.StatusOk
} }

View File

@ -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"`
}

View File

@ -1,8 +1,10 @@
package repositories 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 // I have no idea what this is tbh
return []PartitionKeyRange{ return []repositorymodels.PartitionKeyRange{
{ {
Rid: "ZxlyAP7rKwACAAAAAAAAUA==", Rid: "ZxlyAP7rKwACAAAAAAAAUA==",
ID: "0", ID: "0",
@ -17,5 +19,5 @@ func GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionK
Ts: 1707431241, Ts: 1707431241,
Lsn: 17, Lsn: 17,
}, },
}, StatusOk }, repositorymodels.StatusOk
} }

View File

@ -1,15 +1,17 @@
package repositories package repositories
var storedProcedures = []StoredProcedure{} import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
func GetAllStoredProcedures(databaseId string, collectionId string) ([]StoredProcedure, RepositoryStatus) { var storedProcedures = []repositorymodels.StoredProcedure{}
sps := make([]StoredProcedure, 0)
func GetAllStoredProcedures(databaseId string, collectionId string) ([]repositorymodels.StoredProcedure, repositorymodels.RepositoryStatus) {
sps := make([]repositorymodels.StoredProcedure, 0)
for _, coll := range storedProcedures { 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) sps = append(sps, coll)
} }
} }
return sps, StatusOk return sps, repositorymodels.StatusOk
} }

View File

@ -1,15 +1,17 @@
package repositories package repositories
var triggers = []Trigger{} import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
func GetAllTriggers(databaseId string, collectionId string) ([]Trigger, RepositoryStatus) { var triggers = []repositorymodels.Trigger{}
filteredTriggers := make([]Trigger, 0)
func GetAllTriggers(databaseId string, collectionId string) ([]repositorymodels.Trigger, repositorymodels.RepositoryStatus) {
filteredTriggers := make([]repositorymodels.Trigger, 0)
for _, coll := range triggers { 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) filteredTriggers = append(filteredTriggers, coll)
} }
} }
return filteredTriggers, StatusOk return filteredTriggers, repositorymodels.StatusOk
} }

View File

@ -1,15 +1,17 @@
package repositories package repositories
var userDefinedFunctions = []UserDefinedFunction{} import repositorymodels "github.com/pikami/cosmium/internal/repository_models"
func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]UserDefinedFunction, RepositoryStatus) { var userDefinedFunctions = []repositorymodels.UserDefinedFunction{}
udfs := make([]UserDefinedFunction, 0)
func GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]repositorymodels.UserDefinedFunction, repositorymodels.RepositoryStatus) {
udfs := make([]repositorymodels.UserDefinedFunction, 0)
for _, coll := range userDefinedFunctions { 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) udfs = append(udfs, coll)
} }
} }
return udfs, StatusOk return udfs, repositorymodels.StatusOk
} }

View File

@ -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"`
}

View File

@ -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/",
}

View File

@ -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
}