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 }