mgs

package module
v0.0.0-beta.3 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2023 License: Apache-2.0 Imports: 13 Imported by: 0

README

Mgs

CodeQL GitHub release (with filter) Go MongoDB Go Report Card Go Reference Coverage Status

Mgs is a mongoose-like go mongodb odm. If you've used mongoose.js, or you're looking for a dev friendly mongodb odm for golang, then this is for you.


Features

  • Perform left join (lookup) on find operations without having to define aggregation pipelines for each query.
  • Register hooks on predefined collection schemas for CRUD operations.
  • Type safe schema & model validations.
  • Atomic WRITE operations (documents are not written to database if one or more hooks return errors).

Requirements

  • Go >=1.18 (for generics)
  • MongoDB >=4.4 (for atomic transactions)

Installation

go get github.com/0x-buidl/mgs@latest

Usage

To get started, establish a connection to mongodb client like normal.

import (
    "context"
    "time"

    "github.com/0x-buidl/mgs"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
	log.Fatal(err)
}

defer func() {
    if err = client.Disconnect(ctx); err != nil {
        panic(err)
    }
}()

err = client.Ping(ctx, nil)
if err != nil {
	log.Fatal(err)
}

db := client.Database("test")

coll := db.Collection("test_coll")

Define your collection schema and hooks.

NOTE: Do not modify hook receivers, doing so may lead to unexpected behaviours. To avoid errors, ensure hook receivers are not pointers.

type Book struct {
	Title  string      `json:"title"  bson:"title"`
	Author interface{} `json:"author" bson:"author"`
}

// For simplicity. You can also define your custom default schema that implements mgs.IDefaultSchema
type BookModel = mgs.Model[Book,*mgs.DefaultSchema]
type BookDoc = mgs.Document[Book]

func NewBookModel(coll *mongo.Collection) *BookModel {
    return mgs.NewModel[Book,*mgs.DefaultSchema](coll)
}

func (book Book) Validate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) BeforeValidate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) AfterValidate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) BeforeCreate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) AfterCreate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) BeforeUpdate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) AfterUpdate(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) BeforeDelete(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) AfterDelete(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) BeforeFind(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

func (book Book) AfterFind(ctx context.Context, arg *mgs.HookArg[Book]) error {
	return nil
}

Additional examples and usage guides can be found under the examples directory and mgs go docs.

License

This package is licensed under the Apache License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithTransaction

func WithTransaction[T SessionLike](ctx context.Context, sess T, fn SessionFunc, opts ...*options.TransactionOptions) (any, error)

WithTransaction executes the callback function in a transaction. When a transaction is started with mongo.SessionContext options are ignored because the session is already created. This method only closes the session if it was created by this method.

Types

type AfterCreateHook

type AfterCreateHook[T Schema] interface {
	AfterCreate(ctx context.Context, arg *HookArg[T]) error
}

AfterCreateHook runs after documents are written to the database when executing Model.CreateOne and Model.CreateMany operations. AfterSaveHook will run before this hook runs. HookArg.Data will return ptr to Document(s) created.

type AfterDeleteHook

type AfterDeleteHook[T Schema] interface {
	AfterDelete(ctx context.Context, arg *HookArg[T]) error
}

AfterDeleteHook runs after Document(s) are removed from the database. HookArg.Data will return ptr to deleted Document if this is called on a Document, otherwise it will return ptr to mongo.DeleteResult.

type AfterFindHook

type AfterFindHook[T Schema] interface {
	AfterFind(ctx context.Context, arg *HookArg[T]) error
}

AfterFindHook runs after a find operation is executed. HookArg.Data will return ptr to found Document(s).

type AfterSaveHook

type AfterSaveHook[T Schema] interface {
	AfterSave(ctx context.Context, arg *HookArg[T]) error
}

AfterSaveHook runs after Document(s) are written to the database when using Model.CreateOne, Model.CreateMany or Document.Save. This hook doesn't run on all Model Update operations. HookArg.Data will return ptr to Document(s) being saved.

type AfterUpdateHook

type AfterUpdateHook[T Schema] interface {
	AfterUpdate(ctx context.Context, arg *HookArg[T]) error
}

AfterUpdateHook runs after a document is updated in the database. This hook also runs on `replace` operations. HookArg.Data will return ptr to updated *Document if called on a Document, otherwise it will return ptr to mongo.UpdateResult.

type AfterValidateHook

type AfterValidateHook[T Schema] interface {
	AfterValidate(ctx context.Context, arg *HookArg[T]) error
}

AfterValidateHook runs after validate hook is called. HookArg.Data will return ptr to validated Document.

type BeforeCreateHook

type BeforeCreateHook[T Schema] interface {
	BeforeCreate(ctx context.Context, arg *HookArg[T]) error
}

BeforeCreateHook runs before executing [Model.Create] and Model.CreateMany operations. BeforeSaveHook will run after this hook runs. HookArg.Data will return ptr to Document(s) being created.

type BeforeDeleteHook

type BeforeDeleteHook[T Schema] interface {
	BeforeDelete(ctx context.Context, arg *HookArg[T]) error
}

BeforeDeleteHook runs before Document(s) are removed from the database. HookArg.Data will return ptr to Query being executed if this is called on a Model, otherwise it will return ptr to Document being deleted.

type BeforeFindHook

type BeforeFindHook[T Schema] interface {
	BeforeFind(ctx context.Context, arg *HookArg[T]) error
}

BeforeFindHook runs before any find QueryOperation is executed. HookArg.Data will return ptr to Query being ececuted.

type BeforeSaveHook

type BeforeSaveHook[T Schema] interface {
	BeforeSave(ctx context.Context, arg *HookArg[T]) error
}

BeforeSaveHook runs before Document(s) are written to the database when using Model.CreateOne, Model.CreateMany or Document.Save. This hook doesn't run on all Model Update operations. HookArg.Data will return ptr to Document(s) being saved.

type BeforeUpdateHook

type BeforeUpdateHook[T Schema] interface {
	BeforeUpdate(ctx context.Context, arg *HookArg[T]) error
}

BeforeUpdateHook runs before Document(s) are updated in the database. This hook also runs on `replace` operations. HookArg.Data will return ptr to Document being updated if called on a Document, otherwise it will return ptr to Query.

type BeforeValidateHook

type BeforeValidateHook[T Schema] interface {
	BeforeValidate(ctx context.Context, arg *HookArg[T]) error
}

BeforeValidateHook runs before validate hook is called. HookArg.Data will return ptr to Document being validated.

type DefaultSchema

type DefaultSchema struct {
	ID        *primitive.ObjectID `json:"_id,omitempty"       bson:"_id,omitempty"`
	CreatedAt *time.Time          `json:"createdAt,omitempty" bson:"createdAt,omitempty"`
	UpdatedAt *time.Time          `json:"updatedAt,omitempty" bson:"updatedAt,omitempty"`
}

DefaultSchema is a struct that implements the IDefaultSchema interface. It contains the default fields (ID,CreatedAt,UpdatedAt) that are added to a document.

func (*DefaultSchema) GenerateCreatedAt

func (s *DefaultSchema) GenerateCreatedAt()

func (*DefaultSchema) GenerateID

func (s *DefaultSchema) GenerateID()

func (*DefaultSchema) GenerateUpdatedAt

func (s *DefaultSchema) GenerateUpdatedAt()

func (DefaultSchema) GetCreatedAt

func (s DefaultSchema) GetCreatedAt() time.Time

func (DefaultSchema) GetID

func (s DefaultSchema) GetID() primitive.ObjectID

func (DefaultSchema) GetUpdatedAt

func (s DefaultSchema) GetUpdatedAt() time.Time

func (DefaultSchema) GetUpdatedAtTag

func (s DefaultSchema) GetUpdatedAtTag(t string) string

func (*DefaultSchema) SetUpdatedAt

func (s *DefaultSchema) SetUpdatedAt(t time.Time)

type Document

type Document[T Schema, P IDefaultSchema] struct {
	IDefaultSchema `json:"-" bson:"-"`
	Doc            *T `json:",inline" bson:",inline"`
	// contains filtered or unexported fields
}

Document is a struct that represents a document in a MongoDB collection. Do not use this struct directly, instead use the Model.NewDocument method.

func (*Document[T, P]) BSON

func (doc *Document[T, P]) BSON() (bson.M, error)

Returns BSON representation of doc.

func (*Document[T, P]) Collection

func (doc *Document[T, P]) Collection() *mongo.Collection

Returns the collection that doc belongs to.

func (*Document[T, P]) Delete

func (doc *Document[T, P]) Delete(ctx context.Context) error

Deletes Document (doc) from the database atomically. This operation fails if any of the hooks return an error.

func (*Document[T, P]) IsModified

func (doc *Document[T, P]) IsModified(field string) bool

IsModified returns true if the field has been modified.

func (*Document[T, P]) IsNew

func (doc *Document[T, P]) IsNew() bool

IsNew returns true if the document is new and has never been written to the database. Otherwise, it returns false

func (*Document[T, P]) JSON

func (doc *Document[T, P]) JSON() (map[string]any, error)

Returns the JSON representation of doc.

func (*Document[T, P]) MarshalBSON

func (doc *Document[T, P]) MarshalBSON() ([]byte, error)

Returns doc as BSON bytes.

func (*Document[T, P]) MarshalJSON

func (doc *Document[T, P]) MarshalJSON() ([]byte, error)

Returns doc as JSON bytes.

func (*Document[T, P]) Model

func (doc *Document[T, P]) Model() *Model[T, P]

Returns the model that the doc belongs to.

func (*Document[T, P]) Save

func (doc *Document[T, P]) Save(ctx context.Context) error

Saves [Documet] (doc) to the database atomically. This method creates a new document if the document is not already existing, Otherwise, it updates the existing document. This operation fails if any of the hooks return an error.

func (*Document[T, P]) UnmarshalBSON

func (doc *Document[T, P]) UnmarshalBSON(data []byte) error

Unmarshals data into the doc.

type HookArg

type HookArg[T Schema] struct {
	// contains filtered or unexported fields
}

HookArg represents arguments passed to a hook method. It is advisable to only modify HookArg.Data and not the Hook receiver itself, doing so may cause unexpected behaviors. To avoid modifying the receiver, ensure it's not a pointer.

func (*HookArg[T]) Data

func (arg *HookArg[T]) Data() interface{}

Data returns the data associated with this hook.

func (*HookArg[T]) Operation

func (arg *HookArg[T]) Operation() QueryOperation

Operation returns the QueryOperation being executed.

type IDefaultSchema

type IDefaultSchema interface {
	// Generates a new ObjectID and sets it to the ID field.
	GenerateID()
	// Generates a new time.Time and sets it to the CreatedAt field.
	GenerateCreatedAt()
	// Generates a new time.Time and sets it to the UpdatedAt field.
	GenerateUpdatedAt()
	// GetID returns the ID field.
	GetID() primitive.ObjectID
	// GetCreatedAt returns the CreatedAt field.
	GetCreatedAt() time.Time
	// GetUpdatedAt returns the UpdatedAt field.
	GetUpdatedAt() time.Time

	// Sets the UpdatedAt field to t.
	SetUpdatedAt(t time.Time)
	// Returns the tag name for the UpdatedAt field. t can be either "json", "bson" or any custom tag.
	// This is useful for setting the UpdatedAt field when updating with [Model.UpdateOne] and [Model.UpdateMany].
	GetUpdatedAtTag(t string) string
}

IDefaultSchema is an interface that represents the default fields that are added to a document. Only structs that implement this interface can be used as a default schema.

type Model

type Model[T Schema, P IDefaultSchema] struct {
	// contains filtered or unexported fields
}

func NewModel

func NewModel[T Schema, P IDefaultSchema](collection *mongo.Collection) *Model[T, P]

NewModel creates a new model. T represents the schema type while P represents default schema type. Panics if T or P is not a struct .

func (*Model[T, P]) Collection

func (model *Model[T, P]) Collection() *mongo.Collection

Collection returns the *mongo.Collection that the model is using.

func (*Model[T, P]) CreateMany

func (model *Model[T, P]) CreateMany(ctx context.Context, docs []T, opts ...*mopt.InsertManyOptions) ([]*Document[T, P], error)

CreateMany creates multiple documents in the collection. It returns the created documents or an error if one occurred. Documents are not created if any of the hooks return an error.

func (*Model[T, P]) CreateOne

func (model *Model[T, P]) CreateOne(ctx context.Context, doc T, opts ...*mopt.InsertOneOptions) (*Document[T, P], error)

CreateOne creates a single document in the collection. It returns the created document or an error if one occurred. Document is not created if any of the hooks return an error.

func (*Model[T, P]) DeleteMany

func (model *Model[T, P]) DeleteMany(ctx context.Context, query bson.M, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)

DeleteMany deletes multiple documents from the collection. It returns the deleted result or an error if one occurred. Documents are not deleted if any of the hooks return an error.

func (*Model[T, P]) DeleteOne

func (model *Model[T, P]) DeleteOne(ctx context.Context, query bson.M, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)

DeleteOne deletes a single document from the collection. It returns the deleted result or an error if one occurred. Document is not deleted if any of the hooks return an error.

func (*Model[T, P]) Find

func (model *Model[T, P]) Find(ctx context.Context, query bson.M, opts ...*mopt.FindOptions) ([]*Document[T, P], error)

Find finds multiple documents from the collection. It returns the documents or an error if one occurred.

func (*Model[T, P]) FindById

func (model *Model[T, P]) FindById(ctx context.Context, id any, opts ...*mopt.FindOneOptions) (*Document[T, P], error)

FindById finds a single document by its id. It returns the document or an error if one occurred. If no document is found, it returns mongo.ErrNoDocuments.

func (*Model[T, P]) FindOne

func (model *Model[T, P]) FindOne(ctx context.Context, query bson.M, opts ...*mopt.FindOneOptions) (*Document[T, P], error)

FindOne finds a single document from the collection. It returns the document or an error if one occurred. If no document is found, it returns mongo.ErrNoDocuments.

func (*Model[T, P]) NewDocument

func (model *Model[T, P]) NewDocument(data T) *Document[T, P]

NewDocument creates a new *Document with the given data.

func (*Model[T, P]) UpdateMany

func (model *Model[T, P]) UpdateMany(ctx context.Context, query bson.M, update bson.M, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)

UpdateMany updates multiple documents in the collection. It returns the update result or an error if one occurred. Documents are not updated if any of the hooks return an error.

func (*Model[T, P]) UpdateOne

func (model *Model[T, P]) UpdateOne(ctx context.Context, query bson.M, update bson.M, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)

UpdateOne updates a single document in the collection. It returns the update result or an error if one occurred. Document is not updated if any of the hooks return an error.

type Query

type Query[T Schema] struct {
	// The document filter for this operation
	Filter *bson.M
	// Update payload if Operation is an update operation
	Update *bson.M
	// Options specific to the current operation
	Options interface{}
	// Operation being executed
	Operation QueryOperation
}

Query is a struct that holds information about the current operation beign executed on a model.

func NewQuery

func NewQuery[T Schema]() *Query[T]

NewQuery returns and empty Query struct.

func (*Query[T]) SetFilter

func (q *Query[T]) SetFilter(f *bson.M) *Query[T]

SetFilter sets the Query filter field.

func (*Query[T]) SetOperation

func (q *Query[T]) SetOperation(o QueryOperation) *Query[T]

SetOperation sets the Query Operation field.

func (*Query[T]) SetOptions

func (q *Query[T]) SetOptions(o interface{}) *Query[T]

SetOptions sets the Query Options field.

func (*Query[T]) SetUpdate

func (q *Query[T]) SetUpdate(u *bson.M) *Query[T]

SetUpdate sets the Query Update field.

type QueryOperation

type QueryOperation string

Model Query Operation

const (
	CreateOne        QueryOperation = "create-one"
	CreateMany       QueryOperation = "create-many"
	FindMany         QueryOperation = "find-many"
	FindOne          QueryOperation = "find-one"
	FindOneAndUpdate QueryOperation = "find-one-and-update"
	Replace          QueryOperation = "replace"
	UpdateOne        QueryOperation = "update-one"
	UpdateMany       QueryOperation = "update-many"
	DeleteOne        QueryOperation = "delete-one"
	DeleteMany       QueryOperation = "delete-many"
)

type Schema

type Schema interface{}

Schema is an interface that represents the structure of a document in a MongoDB collection. It must be a struct.

type SessionFunc

type SessionFunc func(sessCtx mongo.SessionContext) (interface{}, error)

SessionFunc is a callback function that's executed within a session transaction.

type SessionLike

type SessionLike interface {
	*mongo.Database | *mongo.Collection | *mongo.SessionContext | *mongo.Client | *mongo.Session
}

SessionLike is a Union type of all mongo types that a seeion can be derived from.

type ValidateHook

type ValidateHook[T Schema] interface {
	Validate(ctx context.Context, arg *HookArg[T]) error
}

ValidateHook is used to register validation for a schema. This hook runs before a Document is saved to the database. It only runs on Model.CreateOne, Model.CreateMany and Document.Save operations. HookArg.Data will return ptr to Document being validated.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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