morm

package module
v0.10.3 Latest Latest
Warning

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

Go to latest
Published: Jan 3, 2026 License: MIT Imports: 11 Imported by: 0

README

Minimal Object Relational Model (MORM)

MORM (Minimal Object Relational Model) is a lightweight object–relational model focused on simplicity and performance. It is designed to handle straightforward CRUD operations, including creating and dropping database tables based on your application’s logic. The primary goal is to improve productivity and development speed by approaching the data layer from a struct-first perspective when working with relational databases.

For MORM to be considered successful, it should significantly reduce the time spent designing and maintaining database schemas. In most cases, the schema should be inferred directly from your data structures, minimizing manual setup and redundant definitions.

MORM is not intended to replace complex or highly optimized queries within your architecture. For those use cases, tools like SQLC, combined with well-written, traditional SQL, are a better fit.

Like a Myrmidon in your arsenal, MORM strives for performance, predictability, and minimal magic—doing one thing well, and doing it efficiently.

Quick Start


import "github.com/chapgx/morm"

type User struct {
  Id int `morm:"id integer primary"` // this tag notation will be executed exactly as it is
  FirstName string `morm:"first_name text"` // this gets execute exactly as it is using first_name as the field name
  LastName string // untagged fields will be added by default . In this case the field name is lastname
  Foo string `morm:":ignore"` // this is a directive tells the ORM to ignore this field
  Email Email // default behavior is to create a new table based on the struct
  Phone Phone `morm:":flatten"` // this will bring all the Phone struct fields to the User table
}


// this structure uses the struct field names as the table fields and the data types as well
type Email struct {
  Id int
  Address string
}


type Phone struct {
  Primary bool
  Number string
}


func main() {
  // takes engine and connection string, returns an error if any
  // this sets the package level MORM usually if you have a long running process you want to set this
	e := morm.SetDefaultClient(morm.SQLITE, "db.db")
  if e != nil {
    panic(e)
  }

  var u User
  // second parameter is table name if none passed the struct name is use, in this case users would be use
  e := morm.CreateTable(u, "")
  if e != nil {
    panic(e)
  }
}

The query for the example above would be


create table if not exists users (
  id integer primary,
  first_name text,
  lastname text,
  phone_primary integer check(phone_primary in(0,1)),
  phone_number text,
)

create table if not exists emails (
  id integer,
  address text,
)

Form the struct to the query to the engine executing the query that is the basic process of MORM

DIRECTIVES

Special tags that declare behavior for a structure field beyond SQL context

Directive Usage Description
ignore :ignore ignores the field
flatten :flatten fields in nested structure are merge into the parent table (the table made out of the parent structure)

ENGINES

SQL engines supported and states of development

Name Supported Plan To Support State
SQLITE YES YES Developement
SQLServer NO YES Pending
Postgress NO YES Pending
MySql NO YES Pending

How To Use

By Default you don't have to add MORM tags for the structure to be transpile into it's SQL representation. In the case of no tags it will simple use the field name (this will be turn to lowercase) and it will try to represent the specify data type in it's SQL form. If the structure contains nested structures then adjacent tables will be created for them.

At the beginning of your process of before you start calling library functions you most specify the engine to be used. Sample below.

import "github.com/chapgx/morm"

// engine and connection string passed in. this sets the package level MORM client
e := morm.SetDefaultClient(morm.SQLITE, "db.db")

You can also create a new client at any time in the process that points to the same db or a separate one.

import "github.com/chapgx/morm"

client, e := morm.New(morm.SQLITE, "db.db")

Tags

The MORM tag is simple statement in SQL of the field. For example an ID of type integer would be tag as follow morm:"id int primary", this would make the id an integer and the column primary.

Directives are special tags that expand beyond the context of SQL check the Directives sessions for more information.

Samples

Common use case examples of MORM. All examples assume you have specify the engine/driver and connection string. For how to do that check How To Use

Create a table

// engine declare as SQLITE

import "github.com/chapgx/morm"

type Plane struct {
  Number int `morm:"number text"`
  Weight float
  Active bool
  NeedService bool `morm:"need_service int check(need_service in(0,1))"`
}

// creates sql table out of Plane struct, by default the name is planes but you can overwrite with
// the second parameter
err := morm.CreateTable(Plane{}, "")

Insert Record

// engine declare as SQLITE

import "github.com/chapgx/morm"


plane := Plane{"BOING_00", 15.20}
// inters record into the database
err := morm.Insert(&plane)

plane1 := Plane{"BOING_01", 20}
// insert record into the database with a explicit table name
err := morm.InsertByName(&plane1, "planes_backup")

Update Record


import "github.com/chapgx/morm"
import "fmt"

plane := Plane{NeedService: true}

// create your filter which is an in code representation of a where clause
filter := morm.NewFilter()
filter.
  And("name", EQUAL, "BOING_07").
  Or("weight", GREATER, 20)

g := filter.Group()
g.
  And("active", EQUAL,  true).
  Or("need_service", EQUAL,  false)


result := Update(&plane, &filter, "NeedService")
if result.Error != nil {
  panic(result.Error)
}

fmt.Println("affected", result.RowsAffected)

The SQL would look like this

update planes
set need_service = 1
where name = 'BOING_07' or weight > 20
and (active = 1 or need_service = 0)

P.S If filters equals nil it will make the update to all records in the database

Delete Record For Delete filter is required and it will panic if non passed. This is to avoid deleting the entire table. Use morm.Exec(query) for something like that.


import "github.com/chapgx/morm"

filter := morm.NewFilter()
filter.And("weight", GREATER, 20)


rslt := DeleteByName("planes", &filters)
// handle error and check rows affected if needed

rslt = Delete(Plane{}, &filters)

ROADMAP

  • CRUD Operations On simple structures.
  • Full SQLITE support
  • Full SQL Server support

Documentation

Index

Constants

View Source
const (
	IgnoreDirective  = ":ignore"
	FlattenDirective = ":flatten"
)

Variables

View Source
var (
	ErrDefaultClientIsNil = errors.New("err defautl client is nil")
	ErrDBIsNil            = errors.New("err db interface is nil")
)
View Source
var ErrValIsNotExpectedType = errors.New("val is not of the expected type")

Functions

func Close added in v0.3.1

func Close() error

Close closes databse connection for the default MORM client

func CreateTable

func CreateTable(model any, tablename string) error

CreateTable creates a new table if it does not exists, tablename is used if is not <nil> otherwise the struct name is used as the table name.

func Drop added in v0.3.1

func Drop(model any) error

func DropByName added in v0.3.1

func DropByName(tablename string) error

func Exec

func Exec(query string, params ...any) (sql.Result, error)

Exec executres arbitrary query using the underlying driver

func Insert

func Insert(model any) error

Insert creates a new record

func InsertByName

func InsertByName(model any, tablename string) error

InsertByName creates a new record where the tablename is explicit not implicit

func PrintQueryHistory

func PrintQueryHistory()

func Query added in v0.3.1

func Query(query string, params ...any) (*sql.Rows, error)

func QueryRow added in v0.4.2

func QueryRow(query string, params ...any) (*sql.Row, error)

func Read added in v0.3.1

func Read(model any, filters *Filter, tablename string) error

func SetDefaultClient added in v0.9.3

func SetDefaultClient(engine ENGINE, connString string) error

SetDefaultClient sets the package level MORM

Types

type DBInfo added in v0.10.3

type DBInfo interface {
	Version() string
	Edition() string
	EngineEdition() int
}

type ENGINE added in v0.10.3

type ENGINE int
const (
	SQLITE ENGINE = iota + 1
	SQLServer
	POSTGRESS
	MySQL
)

func (ENGINE) String added in v0.10.3

func (e ENGINE) String() string

type Filter

type Filter struct {
	// contains filtered or unexported fields
}

func NewFilter

func NewFilter() Filter

func (*Filter) And

func (f *Filter) And(key string, c FilterComparison, val any) *Filter

func (*Filter) AndIsNull added in v0.2.1

func (f *Filter) AndIsNull(key string) *Filter

func (*Filter) Group

func (f *Filter) Group() *FilterGroup

func (*Filter) Or

func (f *Filter) Or(key string, c FilterComparison, val any) *Filter

func (*Filter) OrIsNull added in v0.2.1

func (f *Filter) OrIsNull(key string) *Filter

func (*Filter) WhereSQL

func (f *Filter) WhereSQL() (string, error)

type FilterComparison

type FilterComparison string
const (
	EQUAL           FilterComparison = "="
	NOT_EQUAL       FilterComparison = "<>"
	GREATER         FilterComparison = ">"
	GREATER_OR_EQ   FilterComparison = ">="
	LESS_THAN       FilterComparison = "<"
	LESS_THAN_OR_EQ FilterComparison = "<="
	IS              FilterComparison = "is"
)

type FilterGroup

type FilterGroup struct {
	// contains filtered or unexported fields
}

func (*FilterGroup) And

func (*FilterGroup) AndIsNull added in v0.2.1

func (fg *FilterGroup) AndIsNull(key string) *FilterGroup

func (*FilterGroup) Or

func (*FilterGroup) OrIsNull added in v0.2.1

func (fg *FilterGroup) OrIsNull(key string) *FilterGroup

func (*FilterGroup) SQL

func (fg *FilterGroup) SQL() (string, error)

type FilterItem

type FilterItem struct {
	// contains filtered or unexported fields
}

type FilterSeparator

type FilterSeparator string
const (
	AND FilterSeparator = "and"
	OR  FilterSeparator = "or"
)

type FnConnect

type FnConnect func() error

type MORM

type MORM struct {
	// contains filtered or unexported fields
}

func GetDefault added in v0.9.3

func GetDefault() (*MORM, error)

GetDefault returns the package level MORM or an error

func GetDefaultMust added in v0.9.3

func GetDefaultMust() *MORM

GetDefaultMust returns default MORM panics on error

func New

func New(engine ENGINE, connectionString string) (*MORM, error)

New creates and return a new MORM based on the engine and connectionString

func NewWithName added in v0.10.3

func NewWithName(engine ENGINE, conn string, dbname string) (*MORM, error)

func (*MORM) Close

func (m *MORM) Close() error

Close() closes the database connection and resets MORM

func (*MORM) CreateTable added in v0.9.3

func (m *MORM) CreateTable(model any, tablename string) error

CreateTable creates a table base on the model and optional tablename

func (*MORM) Delete added in v0.9.3

func (m *MORM) Delete(model any, filters *Filter) Result

Delete deletes a record from the table representation of the model passed in

func (*MORM) DeleteByName added in v0.9.3

func (m *MORM) DeleteByName(tablename string, filters *Filter) Result

DeleteByName deletes records from a tablename based on filter

func (*MORM) Drop added in v0.9.3

func (m *MORM) Drop(model any) error

func (*MORM) DropByName added in v0.9.3

func (m *MORM) DropByName(tablename string) error

func (*MORM) Exec added in v0.9.3

func (m *MORM) Exec(query string, params ...any) (sql.Result, error)

Exec executres arbitrary query using the underlying driver

func (*MORM) GetDatabaseName added in v0.10.3

func (m *MORM) GetDatabaseName() string

GetDatabaseName returns the databasename is any

func (*MORM) Info added in v0.10.3

func (m *MORM) Info() (DBInfo, error)

Info returns server information

func (*MORM) Insert added in v0.9.3

func (m *MORM) Insert(model any) error

Insert creates a new record

func (*MORM) InsertByName added in v0.9.3

func (m *MORM) InsertByName(model any, tablename string) error

InsertByName creates a new record where the tablename is explicit not implicit

func (*MORM) Query added in v0.9.3

func (m *MORM) Query(query string, params ...any) (*sql.Rows, error)

func (*MORM) QueryRow added in v0.9.3

func (m *MORM) QueryRow(query string, params ...any) (*sql.Row, error)

func (*MORM) Read added in v0.9.3

func (m *MORM) Read(model any, filters *Filter, tablename string) error

Read read data into the model

func (*MORM) Update added in v0.9.3

func (m *MORM) Update(model any, filters *Filter, fields ...string) Result

Update makes changes to specify fields in the database

type MSSQLInfo added in v0.10.3

type MSSQLInfo struct {
	// contains filtered or unexported fields
}

func (MSSQLInfo) Edition added in v0.10.3

func (i MSSQLInfo) Edition() string

func (MSSQLInfo) EngineEdition added in v0.10.3

func (i MSSQLInfo) EngineEdition() int

func (MSSQLInfo) IsNil added in v0.10.3

func (i MSSQLInfo) IsNil() bool

func (MSSQLInfo) Version added in v0.10.3

func (i MSSQLInfo) Version() string

type MormTag

type MormTag struct {
	// contains filtered or unexported fields
}

MormTag is a representation of the morm notation tag

func (MormTag) IsDirective

func (mt MormTag) IsDirective() bool

IsDirective checks if the notation tag is a morm directive

func (MormTag) IsEmpty

func (mt MormTag) IsEmpty() bool

IsEmpty checks if the morm tag is an empty tag

func (*MormTag) SetFieldName

func (mt *MormTag) SetFieldName(fn string)

type Result

type Result struct {
	Error        error
	RowsAffected int64
}

func Delete

func Delete(model any, filters *Filter) Result

Delete deletes a record from the table representation of the model passed in

func DeleteByName

func DeleteByName(tablename string, filters *Filter) Result

DeleteByName deletes records from a tablename based on filter

func Update

func Update(model any, filters *Filter, fields ...string) Result

Update makes changes to specify fields in the database

Jump to

Keyboard shortcuts

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