删除原有食物逻辑和模型
新增原料和营养价值表和原料库存日志和营养表定义
This commit is contained in:
@@ -167,9 +167,6 @@ func (ps *PostgresStorage) creatingHyperTable(ctx context.Context) error {
|
||||
{models.TaskExecutionLog{}, "created_at"},
|
||||
{models.PendingCollection{}, "created_at"},
|
||||
{models.UserActionLog{}, "time"},
|
||||
{models.RawMaterialPurchase{}, "purchase_date"},
|
||||
{models.RawMaterialStockLog{}, "happened_at"},
|
||||
{models.FeedUsageRecord{}, "recorded_at"},
|
||||
{models.MedicationLog{}, "happened_at"},
|
||||
{models.PigBatchLog{}, "happened_at"},
|
||||
{models.WeighingBatch{}, "weighing_time"},
|
||||
@@ -180,6 +177,7 @@ func (ps *PostgresStorage) creatingHyperTable(ctx context.Context) error {
|
||||
{models.PigSale{}, "sale_date"},
|
||||
{models.Notification{}, "alarm_timestamp"},
|
||||
{models.HistoricalAlarm{}, "trigger_time"},
|
||||
{models.RawMaterialStockLog{}, "happened_at"},
|
||||
}
|
||||
|
||||
for _, table := range tablesToConvert {
|
||||
@@ -210,9 +208,6 @@ func (ps *PostgresStorage) applyCompressionPolicies(ctx context.Context) error {
|
||||
{models.TaskExecutionLog{}, "task_id"},
|
||||
{models.PendingCollection{}, "device_id"},
|
||||
{models.UserActionLog{}, "user_id"},
|
||||
{models.RawMaterialPurchase{}, "raw_material_id"},
|
||||
{models.RawMaterialStockLog{}, "raw_material_id"},
|
||||
{models.FeedUsageRecord{}, "pen_id"},
|
||||
{models.MedicationLog{}, "pig_batch_id"},
|
||||
{models.PigBatchLog{}, "pig_batch_id"},
|
||||
{models.WeighingBatch{}, "pig_batch_id"},
|
||||
@@ -223,6 +218,7 @@ func (ps *PostgresStorage) applyCompressionPolicies(ctx context.Context) error {
|
||||
{models.PigSale{}, "pig_batch_id"},
|
||||
{models.Notification{}, "user_id"},
|
||||
{models.HistoricalAlarm{}, "source_id"},
|
||||
{models.RawMaterialStockLog{}, "raw_material_id"},
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
@@ -258,6 +254,15 @@ func (ps *PostgresStorage) creatingIndex(ctx context.Context) error {
|
||||
// 使用 IF NOT EXISTS 保证幂等性
|
||||
// 如果索引已存在,此命令不会报错
|
||||
|
||||
// 为 raw_material_nutrients 表创建部分唯一索引,以兼容软删除
|
||||
logger.Debug("正在为 raw_material_nutrients 表创建部分唯一索引")
|
||||
partialIndexSQL := "CREATE UNIQUE INDEX IF NOT EXISTS idx_raw_material_nutrients_unique_when_not_deleted ON raw_material_nutrients (raw_material_id, nutrient_id) WHERE deleted_at IS NULL;"
|
||||
if err := ps.db.WithContext(storageCtx).Exec(partialIndexSQL).Error; err != nil {
|
||||
logger.Errorw("为 raw_material_nutrients 创建部分唯一索引失败", "error", err)
|
||||
return fmt.Errorf("为 raw_material_nutrients 创建部分唯一索引失败: %w", err)
|
||||
}
|
||||
logger.Debug("成功为 raw_material_nutrients 创建部分唯一索引 (或已存在)")
|
||||
|
||||
// 为 sensor_data 表的 data 字段创建 GIN 索引
|
||||
logger.Debug("正在为 sensor_data 表的 data 字段创建 GIN 索引")
|
||||
ginSensorDataIndexSQL := "CREATE INDEX IF NOT EXISTS idx_sensor_data_data_gin ON sensor_data USING GIN (data);"
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
饲料和饲喂相关的模型
|
||||
*/
|
||||
|
||||
// RawMaterial 代表饲料的原料。
|
||||
// 建议:所有重量单位统一存储 (例如, 全部使用 'g'),便于计算和避免转换错误。
|
||||
type RawMaterial struct {
|
||||
Model
|
||||
Name string `gorm:"size:100;unique;not null;comment:原料名称"`
|
||||
Description string `gorm:"size:255;comment:描述"`
|
||||
Quantity float32 `gorm:"not null;comment:库存总量, 单位: g"`
|
||||
}
|
||||
|
||||
func (RawMaterial) TableName() string {
|
||||
return "raw_materials"
|
||||
}
|
||||
|
||||
// RawMaterialPurchase 记录了原料的每一次采购。
|
||||
type RawMaterialPurchase struct {
|
||||
Model
|
||||
RawMaterialID uint32 `gorm:"not null;index;comment:关联的原料ID"`
|
||||
RawMaterial RawMaterial `gorm:"foreignKey:RawMaterialID"`
|
||||
Supplier string `gorm:"size:100;comment:供应商"`
|
||||
Amount float32 `gorm:"not null;comment:采购数量, 单位: g"`
|
||||
UnitPrice float32 `gorm:"comment:单价"`
|
||||
TotalPrice float32 `gorm:"comment:总价"`
|
||||
PurchaseDate time.Time `gorm:"primaryKey;comment:采购日期"`
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
func (RawMaterialPurchase) TableName() string {
|
||||
return "raw_material_purchases"
|
||||
}
|
||||
|
||||
// StockLogSourceType 定义了库存日志来源的类型
|
||||
type StockLogSourceType string
|
||||
|
||||
const (
|
||||
StockLogSourcePurchase StockLogSourceType = "采购入库"
|
||||
StockLogSourceFeeding StockLogSourceType = "饲喂出库"
|
||||
StockLogSourceDeteriorate StockLogSourceType = "变质出库"
|
||||
StockLogSourceSale StockLogSourceType = "售卖出库"
|
||||
StockLogSourceMiscellaneous StockLogSourceType = "杂用领取"
|
||||
StockLogSourceManual StockLogSourceType = "手动盘点"
|
||||
)
|
||||
|
||||
// RawMaterialStockLog 记录了原料库存的所有变动,提供了完整的追溯链。
|
||||
type RawMaterialStockLog struct {
|
||||
Model
|
||||
RawMaterialID uint32 `gorm:"not null;index;comment:关联的原料ID"`
|
||||
ChangeAmount float32 `gorm:"not null;comment:变动数量, 正数为入库, 负数为出库"`
|
||||
SourceType StockLogSourceType `gorm:"size:50;not null;index;comment:库存变动来源类型"`
|
||||
SourceID uint32 `gorm:"not null;index;comment:来源记录的ID (如 RawMaterialPurchase.ID 或 FeedUsageRecord.ID)"`
|
||||
HappenedAt time.Time `gorm:"primaryKey;comment:业务发生时间"`
|
||||
Remarks string `gorm:"comment:备注, 如主动领取的理由等"`
|
||||
}
|
||||
|
||||
func (RawMaterialStockLog) TableName() string {
|
||||
return "raw_material_stock_logs"
|
||||
}
|
||||
|
||||
// FeedFormula 代表饲料配方。
|
||||
// 对于没有配方的外购饲料,可以将其视为一种特殊的 RawMaterial, 并为其创建一个仅包含它自己的 FeedFormula。
|
||||
type FeedFormula struct {
|
||||
Model
|
||||
Name string `gorm:"size:100;unique;not null;comment:配方名称"`
|
||||
Description string `gorm:"size:255;comment:描述"`
|
||||
Components []FeedFormulaComponent `gorm:"foreignKey:FeedFormulaID"`
|
||||
}
|
||||
|
||||
func (FeedFormula) TableName() string {
|
||||
return "feed_formulas"
|
||||
}
|
||||
|
||||
// FeedFormulaComponent 代表配方中的一种原料及其占比。
|
||||
type FeedFormulaComponent struct {
|
||||
Model
|
||||
FeedFormulaID uint32 `gorm:"not null;index;comment:外键到 FeedFormula"`
|
||||
RawMaterialID uint32 `gorm:"not null;index;comment:外键到 RawMaterial"`
|
||||
RawMaterial RawMaterial `gorm:"foreignKey:RawMaterialID"`
|
||||
Percentage float32 `gorm:"not null;comment:该原料在配方中的百分比 (0-1.0)"`
|
||||
}
|
||||
|
||||
func (FeedFormulaComponent) TableName() string {
|
||||
return "feed_formula_components"
|
||||
}
|
||||
|
||||
// FeedUsageRecord 代表饲料使用记录。
|
||||
// 应用层逻辑:当一条使用记录被创建时,应根据其使用的 FeedFormula,
|
||||
// 计算出每种 RawMaterial 的消耗量,并在 RawMaterialStockLog 中创建对应的出库记录。
|
||||
type FeedUsageRecord struct {
|
||||
Model
|
||||
PenID uint32 `gorm:"not null;index;comment:关联的猪栏ID"`
|
||||
Pen Pen `gorm:"foreignKey:PenID"`
|
||||
FeedFormulaID uint32 `gorm:"not null;index;comment:使用的饲料配方ID"`
|
||||
FeedFormula FeedFormula `gorm:"foreignKey:FeedFormulaID"`
|
||||
Amount float32 `gorm:"not null;comment:使用数量, 单位: g"`
|
||||
RecordedAt time.Time `gorm:"primaryKey;comment:记录时间"`
|
||||
OperatorID uint32 `gorm:"not null;comment:操作员"`
|
||||
Remarks string `gorm:"comment:备注, 如 '例行喂料, 弱猪补料' 等"`
|
||||
}
|
||||
|
||||
func (FeedUsageRecord) TableName() string {
|
||||
return "feed_usage_records"
|
||||
}
|
||||
@@ -63,11 +63,9 @@ func GetAllModels() []interface{} {
|
||||
|
||||
// Feed Models
|
||||
&RawMaterial{},
|
||||
&RawMaterialPurchase{},
|
||||
&Nutrient{},
|
||||
&RawMaterialNutrient{},
|
||||
&RawMaterialStockLog{},
|
||||
&FeedFormula{},
|
||||
&FeedFormulaComponent{},
|
||||
&FeedUsageRecord{},
|
||||
|
||||
// Medication Models
|
||||
&Medication{},
|
||||
|
||||
92
internal/infra/models/raw_material.go
Normal file
92
internal/infra/models/raw_material.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// StockLogSourceType 定义了库存日志来源的类型
|
||||
type StockLogSourceType string
|
||||
|
||||
const (
|
||||
StockLogSourcePurchase StockLogSourceType = "采购入库"
|
||||
StockLogSourceFeeding StockLogSourceType = "饲喂出库"
|
||||
StockLogSourceDeteriorate StockLogSourceType = "变质出库"
|
||||
StockLogSourceSale StockLogSourceType = "售卖出库"
|
||||
StockLogSourceMiscellaneous StockLogSourceType = "杂用领取"
|
||||
StockLogSourceManual StockLogSourceType = "手动盘点"
|
||||
StockLogSourceFermentStart StockLogSourceType = "发酵出库" // 原料投入发酵,从库存中扣除
|
||||
StockLogSourceFermentEnd StockLogSourceType = "发酵入库" // 发酵料产出,作为新原料计入库存
|
||||
)
|
||||
|
||||
// NutrientType 定义了营养素的分类,用于配方优化和成本控制。
|
||||
type NutrientType string
|
||||
|
||||
const (
|
||||
PositiveNutrient NutrientType = "正面营养" // 希望在配方中最大化的营养素,如蛋白质、能量
|
||||
NegativeNutrient NutrientType = "负面营养" // 需要控制上限的营养素,如粗纤维、霉菌毒素
|
||||
)
|
||||
|
||||
// RawMaterial 代表一种原料的静态定义,是系统中的原料字典。
|
||||
type RawMaterial struct {
|
||||
Model
|
||||
Name string `gorm:"size:100;unique;not null;comment:原料名称"`
|
||||
Description string `gorm:"size:255;comment:描述"`
|
||||
// Quantity 是当前库存的快照值,用于提供高性能的库存查询。
|
||||
// 注意:此字段的值必须在数据库事务中与 RawMaterialStockLog 同步更新,以保证数据一致性。
|
||||
Quantity float32 `gorm:"not null;default:0;comment:当前库存快照, 单位: g"`
|
||||
}
|
||||
|
||||
func (RawMaterial) TableName() string {
|
||||
return "raw_materials"
|
||||
}
|
||||
|
||||
// Nutrient 代表一种营养素的静态定义,是系统中的营养素字典。
|
||||
// 注意:本系统强制统一营养单位,不再单独设置Unit字段。
|
||||
// 约定:宏量营养素(粗蛋白等)单位为百分比(%),微量元素(氨基酸等)单位为毫克/千克(mg/kg)。
|
||||
type Nutrient struct {
|
||||
Model
|
||||
Name string `gorm:"size:100;unique;not null;comment:营养素名称"`
|
||||
Type NutrientType `gorm:"size:50;not null;comment:营养素类型 (正面营养/负面营养)"`
|
||||
Description string `gorm:"size:255;comment:描述"`
|
||||
}
|
||||
|
||||
func (Nutrient) TableName() string {
|
||||
return "nutrients"
|
||||
}
|
||||
|
||||
// RawMaterialNutrient 存储了特定原料的特定营养素的含量值。
|
||||
// 这是连接原料和营养素的“营养价值表”。
|
||||
// 注意:其唯一性由 postgres.go 中的部分唯一索引保证,以兼容软删除。
|
||||
type RawMaterialNutrient struct {
|
||||
Model
|
||||
RawMaterialID uint32 `gorm:"not null;comment:关联的原料ID"`
|
||||
RawMaterial RawMaterial `gorm:"foreignKey:RawMaterialID"`
|
||||
NutrientID uint32 `gorm:"not null;comment:关联的营养素ID"`
|
||||
Nutrient Nutrient `gorm:"foreignKey:NutrientID"`
|
||||
// Value 存储营养价值含量。单位遵循 Nutrient 表中定义的系统级约定。
|
||||
Value float32 `gorm:"not null;comment:营养价值含量"`
|
||||
}
|
||||
|
||||
func (RawMaterialNutrient) TableName() string {
|
||||
return "raw_material_nutrients"
|
||||
}
|
||||
|
||||
// RawMaterialStockLog 记录了原料库存的所有变动,提供了完整的追溯链。
|
||||
// 它是保证数据一致性和可审计性的核心。
|
||||
type RawMaterialStockLog struct {
|
||||
Model
|
||||
RawMaterialID uint32 `gorm:"not null;index;comment:关联的原料ID"`
|
||||
RawMaterial RawMaterial `gorm:"foreignKey:RawMaterialID"`
|
||||
ChangeAmount float32 `gorm:"not null;comment:变动数量, 正数为入库, 负数为出库, 单位: g"`
|
||||
// SourceType 告知 SourceID 关联的是哪种类型的业务单据。
|
||||
SourceType StockLogSourceType `gorm:"size:50;not null;index;comment:库存变动来源类型"`
|
||||
// SourceID 是一个多态外键,关联到触发此次变动的业务单据ID (如采购单ID)。
|
||||
// 对于无单据的业务(如手动盘点),此字段可为NULL。
|
||||
SourceID *uint32 `gorm:"index;comment:来源业务单据的ID"`
|
||||
HappenedAt time.Time `gorm:"primaryKey;comment:业务发生时间"`
|
||||
Remarks string `gorm:"comment:备注"`
|
||||
}
|
||||
|
||||
func (RawMaterialStockLog) TableName() string {
|
||||
return "raw_material_stock_logs"
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// RawMaterialPurchaseListOptions 定义了查询原料采购记录时的可选参数
|
||||
type RawMaterialPurchaseListOptions struct {
|
||||
RawMaterialID *uint32
|
||||
Supplier *string
|
||||
StartTime *time.Time // 基于 purchase_date 字段
|
||||
EndTime *time.Time // 基于 purchase_date 字段
|
||||
OrderBy string // 例如 "purchase_date asc"
|
||||
}
|
||||
|
||||
// RawMaterialStockLogListOptions 定义了查询原料库存日志时的可选参数
|
||||
type RawMaterialStockLogListOptions struct {
|
||||
RawMaterialID *uint32
|
||||
SourceType *models.StockLogSourceType
|
||||
SourceID *uint32
|
||||
StartTime *time.Time // 基于 happened_at 字段
|
||||
EndTime *time.Time // 基于 happened_at 字段
|
||||
OrderBy string // 例如 "happened_at asc"
|
||||
}
|
||||
|
||||
// FeedUsageRecordListOptions 定义了查询饲料使用记录时的可选参数
|
||||
type FeedUsageRecordListOptions struct {
|
||||
PenID *uint32
|
||||
FeedFormulaID *uint32
|
||||
OperatorID *uint32
|
||||
StartTime *time.Time // 基于 recorded_at 字段
|
||||
EndTime *time.Time // 基于 recorded_at 字段
|
||||
OrderBy string // 例如 "recorded_at asc"
|
||||
}
|
||||
|
||||
// RawMaterialRepository 定义了与原料相关的数据库操作接口
|
||||
type RawMaterialRepository interface {
|
||||
ListRawMaterialPurchases(ctx context.Context, opts RawMaterialPurchaseListOptions, page, pageSize int) ([]models.RawMaterialPurchase, int64, error)
|
||||
ListRawMaterialStockLogs(ctx context.Context, opts RawMaterialStockLogListOptions, page, pageSize int) ([]models.RawMaterialStockLog, int64, error)
|
||||
ListFeedUsageRecords(ctx context.Context, opts FeedUsageRecordListOptions, page, pageSize int) ([]models.FeedUsageRecord, int64, error)
|
||||
}
|
||||
|
||||
// gormRawMaterialRepository 是 RawMaterialRepository 的 GORM 实现
|
||||
type gormRawMaterialRepository struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewGormRawMaterialRepository 创建一个新的 RawMaterialRepository GORM 实现实例
|
||||
func NewGormRawMaterialRepository(ctx context.Context, db *gorm.DB) RawMaterialRepository {
|
||||
return &gormRawMaterialRepository{ctx: ctx, db: db}
|
||||
}
|
||||
|
||||
// ListRawMaterialPurchases 实现了分页和过滤查询原料采购记录的功能
|
||||
func (r *gormRawMaterialRepository) ListRawMaterialPurchases(ctx context.Context, opts RawMaterialPurchaseListOptions, page, pageSize int) ([]models.RawMaterialPurchase, int64, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "ListRawMaterialPurchases")
|
||||
if page <= 0 || pageSize <= 0 {
|
||||
return nil, 0, ErrInvalidPagination
|
||||
}
|
||||
|
||||
var results []models.RawMaterialPurchase
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(repoCtx).Model(&models.RawMaterialPurchase{})
|
||||
|
||||
if opts.RawMaterialID != nil {
|
||||
query = query.Where("raw_material_id = ?", *opts.RawMaterialID)
|
||||
}
|
||||
if opts.Supplier != nil {
|
||||
query = query.Where("supplier LIKE ?", "%"+*opts.Supplier+"%")
|
||||
}
|
||||
if opts.StartTime != nil {
|
||||
query = query.Where("purchase_date >= ?", *opts.StartTime)
|
||||
}
|
||||
if opts.EndTime != nil {
|
||||
query = query.Where("purchase_date <= ?", *opts.EndTime)
|
||||
}
|
||||
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
orderBy := "purchase_date DESC"
|
||||
if opts.OrderBy != "" {
|
||||
orderBy = opts.OrderBy
|
||||
}
|
||||
query = query.Order(orderBy).Preload("RawMaterial")
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
err := query.Limit(pageSize).Offset(offset).Find(&results).Error
|
||||
|
||||
return results, total, err
|
||||
}
|
||||
|
||||
// ListRawMaterialStockLogs 实现了分页和过滤查询原料库存日志的功能
|
||||
func (r *gormRawMaterialRepository) ListRawMaterialStockLogs(ctx context.Context, opts RawMaterialStockLogListOptions, page, pageSize int) ([]models.RawMaterialStockLog, int64, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "ListRawMaterialStockLogs")
|
||||
if page <= 0 || pageSize <= 0 {
|
||||
return nil, 0, ErrInvalidPagination
|
||||
}
|
||||
|
||||
var results []models.RawMaterialStockLog
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(repoCtx).Model(&models.RawMaterialStockLog{})
|
||||
|
||||
if opts.RawMaterialID != nil {
|
||||
query = query.Where("raw_material_id = ?", *opts.RawMaterialID)
|
||||
}
|
||||
if opts.SourceType != nil {
|
||||
query = query.Where("source_type = ?", *opts.SourceType)
|
||||
}
|
||||
if opts.SourceID != nil {
|
||||
query = query.Where("source_id = ?", *opts.SourceID)
|
||||
}
|
||||
if opts.StartTime != nil {
|
||||
query = query.Where("happened_at >= ?", *opts.StartTime)
|
||||
}
|
||||
if opts.EndTime != nil {
|
||||
query = query.Where("happened_at <= ?", *opts.EndTime)
|
||||
}
|
||||
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
orderBy := "happened_at DESC"
|
||||
if opts.OrderBy != "" {
|
||||
orderBy = opts.OrderBy
|
||||
}
|
||||
query = query.Order(orderBy)
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
err := query.Limit(pageSize).Offset(offset).Find(&results).Error
|
||||
|
||||
return results, total, err
|
||||
}
|
||||
|
||||
// ListFeedUsageRecords 实现了分页和过滤查询饲料使用记录的功能
|
||||
func (r *gormRawMaterialRepository) ListFeedUsageRecords(ctx context.Context, opts FeedUsageRecordListOptions, page, pageSize int) ([]models.FeedUsageRecord, int64, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "ListFeedUsageRecords")
|
||||
if page <= 0 || pageSize <= 0 {
|
||||
return nil, 0, ErrInvalidPagination
|
||||
}
|
||||
|
||||
var results []models.FeedUsageRecord
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(repoCtx).Model(&models.FeedUsageRecord{})
|
||||
|
||||
if opts.PenID != nil {
|
||||
query = query.Where("pen_id = ?", *opts.PenID)
|
||||
}
|
||||
if opts.FeedFormulaID != nil {
|
||||
query = query.Where("feed_formula_id = ?", *opts.FeedFormulaID)
|
||||
}
|
||||
if opts.OperatorID != nil {
|
||||
query = query.Where("operator_id = ?", *opts.OperatorID)
|
||||
}
|
||||
if opts.StartTime != nil {
|
||||
query = query.Where("recorded_at >= ?", *opts.StartTime)
|
||||
}
|
||||
if opts.EndTime != nil {
|
||||
query = query.Where("recorded_at <= ?", *opts.EndTime)
|
||||
}
|
||||
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
orderBy := "recorded_at DESC"
|
||||
if opts.OrderBy != "" {
|
||||
orderBy = opts.OrderBy
|
||||
}
|
||||
query = query.Order(orderBy).Preload("Pen").Preload("FeedFormula")
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
err := query.Limit(pageSize).Offset(offset).Find(&results).Error
|
||||
|
||||
return results, total, err
|
||||
}
|
||||
Reference in New Issue
Block a user