@@ -0,0 +1,286 @@
|
||||
package officialwebsiteser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
officialwebsitemod "91porn-server/models/v/officialWebsitemod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
// List Helper Types and Functions
|
||||
// ─────────────────────────────────────────
|
||||
|
||||
// CountResp 通用操作返回
|
||||
type CountResp struct {
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// PageReq 分页请求
|
||||
type PageReq struct {
|
||||
Page int64 `form:"page"`
|
||||
PageSize int64 `form:"pageSize"`
|
||||
}
|
||||
|
||||
func (r *PageReq) FindOptions() *options.FindOptions {
|
||||
page := r.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := r.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
skip := (page - 1) * pageSize
|
||||
return options.Find().SetSkip(skip).SetLimit(pageSize).SetSort(officialwebsitemod.M{"createdAt": -1})
|
||||
}
|
||||
|
||||
func parseObjectIDFilter(filter officialwebsitemod.M, key string, raw *string) error {
|
||||
if raw == nil || *raw == "" {
|
||||
return nil
|
||||
}
|
||||
id, err := primitive.ObjectIDFromHex(*raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid %s: %w", key, err)
|
||||
}
|
||||
filter[key] = id
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseJSONFilter(filter officialwebsitemod.M, key string, raw *string, out interface{}) error {
|
||||
if raw == nil || *raw == "" {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal([]byte(*raw), out); err != nil {
|
||||
return fmt.Errorf("invalid %s json: %w", key, err)
|
||||
}
|
||||
v := reflect.ValueOf(out)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
filter[key] = v.Elem().Interface()
|
||||
return nil
|
||||
}
|
||||
filter[key] = out
|
||||
return nil
|
||||
}
|
||||
|
||||
// ─────���───────────────────────────────────
|
||||
// Update Helper Functions
|
||||
// ─────────────────────────────────────────
|
||||
|
||||
func modelToMap(doc interface{}) (officialwebsitemod.M, error) {
|
||||
raw, err := bson.Marshal(doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := officialwebsitemod.M{}
|
||||
if err := bson.Unmarshal(raw, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delete(data, "_id")
|
||||
delete(data, "createdAt")
|
||||
delete(data, "updatedAt")
|
||||
delete(data, "deletedAt")
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func modelChanged(oldDoc interface{}, newDoc interface{}) (bool, error) {
|
||||
oldMap, err := modelToMap(oldDoc)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
newMap, err := modelToMap(newDoc)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !reflect.DeepEqual(oldMap, newMap), nil
|
||||
}
|
||||
|
||||
func buildModelUpdateDoc(doc interface{}) (officialwebsitemod.M, error) {
|
||||
data, err := modelToMap(doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data["updatedAt"] = time.Now().UTC()
|
||||
return officialwebsitemod.M{"$set": data}, nil
|
||||
}
|
||||
|
||||
func buildPointerUpdateDoc(oldDoc interface{}, updateDoc interface{}) (officialwebsitemod.M, error) {
|
||||
oldVal, err := structValueOf(oldDoc, "old doc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newVal, err := structValueOf(updateDoc, "update doc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set := officialwebsitemod.M{}
|
||||
collectPointerChanges(set, oldVal, newVal)
|
||||
|
||||
if len(set) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
set["updatedAt"] = time.Now().UTC()
|
||||
return officialwebsitemod.M{"$set": set}, nil
|
||||
}
|
||||
|
||||
func structValueOf(doc interface{}, label string) (reflect.Value, error) {
|
||||
val := reflect.ValueOf(doc)
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
return reflect.Value{}, errors.New(label + " is nil")
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct {
|
||||
return reflect.Value{}, errors.New(label + " must be struct")
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func collectPointerChanges(set officialwebsitemod.M, oldVal reflect.Value, newVal reflect.Value) {
|
||||
newType := newVal.Type()
|
||||
for i := 0; i < newVal.NumField(); i++ {
|
||||
addPointerFieldChange(set, oldVal, newVal.Field(i), newType.Field(i))
|
||||
}
|
||||
}
|
||||
|
||||
func addPointerFieldChange(set officialwebsitemod.M, oldVal reflect.Value, newField reflect.Value, fieldInfo reflect.StructField) {
|
||||
if fieldInfo.Name == "ID" {
|
||||
return
|
||||
}
|
||||
if !newField.IsValid() || newField.Kind() != reflect.Ptr || newField.IsNil() {
|
||||
return
|
||||
}
|
||||
|
||||
oldField := findStructFieldByName(oldVal, fieldInfo.Name)
|
||||
if !oldField.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
newValue := derefValue(newField)
|
||||
oldValue := derefValue(oldField)
|
||||
if !newValue.IsValid() || !oldValue.IsValid() {
|
||||
return
|
||||
}
|
||||
if reflect.DeepEqual(oldValue.Interface(), newValue.Interface()) {
|
||||
return
|
||||
}
|
||||
|
||||
key := bsonFieldName(fieldInfo)
|
||||
if key == "" {
|
||||
return
|
||||
}
|
||||
set[key] = newValue.Interface()
|
||||
}
|
||||
|
||||
func findStructFieldByName(val reflect.Value, name string) reflect.Value {
|
||||
if !val.IsValid() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
if field := val.FieldByName(name); field.IsValid() {
|
||||
return field
|
||||
}
|
||||
|
||||
valType := val.Type()
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
fieldType := valType.Field(i)
|
||||
if !fieldType.Anonymous {
|
||||
continue
|
||||
}
|
||||
field := findStructFieldByName(val.Field(i), name)
|
||||
if field.IsValid() {
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
func derefValue(v reflect.Value) reflect.Value {
|
||||
for v.IsValid() && v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func bsonFieldName(field reflect.StructField) string {
|
||||
if tag := field.Tag.Get("bson"); tag != "" {
|
||||
name := strings.Split(tag, ",")[0]
|
||||
if name != "" && name != "-" {
|
||||
return name
|
||||
}
|
||||
}
|
||||
if tag := field.Tag.Get("json"); tag != "" {
|
||||
name := strings.Split(tag, ",")[0]
|
||||
if name != "" && name != "-" {
|
||||
return name
|
||||
}
|
||||
}
|
||||
return field.Name
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────
|
||||
// Pointer helpers
|
||||
// ─────────────────────────────────────────
|
||||
|
||||
func stringOrZero(v *string) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
||||
func intOrZero(v *int) int {
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
||||
func objectIDOrZero(v *primitive.ObjectID) primitive.ObjectID {
|
||||
if v == nil {
|
||||
return primitive.NilObjectID
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
||||
func int64OrZero(v *int64) int64 {
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
||||
func boolOrZero(v *bool) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
||||
func isNilObjectID(id primitive.ObjectID) bool {
|
||||
return id == primitive.NilObjectID
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user