2023-11-09 09:26:46 +01:00
package wmo
import (
"context"
"errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
)
func ( c * Coll [ TData ] ) FindOne ( ctx context . Context , filter bson . M ) ( TData , error ) {
r , err := c . findOneInternal ( ctx , filter , false )
if err != nil {
return * new ( TData ) , exerr . Wrap ( err , "mongo-query[find-one] failed" ) . Str ( "collection" , c . Name ( ) ) . Build ( )
}
return * r , nil
}
func ( c * Coll [ TData ] ) FindOneOpt ( ctx context . Context , filter bson . M ) ( * TData , error ) {
r , err := c . findOneInternal ( ctx , filter , true )
if err != nil {
return nil , exerr . Wrap ( err , "mongo-query[find-one-opt] failed" ) . Str ( "collection" , c . Name ( ) ) . Build ( )
}
return r , nil
}
func ( c * Coll [ TData ] ) FindOneByID ( ctx context . Context , id EntityID ) ( TData , error ) {
r , err := c . findOneInternal ( ctx , bson . M { "_id" : id } , false )
if err != nil {
return * new ( TData ) , exerr . Wrap ( err , "mongo-query[find-one-by-id] failed" ) . Id ( "id" , id ) . Str ( "collection" , c . Name ( ) ) . Build ( )
}
return * r , nil
}
func ( c * Coll [ TData ] ) FindOneOptByID ( ctx context . Context , id EntityID ) ( * TData , error ) {
r , err := c . findOneInternal ( ctx , bson . M { "_id" : id } , true )
if err != nil {
return nil , exerr . Wrap ( err , "mongo-query[find-one-opt-by-id] failed" ) . Id ( "id" , id ) . Str ( "collection" , c . Name ( ) ) . Build ( )
}
return r , nil
}
func ( c * Coll [ TData ] ) findOneInternal ( ctx context . Context , filter bson . M , allowNull bool ) ( * TData , error ) {
if len ( c . extraModPipeline ) == 0 {
// simple case, use mongo FindOne
mongoRes := c . coll . FindOne ( ctx , filter )
res , err := c . decodeSingle ( ctx , mongoRes )
if allowNull && errors . Is ( err , mongo . ErrNoDocuments ) {
return nil , nil
}
if err != nil {
2023-11-14 16:00:14 +01:00
return nil , exerr . Wrap ( err , "mongo-query[find-one] failed" ) . Any ( "filter" , filter ) . Str ( "collection" , c . Name ( ) ) . NoLog ( ) . Build ( )
2023-11-09 09:26:46 +01:00
}
return & res , nil
} else {
// complex case, we one ore more additional pipeline stages, convert to aggregation
pipeline := mongo . Pipeline { }
pipeline = append ( pipeline , bson . D { { Key : "$match" , Value : filter } } )
pipeline = append ( pipeline , bson . D { { Key : "$limit" , Value : 1 } } )
2024-01-09 08:51:46 +01:00
for _ , ppl := range c . extraModPipeline {
pipeline = langext . ArrConcat ( pipeline , ppl ( ctx ) )
}
2023-11-09 09:26:46 +01:00
cursor , err := c . coll . Aggregate ( ctx , pipeline )
if err != nil {
2023-11-14 16:00:14 +01:00
return nil , exerr . Wrap ( err , "mongo-aggregation [find-one] failed" ) . Any ( "pipeline" , pipeline ) . Str ( "collection" , c . Name ( ) ) . NoLog ( ) . Build ( )
2023-11-09 09:26:46 +01:00
}
2024-06-28 18:37:02 +02:00
defer func ( ) { _ = cursor . Close ( ctx ) } ( )
2023-11-09 09:26:46 +01:00
if cursor . Next ( ctx ) {
v , err := c . decodeSingle ( ctx , cursor )
if err != nil {
2023-11-14 16:00:14 +01:00
return nil , exerr . Wrap ( err , "mongo-aggregation [find-one] failed to decode results" ) . Any ( "pipeline" , pipeline ) . Str ( "collection" , c . Name ( ) ) . NoLog ( ) . Build ( )
2023-11-09 09:26:46 +01:00
}
return & v , nil
} else if allowNull {
return nil , nil
} else {
2023-11-14 16:00:14 +01:00
return nil , exerr . Wrap ( mongo . ErrNoDocuments , "mongo-aggregation [find-one] returned no documents" ) . Any ( "pipeline" , pipeline ) . Str ( "collection" , c . Name ( ) ) . NoLog ( ) . Build ( )
2023-11-09 09:26:46 +01:00
}
}
}