github.com/openimsdk/tools@v0.0.49/db/mongoutil/uril.go (about) 1 // Copyright © 2024 OpenIM open source community. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mongoutil 16 17 import ( 18 "context" 19 20 "github.com/openimsdk/tools/db/pagination" 21 "github.com/openimsdk/tools/errs" 22 "go.mongodb.org/mongo-driver/mongo" 23 "go.mongodb.org/mongo-driver/mongo/options" 24 ) 25 26 func basic[T any]() bool { 27 var t T 28 switch any(t).(type) { 29 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string, []byte: 30 return true 31 case *int, *int8, *int16, *int32, *int64, *uint, *uint8, *uint16, *uint32, *uint64, *float32, *float64, *string, *[]byte: 32 return true 33 default: 34 return false 35 } 36 } 37 38 func anes[T any](ts []T) []any { 39 val := make([]any, len(ts)) 40 for i := range ts { 41 val[i] = ts[i] 42 } 43 return val 44 } 45 46 func findOptionToCountOption(opts []*options.FindOptions) *options.CountOptions { 47 return options.Count() 48 } 49 50 func InsertMany[T any](ctx context.Context, coll *mongo.Collection, val []T, opts ...*options.InsertManyOptions) error { 51 _, err := coll.InsertMany(ctx, anes(val), opts...) 52 if err != nil { 53 return errs.WrapMsg(err, "mongo insert many") 54 } 55 return nil 56 } 57 58 func UpdateOne(ctx context.Context, coll *mongo.Collection, filter any, update any, notMatchedErr bool, opts ...*options.UpdateOptions) error { 59 res, err := coll.UpdateOne(ctx, filter, update, opts...) 60 if err != nil { 61 return errs.WrapMsg(err, "mongo update one") 62 } 63 if notMatchedErr && res.MatchedCount == 0 { 64 return errs.WrapMsg(mongo.ErrNoDocuments, "mongo update not matched") 65 } 66 return nil 67 } 68 69 func UpdateOneResult(ctx context.Context, coll *mongo.Collection, filter any, update any, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { 70 res, err := coll.UpdateOne(ctx, filter, update, opts...) 71 if err != nil { 72 return nil, errs.WrapMsg(err, "mongo update one") 73 } 74 return res, nil 75 } 76 77 func UpdateMany(ctx context.Context, coll *mongo.Collection, filter any, update any, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { 78 res, err := coll.UpdateMany(ctx, filter, update, opts...) 79 if err != nil { 80 return nil, errs.WrapMsg(err, "mongo update many") 81 } 82 return res, nil 83 } 84 85 func Find[T any](ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.FindOptions) ([]T, error) { 86 cur, err := coll.Find(ctx, filter, opts...) 87 if err != nil { 88 return nil, errs.WrapMsg(err, "mongo find") 89 } 90 defer cur.Close(ctx) 91 return Decodes[T](ctx, cur) 92 } 93 94 func FindOne[T any](ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.FindOneOptions) (res T, err error) { 95 cur := coll.FindOne(ctx, filter, opts...) 96 if err := cur.Err(); err != nil { 97 return res, errs.WrapMsg(err, "mongo find one") 98 } 99 return DecodeOne[T](cur.Decode) 100 } 101 102 func FindOneAndUpdate[T any](ctx context.Context, coll *mongo.Collection, filter any, update any, opts ...*options.FindOneAndUpdateOptions) (res T, err error) { 103 result := coll.FindOneAndUpdate(ctx, filter, update, opts...) 104 if err := result.Err(); err != nil { 105 return res, errs.WrapMsg(err, "mongo find one and update") 106 } 107 return DecodeOne[T](result.Decode) 108 } 109 110 func FindPage[T any](ctx context.Context, coll *mongo.Collection, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) (int64, []T, error) { 111 count, err := Count(ctx, coll, filter, findOptionToCountOption(opts)) 112 if err != nil { 113 return 0, nil, errs.WrapMsg(err, "mongo failed to count documents in collection") 114 } 115 if count == 0 || pagination == nil { 116 return count, nil, nil 117 } 118 skip := int64(pagination.GetPageNumber()-1) * int64(pagination.GetShowNumber()) 119 if skip < 0 || skip >= count || pagination.GetShowNumber() <= 0 { 120 return count, nil, nil 121 } 122 opt := options.Find().SetSkip(skip).SetLimit(int64(pagination.GetShowNumber())) 123 res, err := Find[T](ctx, coll, filter, append(opts, opt)...) 124 if err != nil { 125 return 0, nil, err 126 } 127 return count, res, nil 128 } 129 130 func FindPageOnly[T any](ctx context.Context, coll *mongo.Collection, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) ([]T, error) { 131 skip := int64(pagination.GetPageNumber()-1) * int64(pagination.GetShowNumber()) 132 if skip < 0 || pagination.GetShowNumber() <= 0 { 133 return nil, nil 134 } 135 opt := options.Find().SetSkip(skip).SetLimit(int64(pagination.GetShowNumber())) 136 return Find[T](ctx, coll, filter, append(opts, opt)...) 137 } 138 139 func Count(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.CountOptions) (int64, error) { 140 count, err := coll.CountDocuments(ctx, filter, opts...) 141 if err != nil { 142 return 0, errs.WrapMsg(err, "mongo count") 143 } 144 return count, nil 145 } 146 147 func Exist(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.CountOptions) (bool, error) { 148 opts = append(opts, options.Count().SetLimit(1)) 149 count, err := Count(ctx, coll, filter, opts...) 150 if err != nil { 151 return false, err 152 } 153 return count > 0, nil 154 } 155 156 func DeleteOne(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) error { 157 if _, err := coll.DeleteOne(ctx, filter, opts...); err != nil { 158 return errs.WrapMsg(err, "mongo delete one") 159 } 160 return nil 161 } 162 163 func DeleteOneResult(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { 164 res, err := coll.DeleteOne(ctx, filter, opts...) 165 if err != nil { 166 return nil, errs.WrapMsg(err, "mongo delete one") 167 } 168 return res, nil 169 } 170 171 func DeleteMany(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) error { 172 if _, err := coll.DeleteMany(ctx, filter, opts...); err != nil { 173 return errs.WrapMsg(err, "mongo delete many") 174 } 175 return nil 176 } 177 178 func DeleteManyResult(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { 179 res, err := coll.DeleteMany(ctx, filter, opts...) 180 if err != nil { 181 return nil, errs.WrapMsg(err, "mongo delete many") 182 } 183 return res, nil 184 } 185 186 func Aggregate[T any](ctx context.Context, coll *mongo.Collection, pipeline any, opts ...*options.AggregateOptions) ([]T, error) { 187 cur, err := coll.Aggregate(ctx, pipeline, opts...) 188 if err != nil { 189 return nil, errs.WrapMsg(err, "mongo aggregate") 190 } 191 defer cur.Close(ctx) 192 return Decodes[T](ctx, cur) 193 } 194 195 func Decodes[T any](ctx context.Context, cur *mongo.Cursor) ([]T, error) { 196 var res []T 197 if basic[T]() { 198 var temp []map[string]T 199 if err := cur.All(ctx, &temp); err != nil { 200 return nil, errs.WrapMsg(err, "mongo decodes") 201 } 202 res = make([]T, 0, len(temp)) 203 for _, m := range temp { 204 if len(m) != 1 { 205 return nil, errs.ErrInternalServer.WrapMsg("mongo find result len(m) != 1") 206 } 207 for _, t := range m { 208 res = append(res, t) 209 } 210 } 211 } else { 212 if err := cur.All(ctx, &res); err != nil { 213 return nil, errs.WrapMsg(err, "mongo all") 214 } 215 } 216 return res, nil 217 } 218 219 func DecodeOne[T any](decoder func(v any) error) (res T, err error) { 220 if basic[T]() { 221 var temp map[string]T 222 if err = decoder(&temp); err != nil { 223 err = errs.WrapMsg(err, "mongo decodes one") 224 return 225 } 226 if len(temp) != 1 { 227 err = errs.ErrInternalServer.WrapMsg("mongo find result len(m) != 1") 228 return 229 } 230 for k := range temp { 231 res = temp[k] 232 } 233 } else { 234 if err = decoder(&res); err != nil { 235 err = errs.WrapMsg(err, "mongo decoder") 236 return 237 } 238 } 239 return 240 } 241 242 func Ignore[T any](_ T, err error) error { 243 return err 244 } 245 246 func IgnoreWarp[T any](_ T, err error) error { 247 if err != nil { 248 return errs.Wrap(err) 249 } 250 return err 251 } 252 253 func IncrVersion(dbs ...func() error) error { 254 for _, fn := range dbs { 255 if err := fn(); err != nil { 256 return err 257 } 258 } 259 return nil 260 }