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  }