Skip to content

Commit

Permalink
chore: add ci workflow to test and lint (#13)
Browse files Browse the repository at this point in the history
* feat: add wrapper function to support MongoDB transactions

* doc: mark transactions feature as done in future scope section

* fix: support multi tenancy

* doc: fix mgod usage example in README

* doc: multi tenancy advanced guide

* chore: add ci workflow to test and lint

* fix: remove slog usage

* chore: bump monogdb requirement from 3.6 -> 4.4

* fix: add support from mongodb 3.6 with warning note

* doc: refactor docs -> limitations

* fix: remove slog usage

* style: escape less than in installtion markdown file

* chore: limit test workflow trigger for commits against main branch only
  • Loading branch information
harsh-2711 authored Dec 21, 2023
1 parent 539402a commit 6e63bc1
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 18 deletions.
77 changes: 77 additions & 0 deletions .github/workflows/test-module.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Lint & Test

on:
pull_request:
branches:
- main
paths-ignore:
- 'docs/**'
- 'website/**'
push:
branches:
- main
paths-ignore:
- 'docs/**'
- 'website/**'

jobs:
lint-module:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.18.x

- name: Setup cache
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-
- name: Run linter
uses: golangci/golangci-lint-action@v3
with:
version: v1.54

test-module:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.18', '1.19', '1.20', '1.21']
mongodb-version: ['4.4', '5.0', '6.0', '7.0'] # add 3.6 as well after fixing the tests (collection creation)
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}

- name: Start MongoDB Replica Set
uses: supercharge/[email protected]
with:
mongodb-version: ${{ matrix.mongodb-version }}
mongodb-replica-set: replset
mongodb-db: mgoddb

- name: Setup cache
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-
- name: Run tests
run: go test ./...
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
- Go 1.18 or higher.
- MongoDB 3.6 and higher.

> [!WARNING]
> For MongoDB version **<4.4**, please create the collection in MongoDB before creating an `EntityMongoModel` using `mgod` for the same.
> Refer to [this MongoDB limitations](https://www.mongodb.com/docs/manual/reference/limits/#operations) for more information.
## Installation
```
go get github.com/Lyearn/mgod
Expand Down
29 changes: 16 additions & 13 deletions bsondoc/build_bson_doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package bsondoc
import (
"context"
"fmt"
"log/slog"

"github.com/Lyearn/mgod/errors"
"github.com/Lyearn/mgod/schema"
Expand Down Expand Up @@ -33,7 +32,6 @@ func Build(
}

if bsonDoc == nil && len(entityModelSchema.Root.Children) != 0 {
slog.ErrorContext(ctx, "BSON doc is nil but entity model schema is not empty")
return errors.NewBadRequestError(errors.BadRequestError{
Underlying: "bson doc",
Got: "nil",
Expand Down Expand Up @@ -64,7 +62,7 @@ func build(
return nil
}

schemaNode, err := getSchemaNodeForPath(ctx, parent, schemaNodes, translateTo)
schemaNode, err := getSchemaNodeForPath(parent, schemaNodes, translateTo)
if err != nil {
return err
} else if schemaNode == nil {
Expand Down Expand Up @@ -100,7 +98,7 @@ func build(
uniqVisitedSchemaNodes := lo.Uniq(visitedSchemaNodes)

if len(uniqVisitedSchemaNodes) != len(immediateChildren) {
err := addMissingNodes(ctx, bsonElem, immediateChildren, uniqVisitedSchemaNodes, schemaNodes, translateTo)
err := addMissingNodes(bsonElem, immediateChildren, uniqVisitedSchemaNodes, schemaNodes, translateTo)
if err != nil {
return err
}
Expand Down Expand Up @@ -157,7 +155,10 @@ func build(
case TranslateToEnumEntityModel:
modifiedBSONNodeVal, err = transformer.TransformForEntityModelDoc(elemVal)
default:
err = fmt.Errorf("unknown translateTo enum value %s", translateTo)
err = errors.NewBadRequestError(errors.BadRequestError{
Underlying: "translateTo enum",
Got: string(translateTo),
})
}

if err != nil {
Expand Down Expand Up @@ -220,7 +221,6 @@ func getConvertedValueForNode(

// addMissingNodes appends missing nodes in bson doc which have default value.
func addMissingNodes(
ctx context.Context,
bsonElem *bson.D,
immediateChildren []string,
uniqVisitedSchemaNodes []string,
Expand All @@ -229,7 +229,7 @@ func addMissingNodes(
) error {
missingSchemaPaths, _ := lo.Difference(immediateChildren, uniqVisitedSchemaNodes)
for _, missingSchemaPath := range missingSchemaPaths {
missingSchemaNode, err := getSchemaNodeForPath(ctx, missingSchemaPath, schemaNodes, translateTo)
missingSchemaNode, err := getSchemaNodeForPath(missingSchemaPath, schemaNodes, translateTo)
if err != nil {
return err
} else if missingSchemaNode == nil {
Expand All @@ -245,7 +245,11 @@ func addMissingNodes(

// throw error if schema node is not _id field (special field) and is required but has no default value.
if !isIDField && missingSchemaNode.Props.Options.Default == nil {
return fmt.Errorf("required field at path %s is missing in bson doc", missingSchemaPath)
return errors.NewBadRequestError(errors.BadRequestError{
Underlying: "bson doc",
Got: "nil",
Expected: fmt.Sprintf("field at path - %s", missingSchemaPath),
})
}

var bsonNodeToAppend bson.E
Expand Down Expand Up @@ -278,7 +282,6 @@ func addMissingNodes(
}

func getSchemaNodeForPath(
ctx context.Context,
path string,
schemaNodes map[string]*schema.TreeNode,
translateTo TranslateToEnum,
Expand All @@ -291,10 +294,10 @@ func getSchemaNodeForPath(
return nil, nil
}

slog.ErrorContext(ctx, fmt.Sprintf(
"schema doesn't contains any node at path %s found in bsonDoc", path))

return nil, fmt.Errorf("unknown path %s found in bson doc", path)
return nil, errors.NewNotFoundError(errors.NotFoundError{
Underlying: "bson doc",
Value: fmt.Sprintf("path - %s", path),
})
}

return schemaNode, nil
Expand Down
5 changes: 5 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ title: Installation
- Go 1.18 or higher
- MongoDB 3.6 and higher

:::warning
For MongoDB version **\<4.4**, please create the collection in MongoDB before creating an `EntityMongoModel` using `mgod` for the same.
Refer to [this MongoDB limitations](https://www.mongodb.com/docs/manual/reference/limits/#operations) for more information.
:::

## Installation

```bash
Expand Down
10 changes: 10 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ func NewBadRequestError(e BadRequestError) Error {
return Error(fmt.Sprintf("%s: expected %s, got %s", e.Underlying, e.Expected, e.Got))
}

type NotFoundError struct {
Value string
Underlying string
}

func NewNotFoundError(e NotFoundError) Error {
return Error(fmt.Sprintf("%s not found for %s", e.Value, e.Underlying))
}

const (
ErrNoDatabaseConnection = Error("no database connection")
ErrSchemaNotCached = Error("schema not cached")
)
5 changes: 3 additions & 2 deletions schema/entity_model_schema_cache.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package schema

import (
"fmt"
"sync"

"github.com/Lyearn/mgod/errors"
)

// EntityModelSchemaCache is the cache implementation than can hold [EntityModelSchema].
Expand Down Expand Up @@ -31,7 +32,7 @@ func (c *entityModelSchemaCache) GetSchema(schemaName string) (*EntityModelSchem
return schema, nil
}

return nil, fmt.Errorf("%s schema not found in cache", schemaName)
return nil, errors.ErrSchemaNotCached
}

func (c *entityModelSchemaCache) SetSchema(schemaName string, schema *EntityModelSchema) {
Expand Down
7 changes: 6 additions & 1 deletion schema/fieldopt/default_value_opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"reflect"
"strconv"

"github.com/Lyearn/mgod/errors"
"go.mongodb.org/mongo-driver/bson"
)

Expand Down Expand Up @@ -73,6 +74,10 @@ func (o defaultValueOption) GetValue(field reflect.StructField) (interface{}, er
return bson.A{}, nil

default:
return nil, fmt.Errorf("unsupported type %v", fieldType)
return nil, errors.NewBadRequestError(errors.BadRequestError{
Underlying: "default value option",
Got: fmt.Sprintf("%v", fieldType),
Expected: "string, int, float32, float64, bool, slice or array",
})
}
}
2 changes: 0 additions & 2 deletions transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package mgod

import (
"context"
"log/slog"

"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
Expand All @@ -18,7 +17,6 @@ type TransactionFunc func(sc mongo.SessionContext) (interface{}, error)
func WithTransaction(ctx context.Context, transactionFunc TransactionFunc) (interface{}, error) {
session, err := mClient.StartSession()
if err != nil {
slog.ErrorContext(ctx, "Error occurred during WithTransaction", err)
return nil, err
}
defer session.EndSession(ctx)
Expand Down

0 comments on commit 6e63bc1

Please sign in to comment.