Welcome to the GERPO repository! This document provides a brief overview of the project, build and run instructions, and other helpful information.
GERPO (Golang + Repository) is a generic repository implementation with advanced configuration capabilities and LINQ-like (Language Integrated Query) support.
- Easily handle CRUD operations (Create, Read, Update, Delete) with powerful filtering and sorting.
- LINQ-like capabilities (while not exactly LINQ, it’s conceptually close).
- Straightforward configuration using SQL commands and user-friendly builders.
- All SQL code in one place — inside the configuration.
- Virtual (calculated, joined) columns with mapping to struct fields.
- Caching support (currently only context-oriented cache is supported, but it’s easy to implement other caching mechanisms).
Essentially, GERPO is a helper for building SQL queries and mapping results to Go structs.
-
Repository configuration:
- Map struct fields to SQL columns via a LINQ-like builder.
- Define virtual (calculated) fields (currently supports only bool; contributions welcome).
- Protect certain fields from being updated or inserted.
- Add callbacks and hooks.
- Define persistent filters, groupings, and joins.
- Configure soft deletion
-
Per-request configuration:
- Exclude certain columns (SELECT/INSERT/UPDATE) using a builder.
- Work with transactions.
- Configure filtering and sorting via a LINQ-like builder.
- Implement pagination in your GetList requests.
go get github.com/insei/gerpo@latest
Below you’ll find various configurations and usage examples.
package main
import (
"time"
"github.com/insei/gerpo"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
}
func main() {
repo, err := gerpo.NewBuilder[test]().
DB(db).
Table("tests").
Columns(func(m *test, columns *gerpo.ColumnBuilder[test]) {
columns.Field(&m.ID).AsColumn().WithUpdateProtection()
columns.Field(&m.CreatedAt).AsColumn().WithUpdateProtection()
columns.Field(&m.UpdatedAt).AsColumn().WithInsertProtection()
columns.Field(&m.Name).AsColumn()
columns.Field(&m.Age).AsColumn()
}).
Build()
// Handle err and proceed with repo usage
}
package main
import (
"context"
"time"
"github.com/insei/gerpo"
"github.com/insei/gerpo/query"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
Joined string
}
func main() {
repo, err := gerpo.NewBuilder[test]().
DB(db).
Table("tests").
Columns(func(m *test, columns *gerpo.ColumnBuilder[test]) {
columns.Field(&m.ID).AsColumn().WithUpdateProtection()
columns.Field(&m.CreatedAt).AsColumn().WithUpdateProtection()
columns.Field(&m.UpdatedAt).AsColumn().WithInsertProtection()
columns.Field(&m.Name).AsColumn()
columns.Field(&m.Age).AsColumn()
columns.Field(&m.Joined).AsColumn().WithTable("joined_table")
}).
WithQuery(func(m *test, h query.PersistentHelper[test]) {
h.LeftJoin(func(ctx context.Context) string {
return "<SQL JOIN COMMAND>"
})
}).
Build()
// Handle err and proceed with repo usage
}
package main
import (
"context"
"time"
"github.com/insei/gerpo"
"github.com/insei/gerpo/query"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
DeletedAt *time.Time
}
func main() {
repo, err := gerpo.NewBuilder[test]().
DB(db).
Table("tests").
Columns(func(m *test, columns *gerpo.ColumnBuilder[test]) {
columns.Field(&m.ID).AsColumn().WithUpdateProtection()
columns.Field(&m.CreatedAt).AsColumn().WithUpdateProtection()
columns.Field(&m.UpdatedAt).AsColumn().WithInsertProtection()
columns.Field(&m.Name).AsColumn()
columns.Field(&m.Age).AsColumn()
columns.Field(&m.DeletedAt).AsColumn().WithInsertProtection() // configure soft deletion field/column
}).
WithSoftDeletion(func(m *User, softDeletion *gerpo.SoftDeletionBuilder[User]) {
//Configure set value for soft deletion fields/columns
softDeletion.Field(&m.DeletedAt).SetValueFn(func(ctx context.Context) any {
deletedAt := time.Now().UTC()
return &deletedAt
})
}).
WithQuery(func(m *test, h query.PersistentHelper[test]) {
// Permanently exclude deleted elements from all queries
h.Where().Field(&m.DeletedAt).EQ(nil)
}).
Build()
// Handle err and proceed with repo usage
}
Exclude certain fields from commands like SELECT/UPDATE/INSERT (Update/GetFirst/Insert/GetList):
package main
import (
"context"
"github.com/insei/gerpo"
"github.com/insei/gerpo/query"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
Joined string
}
func main() {
var repo gerpo.Repository[test] // Already initialized
list, err := repo.GetList(ctxCache, func(m *test, h query.GetListHelper[test]) {
h.Page(1).Size(2) // Pagination
h.Exclude(&m.UpdatedAt, &m.ID)
})
// Handle err and work with the list
}
Available for Count/GetFirst/GetList/Delete/Update, supporting where grouping (AND/OR):
package main
import (
"context"
"github.com/insei/gerpo"
"github.com/insei/gerpo/query"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
Joined string
}
func main() {
var repo gerpo.Repository[test] // Already initialized
list, err := repo.GetList(ctxCache, func(m *test, h query.GetListHelper[test]) {
h.Where().Field(&m.ID).LT(7) // Items with ID < 7
})
// Handle err and use the list
}
Available for GetFirst/GetList:
package main
import (
"context"
"github.com/insei/gerpo"
"github.com/insei/gerpo/query"
)
type test struct {
ID int
CreatedAt time.Time
UpdatedAt *time.Time
Name string
Age int
Joined string
}
func main() {
var repo gerpo.Repository[test] // Already initialized
item, err := repo.GetFirst(ctxCache, func(m *test, h query.GetFirstHelper[test]) {
h.OrderBy().Field(&m.CreatedAt).DESC()
})
// Handle err and use 'item'
}
We hope this information helps you quickly get started with GERPO and integrate it into your own projects. If you have any questions or suggestions, feel free to open an issue or contribute to the repository.