Giter Site home page Giter Site logo

grimoire's Introduction

grimoire

GoDoc Build Status Go Report Card Maintainability Test Coverage FOSSA Status

โš ๏ธ Grimoire V2 is available as REL and Changeset package.

Grimoire is a database access layer inspired by Ecto. It features a flexible query API and built-in validation. It currently supports MySQL, PostgreSQL, and SQLite3 but a custom adapter can be implemented easily using the Adapter interface.

Features:

  • Query Builder
  • Association Preloading
  • Struct style create and update
  • Changeset Style create and update
  • Builtin validation using changeset
  • Multi adapter support
  • Logger

Motivation

Common go ORM accepts struct as a value for modifying records which has a problem of unable to differentiate between an empty, nil, or undefined value. It's a tricky problem especially when you want to have an endpoint that supports partial updates. Grimoire attempts to solve that problem by integrating Changeset system inspired from Elixir's Ecto. Changeset is a form like entity which allows us to not only solve that problem but also help us with casting, validations, and constraints check.

Install

go get github.com/Fs02/grimoire

Quick Start

package main

import (
	"time"

	"github.com/Fs02/grimoire"
	"github.com/Fs02/grimoire/adapter/mysql"
	"github.com/Fs02/grimoire/changeset"
	"github.com/Fs02/grimoire/params"
)

type Product struct {
	ID        int
	Name      string
	Price     int
	CreatedAt time.Time
	UpdatedAt time.Time
}

// ChangeProduct prepares data before database operation.
// Such as casting value to appropriate types and perform validations.
func ChangeProduct(product interface{}, params params.Params) *changeset.Changeset {
	ch := changeset.Cast(product, params, []string{"name", "price"})
	changeset.ValidateRequired(ch, []string{"name", "price"})
	changeset.ValidateMin(ch, "price", 100)
	return ch
}

func main() {
	// initialize mysql adapter.
	adapter, err := mysql.Open("root@(127.0.0.1:3306)/db?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic(err)
	}
	defer adapter.Close()

	// initialize grimoire's repo.
	repo := grimoire.New(adapter)

	var product Product

	// Inserting Products.
	// Changeset is used when creating or updating your data.
	ch := ChangeProduct(product, params.Map{
		"name":  "shampoo",
		"price": 1000,
	})

	if ch.Error() != nil {
		// handle error
	}

	// Changeset can also be created directly from json string.
	jsonch := ChangeProduct(product, params.ParseJSON(`{
		"name":  "soap",
		"price": 2000,
	}`))

	// Create products with changeset and return the result to &product,
	if err = repo.From("products").Insert(&product, ch); err != nil {
		// handle error
	}

	// or panic when insertion failed
	repo.From("products").MustInsert(&product, jsonch)

	// Querying Products.
	// Find a product with id 1.
	repo.From("products").Find(1).MustOne(&product)

	// Updating Products.
	// Update products with id=1.
	repo.From("products").Find(1).MustUpdate(&product, ch)

	// Deleting Products.
	// Delete Product with id=1.
	repo.From("products").Find(1).MustDelete()
}

Examples

Documentation

Guides: https://fs02.github.io/grimoire

API Documentation: https://godoc.org/github.com/Fs02/grimoire

License

Released under the MIT License

FOSSA Status

grimoire's People

Contributors

dependabot[bot] avatar enkiprobo avatar fossabot avatar fs02 avatar husnimun avatar kevinalfianto avatar raihannurr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

grimoire's Issues

[Potential Bug] Changeset.ValidateRequired doesn't produce error for required field

Bug Description

ValidateRequired doesn't produce error even though required field is empty

Steps to reproduce

https://play.golang.org/p/9soJDMn9B8t

Expected result

ch.Errors() should be [ktp_direksi is required, tdp is required, sk_domisili is required, akta_pendirian is required, akta_perubahan is required]

Actual result

ch.Errors() is [] (empty)

Possible root cause

  • For this to happen, we need to set some fields in the entity. If some fields in the entity has been set to non empty value, ch.zero will be false.
  • If the required field is not in the changeset and ch.zero is false, it will check if the required field exists in ch.values
  • Required fields exists in ch.values, but it only checks for empty string and nil value.
  • Since the required fields (e.g sk_domisili) has fichaURL as its type, it will check for nil value. Since it's not nil, it will continue and skip the loop without adding error to the changeset https://github.com/Fs02/grimoire/blob/master/changeset/validate_required.go#L27

Possible solution

Many To Many Relationship (pivot table)

Hello,

I would like to say thank you for helping out last time. Unfortunetly I got stuck again.

I am trying to query many to many realtionship.

  1. Post table

id
title

  1. Pivot Table

id
post_id
tag_id

  1. Tag Table
    id
    title

Tables in the db are named as: posts, post_tag and tags. As far, this naming convention was working great for preloading has many, has one or belongs to. Can't figure it out how do I query posts with all the tags. Tried joins with preload but always get a panic mentioning that PostID or TagID field is not found...

Quering Relationships

Thanks guys for sharing this package, very intuitive api in most cases with exception for relationships...

More of the question than issue I hope:

So I have relationship one to many:

Tests Table:

CREATE TABLE tests (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Tags Table:

CREATE TABLE tags (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    test_id INT UNSIGNED,
    title TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (test_id)
        REFERENCES tests(id)
        ON DELETE CASCADE
);

Here are the structs:

type Test struct {
	ID        int
	Title     string
	Tags      []Tag `references:"ID" foreign_key:"TestID"`
	CreatedAt string
	UpdatedAt string
}

type Tag struct {
	ID        int
	TestID    int
	Title     string
	CreatedAt string
	UpdatedAt string
}

My question is how do I query all the tests with all assosiated tags. I tried all posibilities and I can not figure it out how to query relationships. Always geting null for the tags... Any help would be appriciated.

{
"status": "OK",
"data": [
{
"ID": 1,
"Title": "test 1",
"Tags": null,
"CreatedAt": "2019-08-19 23:18:24",
"UpdatedAt": "2019-08-19 23:18:24"
},
{
"ID": 1,
"Title": "test 1",
"Tags": null,
"CreatedAt": "2019-08-19 23:18:24",
"UpdatedAt": "2019-08-19 23:18:24"
},
{
"ID": 1,
"Title": "test 1",
"Tags": null,
"CreatedAt": "2019-08-19 23:18:24",
"UpdatedAt": "2019-08-19 23:18:24"
},
etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.