mirror of https://github.com/pikami/cosmium.git
Added Documents CURD
This commit is contained in:
parent
a4181ef6bf
commit
471df5151a
|
@ -12,7 +12,7 @@ func GetAllCollections(c *gin.Context) {
|
|||
|
||||
collections, status := repositories.GetAllCollections(databaseId)
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "DocumentCollections": collections})
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "DocumentCollections": collections, "_count": len(collections)})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
func GetAllDatabases(c *gin.Context) {
|
||||
databases, status := repositories.GetAllDatabases()
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Databases": databases})
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Databases": databases, "_count": len(databases)})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pikami/cosmium/internal/constants"
|
||||
"github.com/pikami/cosmium/internal/repositories"
|
||||
)
|
||||
|
||||
func GetAllDocuments(c *gin.Context) {
|
||||
databaseId := c.Param("databaseId")
|
||||
collectionId := c.Param("collId")
|
||||
|
||||
documents, status := repositories.GetAllDocuments(databaseId, collectionId)
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Documents": documents, "_count": len(documents)})
|
||||
return
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||
}
|
||||
|
||||
func GetDocument(c *gin.Context) {
|
||||
databaseId := c.Param("databaseId")
|
||||
collectionId := c.Param("collId")
|
||||
documentId := c.Param("docId")
|
||||
|
||||
document, status := repositories.GetDocument(databaseId, collectionId, documentId)
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusOK, document)
|
||||
return
|
||||
}
|
||||
|
||||
if status == repositories.StatusNotFound {
|
||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||
return
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||
}
|
||||
|
||||
func DeleteDocument(c *gin.Context) {
|
||||
databaseId := c.Param("databaseId")
|
||||
collectionId := c.Param("collId")
|
||||
documentId := c.Param("docId")
|
||||
|
||||
status := repositories.DeleteDocument(databaseId, collectionId, documentId)
|
||||
if status == repositories.StatusOk {
|
||||
c.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
if status == repositories.StatusNotFound {
|
||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||
return
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||
}
|
||||
|
||||
func DocumentsPost(c *gin.Context) {
|
||||
databaseId := c.Param("databaseId")
|
||||
collectionId := c.Param("collId")
|
||||
|
||||
var requestBody map[string]interface{}
|
||||
if err := c.BindJSON(&requestBody); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
query := requestBody["query"]
|
||||
if query != nil {
|
||||
if c.GetHeader("x-ms-cosmos-is-query-plan-request") != "" {
|
||||
c.IndentedJSON(http.StatusOK, constants.QueryPlanResponse)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Handle these {"query":"select c.id, c._self, c._rid, c._ts, [c[\"pk\"]] as _partitionKeyValue from c"}
|
||||
GetAllDocuments(c)
|
||||
return
|
||||
}
|
||||
|
||||
if requestBody["id"] == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"message": "BadRequest"})
|
||||
return
|
||||
}
|
||||
|
||||
status := repositories.CreateDocument(databaseId, collectionId, requestBody)
|
||||
if status == repositories.Conflict {
|
||||
c.IndentedJSON(http.StatusConflict, gin.H{"message": "Conflict"})
|
||||
return
|
||||
}
|
||||
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusCreated, requestBody)
|
||||
return
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pikami/cosmium/internal/repositories"
|
||||
)
|
||||
|
||||
func GetPartitionKeyRanges(c *gin.Context) {
|
||||
databaseId := c.Param("databaseId")
|
||||
collectionId := c.Param("collId")
|
||||
|
||||
partitionKeyRanges, status := repositories.GetPartitionKeyRanges(databaseId, collectionId)
|
||||
if status == repositories.StatusOk {
|
||||
c.IndentedJSON(http.StatusOK, gin.H{
|
||||
"_rid": "",
|
||||
"_count": len(partitionKeyRanges),
|
||||
"PartitionKeyRanges": partitionKeyRanges,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if status == repositories.StatusNotFound {
|
||||
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "NotFound"})
|
||||
return
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||
}
|
|
@ -1,42 +1,12 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pikami/cosmium/api/config"
|
||||
"github.com/pikami/cosmium/internal/constants"
|
||||
)
|
||||
|
||||
func GetServerInfo(c *gin.Context) {
|
||||
c.IndentedJSON(http.StatusOK, gin.H{
|
||||
"_self": "",
|
||||
"id": config.Config.DatabaseAccount,
|
||||
"_rid": fmt.Sprintf("%s.%s", config.Config.DatabaseAccount, config.Config.DatabaseDomain),
|
||||
"media": "//media/",
|
||||
"addresses": "//addresses/",
|
||||
"_dbs": "//dbs/",
|
||||
"writableLocations": []map[string]interface{}{
|
||||
{
|
||||
"name": "South Central US",
|
||||
"databaseAccountEndpoint": config.Config.DatabaseEndpoint,
|
||||
},
|
||||
},
|
||||
"readableLocations": []map[string]interface{}{
|
||||
{
|
||||
"name": "South Central US",
|
||||
"databaseAccountEndpoint": config.Config.DatabaseEndpoint,
|
||||
},
|
||||
},
|
||||
"enableMultipleWriteLocations": false,
|
||||
"userReplicationPolicy": map[string]interface{}{
|
||||
"asyncReplication": false,
|
||||
"minReplicaSetSize": 1,
|
||||
"maxReplicasetSize": 4,
|
||||
},
|
||||
"userConsistencyPolicy": map[string]interface{}{"defaultConsistencyLevel": "Session"},
|
||||
"systemReplicationPolicy": map[string]interface{}{"minReplicaSetSize": 1, "maxReplicasetSize": 4},
|
||||
"readPolicy": map[string]interface{}{"primaryReadCoefficient": 1, "secondaryReadCoefficient": 1},
|
||||
"queryEngineConfiguration": "{\"allowNewKeywords\":true,\"maxJoinsPerSqlQuery\":10,\"maxQueryRequestTimeoutFraction\":0.9,\"maxSqlQueryInputLength\":524288,\"maxUdfRefPerSqlQuery\":10,\"queryMaxInMemorySortDocumentCount\":-1000,\"spatialMaxGeometryPointCount\":256,\"sqlAllowNonFiniteNumbers\":false,\"sqlDisableOptimizationFlags\":0,\"enableSpatialIndexing\":true,\"maxInExpressionItemsCount\":2147483647,\"maxLogicalAndPerSqlQuery\":2147483647,\"maxLogicalOrPerSqlQuery\":2147483647,\"maxSpatialQueryCells\":2147483647,\"sqlAllowAggregateFunctions\":true,\"sqlAllowGroupByClause\":true,\"sqlAllowLike\":true,\"sqlAllowSubQuery\":true,\"sqlAllowScalarSubQuery\":true,\"sqlAllowTop\":true}",
|
||||
})
|
||||
c.IndentedJSON(http.StatusOK, constants.ServerInfoResponse)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,13 @@ import (
|
|||
func CreateRouter() *gin.Engine {
|
||||
router := gin.Default()
|
||||
|
||||
router.GET("/dbs/:databaseId/colls/:collId/pkranges", handlers.GetPartitionKeyRanges)
|
||||
|
||||
router.POST("/dbs/:databaseId/colls/:collId/docs", handlers.DocumentsPost)
|
||||
router.GET("/dbs/:databaseId/colls/:collId/docs", handlers.GetAllDocuments)
|
||||
router.GET("/dbs/:databaseId/colls/:collId/docs/:docId", handlers.GetDocument)
|
||||
router.DELETE("/dbs/:databaseId/colls/:collId/docs/:docId", handlers.DeleteDocument)
|
||||
|
||||
router.POST("/dbs/:databaseId/colls", handlers.CreateCollection)
|
||||
router.GET("/dbs/:databaseId/colls", handlers.GetAllCollections)
|
||||
router.GET("/dbs/:databaseId/colls/:collId", handlers.GetCollection)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package constants
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pikami/cosmium/api/config"
|
||||
)
|
||||
|
||||
var ServerInfoResponse = gin.H{
|
||||
"_self": "",
|
||||
"id": config.Config.DatabaseAccount,
|
||||
"_rid": fmt.Sprintf("%s.%s", config.Config.DatabaseAccount, config.Config.DatabaseDomain),
|
||||
"media": "//media/",
|
||||
"addresses": "//addresses/",
|
||||
"_dbs": "//dbs/",
|
||||
"writableLocations": []map[string]interface{}{
|
||||
{
|
||||
"name": "South Central US",
|
||||
"databaseAccountEndpoint": config.Config.DatabaseEndpoint,
|
||||
},
|
||||
},
|
||||
"readableLocations": []map[string]interface{}{
|
||||
{
|
||||
"name": "South Central US",
|
||||
"databaseAccountEndpoint": config.Config.DatabaseEndpoint,
|
||||
},
|
||||
},
|
||||
"enableMultipleWriteLocations": false,
|
||||
"userReplicationPolicy": map[string]interface{}{
|
||||
"asyncReplication": false,
|
||||
"minReplicaSetSize": 1,
|
||||
"maxReplicasetSize": 4,
|
||||
},
|
||||
"userConsistencyPolicy": map[string]interface{}{"defaultConsistencyLevel": "Session"},
|
||||
"systemReplicationPolicy": map[string]interface{}{"minReplicaSetSize": 1, "maxReplicasetSize": 4},
|
||||
"readPolicy": map[string]interface{}{"primaryReadCoefficient": 1, "secondaryReadCoefficient": 1},
|
||||
"queryEngineConfiguration": "{\"allowNewKeywords\":true,\"maxJoinsPerSqlQuery\":10,\"maxQueryRequestTimeoutFraction\":0.9,\"maxSqlQueryInputLength\":524288,\"maxUdfRefPerSqlQuery\":10,\"queryMaxInMemorySortDocumentCount\":-1000,\"spatialMaxGeometryPointCount\":256,\"sqlAllowNonFiniteNumbers\":false,\"sqlDisableOptimizationFlags\":0,\"enableSpatialIndexing\":true,\"maxInExpressionItemsCount\":2147483647,\"maxLogicalAndPerSqlQuery\":2147483647,\"maxLogicalOrPerSqlQuery\":2147483647,\"maxSpatialQueryCells\":2147483647,\"sqlAllowAggregateFunctions\":true,\"sqlAllowGroupByClause\":true,\"sqlAllowLike\":true,\"sqlAllowSubQuery\":true,\"sqlAllowScalarSubQuery\":true,\"sqlAllowTop\":true}",
|
||||
}
|
||||
|
||||
var QueryPlanResponse = gin.H{
|
||||
"partitionedQueryExecutionInfoVersion": 2,
|
||||
"queryInfo": map[string]interface{}{
|
||||
"distinctType": "None",
|
||||
"top": nil,
|
||||
"offset": nil,
|
||||
"limit": nil,
|
||||
"orderBy": []interface{}{},
|
||||
"orderByExpressions": []interface{}{},
|
||||
"groupByExpressions": []interface{}{},
|
||||
"groupByAliases": []interface{}{},
|
||||
"aggregates": []interface{}{},
|
||||
"groupByAliasToAggregateType": map[string]interface{}{},
|
||||
"rewrittenQuery": "",
|
||||
"hasSelectValue": false,
|
||||
"dCountInfo": nil,
|
||||
},
|
||||
"queryRanges": []interface{}{
|
||||
map[string]interface{}{
|
||||
"min": "",
|
||||
"max": "FF",
|
||||
"isMinInclusive": true,
|
||||
"isMaxInclusive": false,
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package repositories
|
||||
|
||||
import "strings"
|
||||
|
||||
var documents = []Document{}
|
||||
|
||||
func GetAllDocuments(databaseId string, collectionId string) ([]Document, RepositoryStatus) {
|
||||
filteredDocuments := make([]Document, 0)
|
||||
|
||||
for _, doc := range documents {
|
||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
||||
|
||||
if docDbId == databaseId && docCollId == collectionId {
|
||||
doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"]
|
||||
filteredDocuments = append(filteredDocuments, doc)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredDocuments, StatusOk
|
||||
}
|
||||
|
||||
func GetDocument(databaseId string, collectionId string, documentId string) (Document, RepositoryStatus) {
|
||||
for _, doc := range documents {
|
||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
||||
docId := doc["id"]
|
||||
|
||||
if docDbId == databaseId && docCollId == collectionId && docId == documentId {
|
||||
doc["_partitionKeyValue"] = doc["_internal"].(map[string]interface{})["partitionKeyValue"]
|
||||
return doc, StatusOk
|
||||
}
|
||||
}
|
||||
|
||||
return Document{}, StatusNotFound
|
||||
}
|
||||
|
||||
func DeleteDocument(databaseId string, collectionId string, documentId string) RepositoryStatus {
|
||||
for index, doc := range documents {
|
||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
||||
docId := doc["id"]
|
||||
|
||||
if docDbId == databaseId && docCollId == collectionId && docId == documentId {
|
||||
documents = append(documents[:index], documents[index+1:]...)
|
||||
return StatusOk
|
||||
}
|
||||
}
|
||||
|
||||
return StatusNotFound
|
||||
}
|
||||
|
||||
func CreateDocument(databaseId string, collectionId string, document map[string]interface{}) RepositoryStatus {
|
||||
if document["id"] == "" {
|
||||
return BadRequest
|
||||
}
|
||||
|
||||
collection, status := GetCollection(databaseId, collectionId)
|
||||
if status != StatusOk {
|
||||
return StatusNotFound
|
||||
}
|
||||
|
||||
for _, doc := range documents {
|
||||
docDbId := doc["_internal"].(map[string]interface{})["databaseId"]
|
||||
docCollId := doc["_internal"].(map[string]interface{})["collectionId"]
|
||||
docId := doc["id"]
|
||||
|
||||
if docDbId == databaseId && docCollId == collectionId && docId == document["id"] {
|
||||
return Conflict
|
||||
}
|
||||
}
|
||||
|
||||
partitionKeyValue := make([]string, 0)
|
||||
for _, path := range collection.PartitionKey.Paths {
|
||||
var val interface{}
|
||||
for _, part := range strings.Split(path, "/") {
|
||||
val = document[part]
|
||||
}
|
||||
partitionKeyValue = append(partitionKeyValue, val.(string))
|
||||
}
|
||||
|
||||
document["_internal"] = map[string]interface{}{
|
||||
"databaseId": databaseId,
|
||||
"collectionId": collectionId,
|
||||
"partitionKeyValue": partitionKeyValue,
|
||||
}
|
||||
documents = append(documents, document)
|
||||
|
||||
return StatusOk
|
||||
}
|
|
@ -10,6 +10,7 @@ const (
|
|||
StatusOk = 1
|
||||
StatusNotFound = 2
|
||||
Conflict = 3
|
||||
BadRequest = 4
|
||||
)
|
||||
|
||||
type Collection struct {
|
||||
|
@ -86,3 +87,20 @@ type Trigger struct {
|
|||
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"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package repositories
|
||||
|
||||
func GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionKeyRange, RepositoryStatus) {
|
||||
// I have no idea what this is tbh
|
||||
return []PartitionKeyRange{
|
||||
{
|
||||
Rid: "ZxlyAP7rKwACAAAAAAAAUA==",
|
||||
ID: "0",
|
||||
Etag: "\"00005504-0000-0100-0000-65c555490000\"",
|
||||
MinInclusive: "",
|
||||
MaxExclusive: "FF",
|
||||
RidPrefix: 0,
|
||||
Self: "dbs/ZxlyAA==/colls/ZxlyAP7rKwA=/pkranges/ZxlyAP7rKwACAAAAAAAAUA==/",
|
||||
ThroughputFraction: 1,
|
||||
Status: "online",
|
||||
Parents: []interface{}{},
|
||||
Ts: 1707431241,
|
||||
Lsn: 17,
|
||||
},
|
||||
}, StatusOk
|
||||
}
|
|
@ -3,13 +3,13 @@ package repositories
|
|||
var triggers = []Trigger{}
|
||||
|
||||
func GetAllTriggers(databaseId string, collectionId string) ([]Trigger, RepositoryStatus) {
|
||||
sps := make([]Trigger, 0)
|
||||
filteredTriggers := make([]Trigger, 0)
|
||||
|
||||
for _, coll := range triggers {
|
||||
if coll.internals.databaseId == databaseId && coll.internals.collectionId == collectionId {
|
||||
sps = append(sps, coll)
|
||||
filteredTriggers = append(filteredTriggers, coll)
|
||||
}
|
||||
}
|
||||
|
||||
return sps, StatusOk
|
||||
return filteredTriggers, StatusOk
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue