modm

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 11, 2024 License: MIT Imports: 7 Imported by: 0

README

MODM

Go Report Card Go Go Reference GitHub Coverage Status

MODM is a MongoDB wrapper built on top of the mongo-go-driver, leveraging the powerful features of Go generics. It provides a convenient interface for CRUD operations, allowing direct return of structured data without the need for code generation.

Features

  • Structured Data for CRUD Operations: Directly return structured data from CRUD operations, providing a seamless development experience.

  • No Code Generation Required: Leverage Go 1.18's generics features to minimize code volume and enhance development efficiency.

  • Flexible Hooks: Support automated field updates, providing a more adaptable approach to data handling.

  • Easy-to-Use Index Management: Effortlessly create MongoDB indexes through code for streamlined management.

  • Simple Transactions: Simplify transaction usage, empowering developers to effortlessly employ MongoDB transactions.

Requirements

  • Go 1.18 and Above: MODM is designed to take full advantage of the features introduced in Go 1.18 and later versions.

Comparison with mongo-go-driver

When using mongodb, the typical approach is to define models and collections as follows:

type User struct {
	DefaultField `bson:",inline"`
	Name         string `bson:"name,omitempty" json:"name"`
	Age          int    `bson:"age,omitempty" json:"age"`
}

Subsequently, the query is executed using mongo-go-driver:

coll := db.Collection("users")
users := make([]*User, 0)
cursor, err := coll.Find(context.TODO(), bson.D{})
if err != nil {
	log.Fatal(err)
}
if err = cursor.All(context.TODO(), &users); err != nil {
	log.Fatal(err)
}

In contrast, using modm can greatly simplify the process:

coll := NewRepo[*User](db.Collection("users"))
users, err := coll.Find(context.TODO(), bson.D{})
if err != nil {
	log.Fatal(err)
}

Here, Find() returns []*User, error.

Performance tests show that the efficiency of the two methods is comparable.

Installation

go get github.com/miilord/modm

Getting Started

Connecting to the database

To use MODM, you only need to pass *mongo.Collection in mongo-go-driver, so MODM is compatible with all libraries based on the official driver, e.g. qmgo.

Below is an example of the official driver:

ctx := context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("your mongodb uri"))
if err != nil {
	panic(err)
}
defer client.Disconnect(ctx)
database := client.Database("test")
Importing MODM
type User struct {
	modm.DefaultField `bson:",inline"`
	Name              string `bson:"name,omitempty" json:"name"`
	Age               int    `bson:"age,omitempty" json:"age"`
}

type DB struct {
	Users *modm.Repo[*User]
}

func main() {
	...
	db := DB{
		Users: modm.NewRepo[*User](database.Collection("users")),
	}
	db.Users.InsertOne(ctx, &User{Name: "gooooo", Age: 6})

	// To query for documents containing zero values, use bson.M, bson.D, or a map.
	// Alternatively, consider using pointers for the appropriate fields.
	user, _ := db.Users.FindOne(ctx, &User{Name: "gooooo"})
	fmt.Println(user.Age) // 6

	// Find() returns ([]*User, error)
	users, _ := db.Users.Find(ctx, &User{Age: 6})
}

Contributions

Contributions are welcome! Feel free to open issues, submit pull requests, or provide suggestions to improve MODM.

License

MODM is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetPointer

func GetPointer[T any](value T) *T

GetPointer returns a pointer to the given value.

func IndexesToModel

func IndexesToModel(uniques []string, indexes []string) []mongo.IndexModel

Generate index models from unique and compound index definitions. If uniques/indexes is []string{"name"}, means create index "name" If uniques/indexes is []string{"name,-age","uid"}, means create compound indexes: name and -age, then create one index: uid

func IsDocumentExists added in v0.0.4

func IsDocumentExists(err error) (bool, error)

IsDocumentExists checks if a MongoDB FindOne/Find operation returned an error indicating the absence of documents. It returns true if documents are found, false if no documents are found, and any other error encountered during the operation. The function is designed to be used in conjunction with MongoDB FindOne/Find queries. Example:

_, err := db.Mongo.Account.FindOne(context.TODO(), filter)
exists, err := IsDocumentExists(err)
if err != nil {
    return err
}
if !exists {
    return fmt.Errorf("Document not found")
}

func SplitSortField

func SplitSortField(field string) (key string, sort int32)

SplitSortField handle sort symbol: "+"/"-" in front of field. if "+", return sort as 1 if "-", return sort as -1

Types

type DefaultField

type DefaultField struct {
	ID        primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
	CreatedAt time.Time          `bson:"created_at,omitempty" json:"created_at"`
	UpdatedAt time.Time          `bson:"updated_at,omitempty" json:"updated_at"`
}

DefaultField represents a structure with default fields for MongoDB documents.

func (*DefaultField) AfterFind

func (df *DefaultField) AfterFind(ctx context.Context)

AfterFind is a hook to handle actions after finding a document.

func (*DefaultField) AfterInsert

func (df *DefaultField) AfterInsert(ctx context.Context)

AfterInsert is a hook to handle actions after inserting a document.

func (*DefaultField) AfterUpdate

func (df *DefaultField) AfterUpdate(ctx context.Context)

AfterUpdate is a hook to handle actions after updating a document.

func (*DefaultField) BeforeInsert

func (df *DefaultField) BeforeInsert(ctx context.Context)

BeforeInsert is a hook to set default field values before inserting a document.

func (*DefaultField) BeforeUpdate

func (df *DefaultField) BeforeUpdate(ctx context.Context)

BeforeUpdate is a hook to set default field values before updating a document.

func (*DefaultField) DefaultCreatedAt

func (df *DefaultField) DefaultCreatedAt()

DefaultCreatedAt sets the default value for the CreatedAt field if it's zero.

func (*DefaultField) DefaultID added in v0.0.3

func (df *DefaultField) DefaultID()

DefaultID sets the default value for the _id field if it's zero.

func (*DefaultField) DefaultUpdatedAt

func (df *DefaultField) DefaultUpdatedAt()

DefaultUpdatedAt sets the default value for the UpdatedAt field.

func (*DefaultField) Indexes

func (df *DefaultField) Indexes() []string

Indexes returns the non-unique indexes for the collection.

func (*DefaultField) Uniques

func (df *DefaultField) Uniques() []string

Uniques returns the unique indexes for the collection.

type DoTransactionFunc

type DoTransactionFunc func(
	ctx context.Context,
	callback func(sessCtx context.Context) (interface{}, error),
	opts ...*options.TransactionOptions,
) (interface{}, error)

DoTransactionFunc is a function signature for performing transactions.

func DoTransaction

func DoTransaction(client *mongo.Client) DoTransactionFunc

DoTransaction creates and manages a database transaction.

type Document

type Document interface {
	BeforeInsert(ctx context.Context)
	AfterInsert(ctx context.Context)
	BeforeUpdate(ctx context.Context)
	AfterUpdate(ctx context.Context)
	AfterFind(ctx context.Context)
}

Document represents an interface for common document operations.

type IRepo

type IRepo[T Document] interface {
	Aggregate(ctx context.Context, pipeline interface{}, res interface{}, opts ...*options.AggregateOptions) error
	Clone(opts ...*options.CollectionOptions) (*mongo.Collection, error)
	Collection() *mongo.Collection
	Count(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error)
	CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error)
	DeleteMany(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (deletedCount int64, err error)
	DeleteOne(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (deletedCount int64, err error)
	Distinct(ctx context.Context, fieldName string, filter interface{}, opts ...*options.DistinctOptions) ([]interface{}, error)
	EnsureIndexes(ctx context.Context, uniques []string, indexes []string) error
	EnsureIndexesByModel(ctx context.Context, model Indexes) error
	EstimatedCount(ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error)
	EstimatedDocumentCount(ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error)
	Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (docs []T, err error)
	FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (doc T, err error)
	FindOneAndDelete(ctx context.Context, filter interface{}, opts ...*options.FindOneAndDeleteOptions) (doc T, err error)
	FindOneAndUpdate(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.FindOneAndUpdateOptions) (T, error)
	Get(ctx context.Context, id interface{}, opts ...*options.FindOneOptions) (T, error)
	InsertMany(ctx context.Context, docs []T, opts ...*options.InsertManyOptions) error
	InsertOne(ctx context.Context, doc T, opts ...*options.InsertOneOptions) (T, error)
	Name() string
	UpdateByID(ctx context.Context, id interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)
	UpdateMany(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)
	UpdateOne(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)
}

IRepo represents the interface for MongoDB repository operations.

type Indexes

type Indexes interface {
	Uniques() []string
	Indexes() []string
}

Indexes is an interface for defining unique and non-unique indexes.

type Repo

type Repo[T Document] struct {
	// contains filtered or unexported fields
}

Repo is a generic repository for working with MongoDB collections.

func NewRepo

func NewRepo[T Document](collection *mongo.Collection) *Repo[T]

NewRepo creates a new repository for the given MongoDB collection.

func (*Repo[T]) Aggregate

func (r *Repo[T]) Aggregate(ctx context.Context, pipeline interface{}, res interface{}, opts ...*options.AggregateOptions) error

Aggregate executes an aggregate command against the collection and returns a cursor over the resulting documents. The pipeline parameter must be an array of documents, each representing an aggregation stage. The pipeline cannot be nil but can be empty. The stage documents must all be non-nil. For a pipeline of bson.D documents, the mongo.Pipeline type can be used. See https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/#db-collection-aggregate-stages for a list of valid stages in aggregations. The opts parameter can be used to specify options for the operation (see the options.AggregateOptions documentation.) For more information about the command, see https://www.mongodb.com/docs/manual/reference/command/aggregate/.

func (*Repo[T]) Clone

func (r *Repo[T]) Clone(opts ...*options.CollectionOptions) (*mongo.Collection, error)

Clone creates a copy of the Collection configured with the given CollectionOptions. The specified options are merged with the existing options on the collection, with the specified options taking precedence.

func (*Repo[T]) Collection

func (r *Repo[T]) Collection() *mongo.Collection

Collection returns the *mongo.Collection

func (*Repo[T]) Count

func (r *Repo[T]) Count(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error)

[MODM] Count counts the number of documents in the collection that match the filter.

func (*Repo[T]) CountDocuments

func (r *Repo[T]) CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error)

CountDocuments returns the number of documents in the collection. For a fast count of the documents in the collection, see the EstimatedDocumentCount method. The filter parameter must be a document and can be used to select which documents contribute to the count. It cannot be nil. An empty document (e.g. bson.D{}) should be used to count all documents in the collection. This will result in a full collection scan. The opts parameter can be used to specify options for the operation (see the options.CountOptions documentation).

func (*Repo[T]) DeleteMany

func (r *Repo[T]) DeleteMany(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (deletedCount int64, err error)

DeleteMany deletes multiple documents based on the provided filter.

func (*Repo[T]) DeleteOne

func (r *Repo[T]) DeleteOne(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (deletedCount int64, err error)

DeleteOne deletes a single document based on the provided filter.

func (*Repo[T]) Distinct

func (r *Repo[T]) Distinct(ctx context.Context, fieldName string, filter interface{}, opts ...*options.DistinctOptions) ([]interface{}, error)

Distinct executes a distinct command to find the unique values for a specified field in the collection. The fieldName parameter specifies the field name for which distinct values should be returned. The filter parameter must be a document containing query operators and can be used to select which documents are considered. It cannot be nil. An empty document (e.g. bson.D{}) should be used to select all documents. The opts parameter can be used to specify options for the operation (see the options.DistinctOptions documentation). For more information about the command, see https://www.mongodb.com/docs/manual/reference/command/distinct/.

func (*Repo[T]) EnsureIndexes

func (r *Repo[T]) EnsureIndexes(ctx context.Context, uniques []string, indexes []string) error

EnsureIndexes creates unique and non-unique indexes in the collection.

func (*Repo[T]) EnsureIndexesByModel

func (r *Repo[T]) EnsureIndexesByModel(ctx context.Context, model Indexes) error

EnsureIndexesByModel creates indexes in the collection based on an Indexes interface.

func (*Repo[T]) EstimatedCount

func (r *Repo[T]) EstimatedCount(ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error)

[MODM] EstimatedCount estimates the number of documents in the collection.

func (*Repo[T]) EstimatedDocumentCount

func (r *Repo[T]) EstimatedDocumentCount(ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error)

EstimatedDocumentCount executes a count command and returns an estimate of the number of documents in the collection using collection metadata. The opts parameter can be used to specify options for the operation (see the options.EstimatedDocumentCountOptions documentation). For more information about the command, see https://www.mongodb.com/docs/manual/reference/command/count/.

func (*Repo[T]) Find

func (r *Repo[T]) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (docs []T, err error)

Find retrieves multiple documents based on the provided filter. Hooks: AfterFind

func (*Repo[T]) FindOne

func (r *Repo[T]) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (doc T, err error)

FindOne retrieves a single document based on the provided filter. Hooks: AfterFind

func (*Repo[T]) FindOneAndDelete

func (r *Repo[T]) FindOneAndDelete(ctx context.Context, filter interface{}, opts ...*options.FindOneAndDeleteOptions) (doc T, err error)

FindOneAndDelete retrieves and deletes a single document based on the provided filter. Hooks: AfterFind

func (*Repo[T]) FindOneAndUpdate

func (r *Repo[T]) FindOneAndUpdate(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.FindOneAndUpdateOptions) (T, error)

FindOneAndUpdate retrieves, updates, and returns a single document based on the provided filter and update/document. Hooks: BeforeUpdate(document), AfterUpdate(document), AfterFind

func (*Repo[T]) Get

func (r *Repo[T]) Get(ctx context.Context, id interface{}, opts ...*options.FindOneOptions) (T, error)

[MODM] Get retrieves a single document by ID(ObjectID) from the collection.

func (*Repo[T]) InsertMany

func (r *Repo[T]) InsertMany(ctx context.Context, docs []T, opts ...*options.InsertManyOptions) error

InsertMany inserts multiple documents into the collection. Hooks: BeforeInsert, AfterInsert

func (*Repo[T]) InsertOne

func (r *Repo[T]) InsertOne(ctx context.Context, doc T, opts ...*options.InsertOneOptions) (T, error)

InsertOne inserts a single document into the collection. Hooks: BeforeInsert, AfterInsert

func (*Repo[T]) Name

func (r *Repo[T]) Name() string

Name returns the name of the collection.

func (*Repo[T]) UpdateByID

func (r *Repo[T]) UpdateByID(ctx context.Context, id interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)

UpdateByID updates a document by ID with the provided update/document. Hooks(document): BeforeUpdate, AfterUpdate

func (*Repo[T]) UpdateMany

func (r *Repo[T]) UpdateMany(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)

UpdateMany updates multiple documents based on the provided filter and update/document. Hooks(document): BeforeUpdate, AfterUpdate

func (*Repo[T]) UpdateOne

func (r *Repo[T]) UpdateOne(ctx context.Context, filter interface{}, updateOrDoc interface{}, opts ...*options.UpdateOptions) (modifiedCount int64, err error)

UpdateOne updates a single document based on the provided filter and update/document. Hooks(document): BeforeUpdate, AfterUpdate

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL