Order & Sorting
This commit is contained in:
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
@@ -18,11 +19,17 @@ func (dbm *DBManager) Album(album *model.Album) (int64, error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) Albums() ([]*model.Album, int64, error) {
|
||||
func (dbm *DBManager) Albums(userID string, filters *model.AlbumFilter, page *model.Page, order *model.Order) ([]*model.Album, model.PageResponse, error) {
|
||||
// Initial User Filter
|
||||
tx := dbm.db.Session(&gorm.Session{}).Model(&model.Album{}).Where("user_id == ?", userID)
|
||||
|
||||
// Dynamically Generate Base Query
|
||||
tx, pageResponse := dbm.generateBaseQuery(tx, filters, page, order)
|
||||
|
||||
// Acquire Results
|
||||
var foundAlbums []*model.Album
|
||||
var count int64
|
||||
err := dbm.db.Find(&foundAlbums).Count(&count).Error
|
||||
return foundAlbums, count, err
|
||||
err := tx.Find(&foundAlbums).Error
|
||||
return foundAlbums, pageResponse, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) DeleteAlbum(album *model.Album) error {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
|
||||
"github.com/iancoleman/strcase"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
// "gorm.io/gorm/logger"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
@@ -30,6 +32,7 @@ func NewMgr(c *config.Config) *DBManager {
|
||||
if c.DBType == "SQLite" {
|
||||
dbLocation := path.Join(c.ConfigPath, "imagini.db")
|
||||
dbm.db, _ = gorm.Open(sqlite.Open(dbLocation), gormConfig)
|
||||
dbm.db = dbm.db.Debug()
|
||||
} else {
|
||||
log.Fatal("Unsupported Database")
|
||||
}
|
||||
@@ -48,28 +51,9 @@ func NewMgr(c *config.Config) *DBManager {
|
||||
dbm.bootstrapDatabase()
|
||||
}
|
||||
|
||||
dbm.testFeatures()
|
||||
|
||||
return dbm
|
||||
}
|
||||
|
||||
func (dbm *DBManager) testFeatures() {
|
||||
|
||||
// Get Devices By UserID
|
||||
// var myDevices []model.Device
|
||||
// dbm.db.Debug().Where(&model.Device{UserID: "97589354-cd42-40e2-bc5e-7ba6badf89fa"}).Find(&myDevices)
|
||||
// fmt.Printf("Devices: %+v\n", myDevices)
|
||||
|
||||
// Get User by DeviceID
|
||||
// var myUser []model.User
|
||||
// dbm.db.Debug().Model(&model.User{}).
|
||||
// Select("users.*").
|
||||
// Joins("left join devices on users.id = devices.user_id").
|
||||
// Where("devices.id = ?", "4e9aa851-f25b-4330-91dc-c0f975e56fa1").
|
||||
// Find(&myUser)
|
||||
// fmt.Printf("User: %+v\n", myUser)
|
||||
}
|
||||
|
||||
func (dbm *DBManager) bootstrapDatabase() {
|
||||
log.Info("[query] Bootstrapping database.")
|
||||
|
||||
@@ -88,46 +72,84 @@ func (dbm *DBManager) bootstrapDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
func (dbm *DBManager) QueryBuilder(dest interface{}, params []byte) (int64, error) {
|
||||
// TODO:
|
||||
// - Where Filters
|
||||
// - Sort Filters
|
||||
// - Paging Filters
|
||||
func (dbm *DBManager) generateBaseQuery(tx *gorm.DB, filter interface{}, page *model.Page, order *model.Order) (*gorm.DB, model.PageResponse) {
|
||||
tx = dbm.generateFilter(tx, filter)
|
||||
tx = dbm.generateOrder(tx, order, filter)
|
||||
tx, pageResponse := dbm.generatePage(tx, page)
|
||||
return tx, pageResponse
|
||||
}
|
||||
|
||||
objType := fmt.Sprintf("%T", dest)
|
||||
if objType == "*[]model.MediaItem" {
|
||||
// TODO: Validate MediaItem Type
|
||||
} else {
|
||||
// Return Error
|
||||
return 0, errors.New("Invalid type")
|
||||
func (dbm *DBManager) generateOrder(tx *gorm.DB, order *model.Order, filter interface{}) *gorm.DB {
|
||||
// Set Defaults
|
||||
orderBy := "created_at"
|
||||
orderDirection := model.OrderDirectionDesc
|
||||
|
||||
if order == nil {
|
||||
order = &model.Order{
|
||||
By: &orderBy,
|
||||
Direction: &orderDirection,
|
||||
}
|
||||
}
|
||||
|
||||
var count int64
|
||||
err := dbm.db.Find(dest).Count(&count).Error
|
||||
return count, err
|
||||
if order.By == nil {
|
||||
order.By = &orderBy
|
||||
}
|
||||
|
||||
// Paging:
|
||||
// - Regular Pagination:
|
||||
// - /api/v1/MediaItems?page[limit]=50&page=2
|
||||
// - Meta Count Only
|
||||
// - /api/v1/MediaItems?page[limit]=0
|
||||
if order.Direction == nil {
|
||||
order.Direction = &orderDirection
|
||||
}
|
||||
|
||||
// Sorting:
|
||||
// - Ascending Sort:
|
||||
// - /api/v1/MediaItems?sort=created_at
|
||||
// - Descending Sort:
|
||||
// - /api/v1/MediaItems?sort=-created_at
|
||||
// Get Possible Values
|
||||
ptr := reflect.New(reflect.TypeOf(filter).Elem())
|
||||
v := reflect.Indirect(ptr)
|
||||
|
||||
// Filters:
|
||||
// - Greater Than / Less Than (created_at, updated_at, exif_date)
|
||||
// - /api/v1/MediaItems?filter[created_at]>=2020-01-01&filter[created_at]<=2021-01-01
|
||||
// - Long / Lat Range (latitude, longitude)
|
||||
// - /api/v1/MediaItems?filter[latitude]>=71.1827&filter[latitude]<=72.0000&filter[longitude]>=100.000&filter[longitude]<=101.0000
|
||||
// - Image / Video (media_type)
|
||||
// - /api/v1/MediaItems?filter[media_type]=Image
|
||||
// - Tags (tags)
|
||||
// - /api/v1/MediaItems?filter[tags]=id1,id2,id3
|
||||
// - Albums (albums)
|
||||
// - /api/v1/MediaItems?filter[albums]=id1
|
||||
isValid := false
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fieldName := v.Type().Field(i).Name
|
||||
if strcase.ToSnake(*order.By) == strcase.ToSnake(fieldName) {
|
||||
isValid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isValid {
|
||||
tx = tx.Order(fmt.Sprintf("%s %s", strcase.ToSnake(*order.By), order.Direction.String()))
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
func (dbm *DBManager) generatePage(tx *gorm.DB, page *model.Page) (*gorm.DB, model.PageResponse) {
|
||||
// Set Defaults
|
||||
var count int64
|
||||
pageSize := 50
|
||||
pageNum := 1
|
||||
|
||||
if page == nil {
|
||||
page = &model.Page{
|
||||
Size: &pageSize,
|
||||
Page: &pageNum,
|
||||
}
|
||||
}
|
||||
|
||||
if page.Size == nil {
|
||||
page.Size = &pageSize
|
||||
}
|
||||
|
||||
if page.Page == nil {
|
||||
page.Page = &pageNum
|
||||
}
|
||||
|
||||
// Acquire Counts Before Pagination
|
||||
tx.Count(&count)
|
||||
|
||||
// Calculate Offset
|
||||
calculatedOffset := (*page.Page - 1) * *page.Size
|
||||
tx = tx.Limit(*page.Size).Offset(calculatedOffset)
|
||||
|
||||
return tx, model.PageResponse{
|
||||
Page: *page.Page,
|
||||
Size: *page.Size,
|
||||
Total: int(count),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
@@ -21,11 +22,17 @@ func (dbm *DBManager) Device(device *model.Device) (int64, error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) Devices() ([]*model.Device, int64, error) {
|
||||
func (dbm *DBManager) Devices(userID string, filters *model.DeviceFilter, page *model.Page, order *model.Order) ([]*model.Device, model.PageResponse, error) {
|
||||
// Initial User Filter
|
||||
tx := dbm.db.Session(&gorm.Session{}).Model(&model.Device{}).Where("user_id == ?", userID)
|
||||
|
||||
// Dynamically Generate Base Query
|
||||
tx, pageResponse := dbm.generateBaseQuery(tx, filters, page, order)
|
||||
|
||||
// Acquire Results
|
||||
var foundDevices []*model.Device
|
||||
var count int64
|
||||
err := dbm.db.Find(&foundDevices).Count(&count).Error
|
||||
return foundDevices, count, err
|
||||
err := tx.Find(&foundDevices).Error
|
||||
return foundDevices, pageResponse, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) DeleteDevice(user *model.Device) error {
|
||||
|
||||
@@ -10,10 +10,13 @@ import (
|
||||
)
|
||||
|
||||
// Generic function used to generate filters for the DB
|
||||
func (dbm *DBManager) generateFilters(filter interface{}) (*gorm.DB, error) {
|
||||
tx := dbm.db.Session(&gorm.Session{}).Debug()
|
||||
func (dbm *DBManager) generateFilter(tx *gorm.DB, filter interface{}) *gorm.DB {
|
||||
ptr := reflect.ValueOf(filter)
|
||||
v := reflect.Indirect(ptr)
|
||||
|
||||
v := reflect.ValueOf(filter)
|
||||
if v == reflect.ValueOf(nil) {
|
||||
return tx
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fieldName := strcase.ToSnake(v.Type().Field(i).Name)
|
||||
@@ -45,7 +48,7 @@ func (dbm *DBManager) generateFilters(filter interface{}) (*gorm.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return tx, nil
|
||||
return tx
|
||||
}
|
||||
|
||||
func generateStringFilter(tx *gorm.DB, fieldName string, filter *model.StringFilter) *gorm.DB {
|
||||
|
||||
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
@@ -18,14 +19,16 @@ func (dbm *DBManager) MediaItem(mediaItem *model.MediaItem) (int64, error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) MediaItems(filters *model.MediaItemFilter) ([]*model.MediaItem, int64, error) {
|
||||
// Perform Filters
|
||||
tx, err := dbm.generateFilters(*filters)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// UserID, Filters, Sort, Page, Delete
|
||||
func (dbm *DBManager) MediaItems(userID string, filters *model.MediaItemFilter, page *model.Page, order *model.Order) ([]*model.MediaItem, model.PageResponse, error) {
|
||||
// Initial User Filter
|
||||
tx := dbm.db.Session(&gorm.Session{}).Model(&model.MediaItem{}).Where("user_id == ?", userID)
|
||||
|
||||
// Dynamically Generate Base Query
|
||||
tx, pageResponse := dbm.generateBaseQuery(tx, filters, page, order)
|
||||
|
||||
// Acquire Results
|
||||
var mediaItems []*model.MediaItem
|
||||
var count int64
|
||||
err = tx.Find(&mediaItems).Count(&count).Error
|
||||
return mediaItems, count, err
|
||||
err := tx.Find(&mediaItems).Error
|
||||
return mediaItems, pageResponse, err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
@@ -18,11 +19,17 @@ func (dbm *DBManager) Tag(tag *model.Tag) (int64, error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) Tags() ([]*model.Tag, int64, error) {
|
||||
func (dbm *DBManager) Tags(userID string, filters *model.TagFilter, page *model.Page, order *model.Order) ([]*model.Tag, model.PageResponse, error) {
|
||||
// Initial User Filter
|
||||
tx := dbm.db.Session(&gorm.Session{}).Model(&model.Tag{}).Where("user_id == ?", userID)
|
||||
|
||||
// Dynamically Generate Base Query
|
||||
tx, pageResponse := dbm.generateBaseQuery(tx, filters, page, order)
|
||||
|
||||
// Acquire Results
|
||||
var foundTags []*model.Tag
|
||||
var count int64
|
||||
err := dbm.db.Find(&foundTags).Count(&count).Error
|
||||
return foundTags, count, err
|
||||
err := tx.Find(&foundTags).Error
|
||||
return foundTags, pageResponse, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) DeleteTag(tag *model.Tag) error {
|
||||
|
||||
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
@@ -25,11 +26,17 @@ func (dbm *DBManager) User(user *model.User) (int64, error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) Users() ([]*model.User, int64, error) {
|
||||
func (dbm *DBManager) Users(filters *model.UserFilter, page *model.Page, order *model.Order) ([]*model.User, model.PageResponse, error) {
|
||||
// Initial User Filter
|
||||
tx := dbm.db.Session(&gorm.Session{}).Model(&model.Tag{})
|
||||
|
||||
// Dynamically Generate Base Query
|
||||
tx, pageResponse := dbm.generateBaseQuery(tx, filters, page, order)
|
||||
|
||||
// Acquire Results
|
||||
var foundUsers []*model.User
|
||||
var count int64
|
||||
err := dbm.db.Find(&foundUsers).Count(&count).Error
|
||||
return foundUsers, count, err
|
||||
err := tx.Find(&foundUsers).Error
|
||||
return foundUsers, pageResponse, err
|
||||
}
|
||||
|
||||
func (dbm *DBManager) DeleteUser(user model.User) error {
|
||||
|
||||
Reference in New Issue
Block a user