enginemongo

package
v0.0.8 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package enginemongo provides the MongoDB engine for r3.

It implements the full r3.CRUD interface using the official MongoDB Go driver v2, with reflection-based struct metadata and BSON query building. The drivers/mongo package wraps this engine as a thin constructor.

Key types:

  • BaseCRUD: full r3.CRUD backed by *mongo.Collection
  • BaseRaw: escape hatch for arbitrary MongoDB operations
  • StructMeta: reflection-based struct metadata (fields, PK, relations, soft-delete)
  • PreparedListQuery: pre-computed BSON filter/sort/pagination from an r3.Query

Model structs should use `bson` struct tags for field mapping, or `r3` tags. The primary key field defaults to `_id`.

Index

Constants

View Source
const (
	// RelHasMany represents a one-to-many relationship.
	RelHasMany = r3tag.RelHasMany
	// RelBelongsTo represents a many-to-one relationship.
	RelBelongsTo = r3tag.RelBelongsTo
)

Variables

This section is empty.

Functions

func BSONFilter

func BSONFilter(kv ...any) bson.D

BSONFilter creates a simple bson.D filter from key-value pairs. Usage: BSONFilter("status", "active", "age", bson.D{{"$gt", 18}}).

func NewBaseQuerier

func NewBaseQuerier[T any, ID comparable](coll *mongo.Collection, opts ...r3.Option) r3.Querier[T, ID]

NewBaseQuerier creates a read-only repository backed by MongoDB. It returns r3.Querier, providing a compile-time guarantee that the caller cannot perform write operations.

Internally this constructs a full BaseCRUD but only exposes the Querier interface (Get, List).

func NewBaseQuerierFromDB

func NewBaseQuerierFromDB[T any, ID comparable](db *mongo.Database, opts ...r3.Option) r3.Querier[T, ID]

NewBaseQuerierFromDB creates a read-only repository backed by MongoDB, deriving the collection name from the struct type T.

func RunPreloads

func RunPreloads(
	ctx context.Context,
	db *mongo.Database,
	meta *StructMeta,
	entitiesPtr any,
	preloads r3.Preloads,
) error

RunPreloads executes preload queries for the given entities based on the requested preload names and the relation metadata in StructMeta.

For has-many relations: collects parent IDs, queries child collection WHERE fk IN (...), groups results by FK, and assigns them to the parent's slice field.

For belongs-to relations: collects FK values from parents, queries target collection WHERE _id IN (...), and assigns results to the parent's pointer field.

entities must be a pointer to a slice (e.g. *[]City).

Types

type BaseCRUD

type BaseCRUD[T any, ID comparable] struct {
	Collection *mongo.Collection

	r3.DefaultsManager

	Meta   StructMeta
	Config r3.Config
	Raw    *BaseRaw[T, ID]
}

BaseCRUD is a generic CRUD repository backed by MongoDB. It implements the full r3.CRUD[T, ID] interface using the MongoDB Go driver v2.

The struct type T must use `bson` struct tags for field mapping (or `r3` tags). The ID type should match the MongoDB _id field type (e.g. primitive.ObjectID or string).

func NewBaseCRUD

func NewBaseCRUD[T any, ID comparable](coll *mongo.Collection, opts ...r3.Option) *BaseCRUD[T, ID]

NewBaseCRUD creates a new BaseCRUD with the given MongoDB collection. If collection is nil, it derives the collection name from the struct type T and uses the provided database.

Accepts optional r3.Option values for framework-level configuration.

func NewBaseCRUDFromDB

func NewBaseCRUDFromDB[T any, ID comparable](db *mongo.Database, opts ...r3.Option) *BaseCRUD[T, ID]

NewBaseCRUDFromDB creates a new BaseCRUD using a database, deriving the collection name automatically from the struct type T.

Accepts optional r3.Option values for framework-level configuration.

func (*BaseCRUD[T, ID]) Aggregate added in v0.0.3

func (r *BaseCRUD[T, ID]) Aggregate(ctx context.Context, qarg ...r3.Query) ([]r3.AggregateRow, error)

Aggregate computes grouped aggregates via the MongoDB aggregation pipeline: $match (filters + soft-delete) → $group → $project (flatten group keys) → $match (having) → $sort → $skip/$limit. See r3.Aggregator for the query semantics.

Degradation notes (documented per the query-parity philosophy): dotted (nested-path) group fields are not supported, and COUNT(DISTINCT field) is computed via $addToSet — fine for the moderate cardinalities aggregates are used for, but it materializes the value set per group.

func (*BaseCRUD[T, ID]) Count

func (r *BaseCRUD[T, ID]) Count(ctx context.Context, qarg ...r3.Query) (int64, error)

Count returns the number of documents matching the query's filters.

func (*BaseCRUD[T, ID]) Create

func (r *BaseCRUD[T, ID]) Create(ctx context.Context, entity T) (T, error)

Create inserts a new document into MongoDB and returns it with the generated _id.

func (*BaseCRUD[T, ID]) Delete

func (r *BaseCRUD[T, ID]) Delete(ctx context.Context, id ID) error

Delete removes a document by its _id. If the model has a soft-delete field, it sets the field to the current time instead of actually deleting the document.

func (*BaseCRUD[T, ID]) Get

func (r *BaseCRUD[T, ID]) Get(ctx context.Context, id ID, qarg ...r3.Query) (T, error)

Get retrieves a document by its _id.

func (*BaseCRUD[T, ID]) HardDelete

func (r *BaseCRUD[T, ID]) HardDelete(ctx context.Context, id ID) error

HardDelete permanently removes a document, bypassing soft-delete.

func (*BaseCRUD[T, ID]) List

func (r *BaseCRUD[T, ID]) List(ctx context.Context, qarg ...r3.Query) ([]T, int64, error)

List retrieves documents based on the provided query parameters.

func (*BaseCRUD[T, ID]) Patch

func (r *BaseCRUD[T, ID]) Patch(ctx context.Context, entity T, fields r3.Fields) (T, error)

Patch performs a partial update, modifying only the fields specified by fields. The entity must have its _id set. Returns the entity after the update.

func (*BaseCRUD[T, ID]) Restore

func (r *BaseCRUD[T, ID]) Restore(ctx context.Context, id ID) error

Restore un-deletes a soft-deleted document by unsetting its soft-delete field. Returns an error if the model has no soft-delete field.

func (*BaseCRUD[T, ID]) Update

func (r *BaseCRUD[T, ID]) Update(ctx context.Context, entity T) (T, error)

Update replaces an existing document identified by its _id.

type BaseRaw

type BaseRaw[T any, ID any] struct {
	Collection *mongo.Collection
	Meta       StructMeta
}

BaseRaw is a MongoDB wrapper that allows executing arbitrary queries against the underlying collection.

func NewBaseRaw

func NewBaseRaw[T any, ID comparable](coll *mongo.Collection, meta StructMeta) *BaseRaw[T, ID]

NewBaseRaw creates a new BaseRaw instance.

func (*BaseRaw[T, ID]) Aggregate

func (r *BaseRaw[T, ID]) Aggregate(ctx context.Context, pipeline any) ([]T, error)

Aggregate executes an aggregation pipeline and decodes results into T.

func (*BaseRaw[T, ID]) BulkWrite

func (r *BaseRaw[T, ID]) BulkWrite(ctx context.Context, models []mongo.WriteModel) (*mongo.BulkWriteResult, error)

BulkWrite executes a bulk write operation.

func (*BaseRaw[T, ID]) Col

func (r *BaseRaw[T, ID]) Col() *mongo.Collection

Col returns the underlying *mongo.Collection for fully custom usage.

func (*BaseRaw[T, ID]) CountDocuments

func (r *BaseRaw[T, ID]) CountDocuments(ctx context.Context, filter any) (int64, error)

CountDocuments returns the count of documents matching the filter.

func (*BaseRaw[T, ID]) DeleteMany

func (r *BaseRaw[T, ID]) DeleteMany(ctx context.Context, filter any) (*mongo.DeleteResult, error)

DeleteMany deletes all documents matching the filter.

func (*BaseRaw[T, ID]) DeleteOne

func (r *BaseRaw[T, ID]) DeleteOne(ctx context.Context, filter any) (*mongo.DeleteResult, error)

DeleteOne deletes a single document matching the filter.

func (*BaseRaw[T, ID]) Distinct

func (r *BaseRaw[T, ID]) Distinct(ctx context.Context, fieldName string, filter any) *mongo.DistinctResult

Distinct returns the distinct values for a given field.

func (*BaseRaw[T, ID]) Find

func (r *BaseRaw[T, ID]) Find(
	ctx context.Context,
	filter any,
	opts ...options.Lister[options.FindOptions],
) ([]T, error)

Find executes a find query with the given filter and returns matching documents.

func (*BaseRaw[T, ID]) FindOne

func (r *BaseRaw[T, ID]) FindOne(
	ctx context.Context,
	filter any,
	opts ...options.Lister[options.FindOneOptions],
) (T, error)

FindOne executes a find query expected to return a single document.

func (*BaseRaw[T, ID]) FindOneAndDelete

func (r *BaseRaw[T, ID]) FindOneAndDelete(
	ctx context.Context,
	filter any,
	opts ...options.Lister[options.FindOneAndDeleteOptions],
) (T, error)

FindOneAndDelete atomically finds a document and deletes it, returning the deleted document.

func (*BaseRaw[T, ID]) FindOneAndUpdate

func (r *BaseRaw[T, ID]) FindOneAndUpdate(
	ctx context.Context,
	filter any,
	update any,
	opts ...options.Lister[options.FindOneAndUpdateOptions],
) (T, error)

FindOneAndUpdate atomically finds a document and updates it, returning the result.

func (*BaseRaw[T, ID]) InsertOne

func (r *BaseRaw[T, ID]) InsertOne(ctx context.Context, doc any) (*mongo.InsertOneResult, error)

InsertOne inserts a single document.

func (*BaseRaw[T, ID]) UpdateMany

func (r *BaseRaw[T, ID]) UpdateMany(ctx context.Context, filter any, update any) (*mongo.UpdateResult, error)

UpdateMany updates all documents matching the filter.

func (*BaseRaw[T, ID]) UpdateOne

func (r *BaseRaw[T, ID]) UpdateOne(ctx context.Context, filter any, update any) (*mongo.UpdateResult, error)

UpdateOne updates a single document matching the filter.

type PreparedListQuery

type PreparedListQuery struct {
	// Filter is the combined BSON filter document.
	Filter bson.D

	// Sort is the BSON sort document.
	Sort bson.D

	// Projection is the BSON projection document (field selection).
	Projection bson.D

	// IsPaginated indicates whether offset-based pagination is active.
	IsPaginated bool

	// Limit and Offset (skip) are set when IsPaginated is true.
	Limit  int64
	Offset int64

	// IsCursorPaginated indicates whether cursor/keyset pagination is active.
	// When true, CursorFilter contains the keyset filter and CursorLimit
	// contains the LIMIT. No skip or count query should be used.
	IsCursorPaginated bool

	// CursorFilter is the keyset filter (may be empty for the first page).
	CursorFilter bson.D

	// CursorLimit is the maximum number of results for cursor pagination.
	CursorLimit int64

	// Query is the merged r3.Query (defaults + user args) for access to
	// Preloads, IncludeTrashed, and other fields.
	Query r3.Query
}

PreparedListQuery holds pre-computed BSON components derived from an r3.Query. It is the result of converting r3 filters, sorts, and pagination into BSON-ready pieces that the MongoDB driver can consume.

func PrepareListQuery

func PrepareListQuery(dm *r3.DefaultsManager, qarg ...r3.Query) (PreparedListQuery, error)

PrepareListQuery merges defaults with user query args, then converts filters, sorts, and pagination into BSON-ready components.

type RelationKind

type RelationKind = r3tag.RelationKind

RelationKind describes the type of relationship between two entities.

type RelationMeta

type RelationMeta struct {
	FieldName  string       // Go struct field name (matched against PreloadSpec.Name)
	FieldIndex int          // struct field index for reflection-based assignment
	Kind       RelationKind // has-many or belongs-to
	FKField    string       // foreign key field name (BSON field name on the "many" side)
	TargetMeta StructMeta   // metadata for the related entity type
	TargetType reflect.Type // reflect.Type of the target entity (element type, not slice/ptr)
}

RelationMeta holds metadata about a struct field that represents a relation.

type StructMeta

type StructMeta struct {
	CollectionName string   // e.g. "cities"
	Fields         []string // BSON field names in order, e.g. ["_id", "name", "country_name", ...]
	FieldIndices   []int    // corresponding struct field indices for each BSON field
	IDField        string   // primary key BSON field name (defaults to "_id")
	IDFieldIdx     int      // index into Fields/FieldIndices for the ID entry

	// SoftDeleteField is the BSON field name used for soft-delete (e.g. "deleted_at").
	// Empty string means soft-delete is not enabled.
	SoftDeleteField string

	// SoftDeleteZero is the zero value of the soft-delete field when it is a
	// non-pointer type. A live (never-deleted) record stores this zero value
	// rather than null — a non-pointer time.Time persists as the zero BSON Date,
	// not as null — so the "not deleted" filter must match it as well as null.
	// Nil when the field is a pointer (live records store null) or when
	// soft-delete is disabled.
	SoftDeleteZero any

	// Relations holds metadata about related entities.
	Relations []RelationMeta
}

StructMeta holds reflection-based metadata about a struct type T. It is the MongoDB equivalent of enginesql.StructMeta.

func GetStructMeta

func GetStructMeta[T any]() StructMeta

GetStructMeta derives collection name and field info from a generic type T.

Tag priority: `r3` tag first, `bson` tag as fallback, then `db` tag, then snake_case. Fields with tag value "-" (in any tag) are ignored.

func (*StructMeta) FieldValues

func (m *StructMeta) FieldValues(entity any) []any

FieldValues extracts the BSON field values from a struct in the same order as Fields.

func (*StructMeta) FieldValuesForFields

func (m *StructMeta) FieldValuesForFields(entity any, fields []string) []any

FieldValuesForFields extracts field values from an entity for the given BSON field names.

func (*StructMeta) IDValue

func (m *StructMeta) IDValue(entity any) any

IDValue extracts the ID field value from an entity.

func (*StructMeta) NonIDFieldValues

func (m *StructMeta) NonIDFieldValues(entity any) []any

NonIDFieldValues extracts field values excluding the ID, for insert operations.

func (*StructMeta) NonIDFields

func (m *StructMeta) NonIDFields() []string

NonIDFields returns all BSON field names except the ID field.

func (*StructMeta) SetFieldsFromMap

func (m *StructMeta) SetFieldsFromMap(entityPtr any, data map[string]any)

SetFieldsFromMap sets struct fields from a map of BSON field name -> value.

func (*StructMeta) SetIDValue

func (m *StructMeta) SetIDValue(entityPtr any, val any)

SetIDValue sets the ID field value on an entity (via pointer).

func (*StructMeta) ToBSONDoc

func (m *StructMeta) ToBSONDoc(entity any, includeID bool) map[string]any

ToBSONDoc converts an entity to a bson.D document using the struct metadata. This is used for insert/update operations.

func (*StructMeta) ValidatePatchFields

func (m *StructMeta) ValidatePatchFields(fields []string) ([]string, error)

ValidatePatchFields checks that the given field names are valid for a Patch operation.

Jump to

Keyboard shortcuts

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