feat(be): add env, tempalte and inv implementation for bolt

This commit is contained in:
Denis Gukov 2021-05-09 01:25:31 +05:00
parent 14f2df7910
commit 67acad9c32
7 changed files with 240 additions and 140 deletions

View File

@ -163,3 +163,8 @@ var RepositoryObject = ObjectProperties{
TemplateColumnName: "repository_id",
}
var TemplateObject = ObjectProperties{
TableName: "project__template",
SortableColumns: []string{"name"},
}

View File

@ -11,14 +11,21 @@ import (
"strconv"
)
type enumerable interface {
First() (key []byte, value []byte)
Next() (key []byte, value []byte)
}
type BoltDb struct {
db *bbolt.DB
}
func makeBucketId(obj db.ObjectProperties, ids ...int) []byte {
func makeBucketId(props db.ObjectProperties, ids ...int) []byte {
n := len(ids)
id := obj.TableName
id := props.TableName
for i := 0; i < n; i++ {
id += fmt.Sprintf("_%010d", ids[i])
}
@ -78,15 +85,19 @@ func getFieldNameByTag(t reflect.Type, tag string, value string) (string, error)
func sortObjects(objects interface{}, sortBy string, sortInverted bool) error {
objectsValue := reflect.ValueOf(objects).Elem()
objType := objectsValue.Type().Elem()
fieldName, err := getFieldNameByTag(objType, "db", sortBy)
if err != nil {
return err
}
sort.SliceStable(objectsValue.Interface(), func (i, j int) bool {
fieldI := objectsValue.Index(i).FieldByName(fieldName)
fieldJ := objectsValue.Index(j).FieldByName(fieldName)
switch fieldJ.Kind() {
valueI := objectsValue.Index(i).FieldByName(fieldName)
valueJ := objectsValue.Index(j).FieldByName(fieldName)
less := false
switch valueI.Kind() {
case reflect.Int:
case reflect.Int8:
case reflect.Int16:
@ -97,65 +108,72 @@ func sortObjects(objects interface{}, sortBy string, sortInverted bool) error {
case reflect.Uint16:
case reflect.Uint32:
case reflect.Uint64:
return fieldI.Int() < fieldJ.Int()
less = valueI.Int() < valueJ.Int()
case reflect.Float32:
case reflect.Float64:
return fieldI.Float() < fieldJ.Float()
less = valueI.Float() < valueJ.Float()
case reflect.String:
return fieldI.String() < fieldJ.String()
less = valueI.String() < valueJ.String()
}
return false
if sortInverted {
less = !less
}
return less
})
return nil
}
func (d *BoltDb) getObjects(projectID int, props db.ObjectProperties, params db.RetrieveQueryParams, objects interface{}) (err error) {
func unmarshalObjects(rawData enumerable, params db.RetrieveQueryParams, objects interface{}) (err error) {
objectsValue := reflect.ValueOf(objects).Elem()
objType := objectsValue.Type().Elem()
// Read elements from database
err = d.db.View(func(tx *bbolt.Tx) error {
i := 0 // current item index
n := 0 // number of added items
b := tx.Bucket(makeBucketId(props, projectID))
c := b.Cursor()
i := 0 // current item index
n := 0 // number of added items
for k, v := c.First(); k != nil; k, v = c.Next() {
if i < params.Offset {
continue
}
obj := reflect.New(objType).Elem()
err2 := json.Unmarshal(v, &obj)
if err2 == nil {
return err2
}
objectsValue.Set(reflect.Append(objectsValue, obj))
n++
if n > params.Count {
break
}
for k, v := rawData.First(); k != nil; k, v = rawData.Next() {
if i < params.Offset {
continue
}
return nil
})
obj := reflect.New(objType).Elem()
err = json.Unmarshal(v, &obj)
if err == nil {
return err
}
objectsValue.Set(reflect.Append(objectsValue, obj))
n++
if n > params.Count {
break
}
}
if err != nil {
return
}
// Sort elements
err = sortObjects(objects, params.SortBy, params.SortInverted)
if params.SortBy != "" {
err = sortObjects(objects, params.SortBy, params.SortInverted)
}
return
}
func (d *BoltDb) getObjects(projectID int, props db.ObjectProperties, params db.RetrieveQueryParams, objects interface{}) error {
return d.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(makeBucketId(props, projectID))
c := b.Cursor()
return unmarshalObjects(c, params, objects)
})
}
func (d *BoltDb) isObjectInUse(projectID int, props db.ObjectProperties, objectID int) (inUse bool, err error) {
err = d.db.View(func(tx *bbolt.Tx) error {
@ -190,3 +208,53 @@ func (d *BoltDb) deleteObject(projectID int, props db.ObjectProperties, objectID
func (d *BoltDb) deleteObjectSoft(projectID int, props db.ObjectProperties, objectID int) error {
return d.deleteObject(projectID, props, objectID)
}
func (d *BoltDb) updateObject(projectID int, props db.ObjectProperties, object interface{}) error {
return d.db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket(makeBucketId(props, projectID))
if b == nil {
return db.ErrNotFound
}
idValue := reflect.ValueOf(object).FieldByName("ID")
id := []byte(strconv.Itoa(int(idValue.Int())))
if b.Get(id) == nil {
return db.ErrNotFound
}
str, err := json.Marshal(object)
if err != nil {
return err
}
return b.Put(id, str)
})
}
func (d *BoltDb) createObject(projectID int, props db.ObjectProperties, object interface{}) (interface{}, error) {
err := d.db.Update(func(tx *bbolt.Tx) error {
b, err2 := tx.CreateBucketIfNotExists(makeBucketId(props, projectID))
if err2 != nil {
return err2
}
id, err2 := b.NextSequence()
if err2 != nil {
return err2
}
idValue := reflect.ValueOf(object).FieldByName("ID")
idValue.SetInt(int64(id))
str, err2 := json.Marshal(object)
if err2 != nil {
return err2
}
return b.Put([]byte(strconv.Itoa(int(id))), str)
})
return object, err
}

View File

@ -1,6 +1,8 @@
package bolt
import "github.com/ansible-semaphore/semaphore/db"
import (
"github.com/ansible-semaphore/semaphore/db"
)
func (d *BoltDb) GetAccessKey(projectID int, accessKeyID int) (db.AccessKey, error) {
var key db.AccessKey
@ -15,11 +17,12 @@ func (d *BoltDb) GetAccessKeys(projectID int, params db.RetrieveQueryParams) ([]
}
func (d *BoltDb) UpdateAccessKey(key db.AccessKey) error {
return nil
return d.updateObject(*key.ProjectID, db.AccessKeyObject, key)
}
func (d *BoltDb) CreateAccessKey(key db.AccessKey) (newKey db.AccessKey, err error) {
return
func (d *BoltDb) CreateAccessKey(key db.AccessKey) (db.AccessKey, error) {
newKey, err := d.createObject(*key.ProjectID, db.GlobalAccessKeyObject, key)
return newKey.(db.AccessKey), err
}
func (d *BoltDb) DeleteAccessKey(projectID int, accessKeyID int) error {
@ -31,24 +34,23 @@ func (d *BoltDb) DeleteAccessKeySoft(projectID int, accessKeyID int) error {
}
func (d *BoltDb) GetGlobalAccessKey(accessKeyID int) (db.AccessKey, error) {
var key db.AccessKey
err := d.getObject(0, db.GlobalAccessKeyObject, accessKeyID, &key)
return key, err
func (d *BoltDb) GetGlobalAccessKey(accessKeyID int) (key db.AccessKey, err error) {
err = d.getObject(0, db.GlobalAccessKeyObject, accessKeyID, &key)
return
}
func (d *BoltDb) GetGlobalAccessKeys(params db.RetrieveQueryParams) ([]db.AccessKey, error) {
var keys []db.AccessKey
err := d.getObjects(0, db.GlobalAccessKeyObject, params, &keys)
return keys, err
func (d *BoltDb) GetGlobalAccessKeys(params db.RetrieveQueryParams) (keys []db.AccessKey, err error) {
err = d.getObjects(0, db.GlobalAccessKeyObject, params, &keys)
return
}
func (d *BoltDb) UpdateGlobalAccessKey(key db.AccessKey) error {
return nil
return d.updateObject(0, db.AccessKeyObject, key)
}
func (d *BoltDb) CreateGlobalAccessKey(key db.AccessKey) (newKey db.AccessKey, err error) {
return
func (d *BoltDb) CreateGlobalAccessKey(key db.AccessKey) (db.AccessKey, error) {
newKey, err := d.createObject(0, db.GlobalAccessKeyObject, key)
return newKey.(db.AccessKey), err
}
func (d *BoltDb) DeleteGlobalAccessKey(accessKeyID int) error {

30
db/bolt/environment.go Normal file
View File

@ -0,0 +1,30 @@
package bolt
import "github.com/ansible-semaphore/semaphore/db"
func (d *BoltDb) GetEnvironment(projectID int, environmentID int) (environment db.Environment, err error) {
err = d.getObject(projectID, db.EnvironmentObject, environmentID, &environment)
return
}
func (d *BoltDb) GetEnvironments(projectID int, params db.RetrieveQueryParams) (environment []db.Environment, err error) {
err = d.getObjects(projectID, db.EnvironmentObject, params, &environment)
return
}
func (d *BoltDb) UpdateEnvironment(env db.Environment) error {
return d.updateObject(env.ProjectID, db.EnvironmentObject, &env)
}
func (d *BoltDb) CreateEnvironment(env db.Environment) (db.Environment, error) {
newEnv, err := d.createObject(env.ProjectID, db.EnvironmentObject, env)
return newEnv.(db.Environment), err
}
func (d *BoltDb) DeleteEnvironment(projectID int, environmentID int) error {
return d.deleteObject(projectID, db.EnvironmentObject, environmentID)
}
func (d *BoltDb) DeleteEnvironmentSoft(projectID int, environmentID int) error {
return d.deleteObjectSoft(projectID, db.EnvironmentObject, environmentID)
}

View File

@ -1,28 +1,12 @@
package bolt
import (
"encoding/json"
"github.com/ansible-semaphore/semaphore/db"
"go.etcd.io/bbolt"
"strconv"
)
func (d *BoltDb) GetInventory(projectID int, inventoryID int) (inventory db.Inventory, err error) {
err = d.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(makeBucketId(db.InventoryObject, projectID))
if b == nil {
return db.ErrNotFound
}
id := []byte(strconv.Itoa(inventoryID))
str := b.Get(id)
if str == nil {
return db.ErrNotFound
}
return json.Unmarshal(str, &inventory)
})
err = d.getObject(projectID, db.InventoryObject, inventoryID, &inventory)
if err != nil {
return
@ -43,76 +27,26 @@ func (d *BoltDb) GetInventory(projectID int, inventoryID int) (inventory db.Inve
}
func (d *BoltDb) GetInventories(projectID int, params db.RetrieveQueryParams) (inventories []db.Inventory, err error) {
err = d.db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket(makeBucketId(db.InventoryObject, projectID))
if b == nil {
return db.ErrNotFound
}
return nil
})
return inventories, err
}
func (d *BoltDb) DeleteInventory(projectID int, inventoryID int) error {
return d.db.Update(func (tx *bbolt.Tx) error {
b := tx.Bucket(makeBucketId(db.InventoryObject, projectID))
if b == nil {
return db.ErrNotFound
}
return b.Delete([]byte(strconv.Itoa(inventoryID)))
})
}
func (d *BoltDb) DeleteInventorySoft(projectID int, inventoryID int) error {
return d.DeleteInventory(projectID, inventoryID)
}
func (d *BoltDb) UpdateInventory(inventory db.Inventory) error {
err := d.db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte("inventory_" + strconv.Itoa(inventory.ProjectID)))
if b == nil {
return db.ErrNotFound
}
id := []byte(strconv.Itoa(inventory.ID))
if b.Get(id) == nil {
return db.ErrNotFound
}
str, err2 := json.Marshal(inventory)
if err2 != nil {
return err2
}
return b.Put(id, str)
})
return err
}
func (d *BoltDb) CreateInventory(inventory db.Inventory) (newInventory db.Inventory, err error) {
err = d.db.Update(func(tx *bbolt.Tx) error {
b, err2 := tx.CreateBucketIfNotExists(makeBucketId(db.InventoryObject, inventory.ProjectID))
if err2 != nil {
return err2
}
id, _ := b.NextSequence()
newInventory = inventory
newInventory.ID = int(id)
str, err2 := json.Marshal(newInventory)
if err2 != nil {
return err2
}
return b.Put([]byte(strconv.Itoa(newInventory.ID)), str)
})
err = d.getObjects(projectID, db.AccessKeyObject, params, &inventories)
return
}
func (d *BoltDb) DeleteInventory(projectID int, inventoryID int) error {
return d.deleteObject(projectID, db.InventoryObject, inventoryID)
}
func (d *BoltDb) DeleteInventorySoft(projectID int, inventoryID int) error {
return d.deleteObjectSoft(projectID, db.InventoryObject, inventoryID)
}
func (d *BoltDb) UpdateInventory(inventory db.Inventory) error {
return d.updateObject(inventory.ProjectID, db.InventoryObject, inventory)
}
func (d *BoltDb) CreateInventory(inventory db.Inventory) (db.Inventory, error) {
newInventory, err := d.createObject(inventory.ProjectID, db.InventoryObject, inventory)
return newInventory.(db.Inventory), err
}

33
db/bolt/repository.go Normal file
View File

@ -0,0 +1,33 @@
package bolt
import (
"github.com/ansible-semaphore/semaphore/db"
)
func (d *BoltDb) GetRepository(projectID int, repositoryID int) (repository db.Repository, err error) {
err = d.getObject(projectID, db.RepositoryObject, repositoryID, &repository)
return
}
func (d *BoltDb) GetRepositories(projectID int, params db.RetrieveQueryParams) (repositories []db.Repository, err error) {
err = d.getObjects(projectID, db.RepositoryObject, params, &repositories)
return
}
func (d *BoltDb) UpdateRepository(repository db.Repository) error {
return d.updateObject(repository.ProjectID, db.RepositoryObject, repository)
}
func (d *BoltDb) CreateRepository(repository db.Repository) (db.Repository, error) {
newRepo, err := d.createObject(repository.ProjectID, db.RepositoryObject, repository)
return newRepo.(db.Repository), err
}
func (d *BoltDb) DeleteRepository(projectID int, repositoryId int) error {
return d.deleteObject(projectID, db.RepositoryObject, repositoryId)
}
func (d *BoltDb) DeleteRepositorySoft(projectID int, repositoryId int) error {
return d.deleteObjectSoft(projectID, db.RepositoryObject, repositoryId)
}

28
db/bolt/template.go Normal file
View File

@ -0,0 +1,28 @@
package bolt
import (
"github.com/ansible-semaphore/semaphore/db"
)
func (d *BoltDb) CreateTemplate(template db.Template) (db.Template, error) {
newTemplate, err := d.createObject(template.ProjectID, db.TemplateObject, template)
return newTemplate.(db.Template), err
}
func (d *BoltDb) UpdateTemplate(template db.Template) error {
return d.updateObject(template.ProjectID, db.TemplateObject, template)
}
func (d *BoltDb) GetTemplates(projectID int, params db.RetrieveQueryParams) (templates []db.Template, err error) {
err = d.getObjects(projectID, db.TemplateObject, params, &templates)
return
}
func (d *BoltDb) GetTemplate(projectID int, templateID int) (template db.Template, err error) {
err = d.getObject(projectID, db.TemplateObject, templateID, &template)
return
}
func (d *BoltDb) DeleteTemplate(projectID int, templateID int) error {
return d.deleteObject(projectID, db.TemplateObject, templateID)
}