Description
When building business webApps one needs to expose much of the database with the default operations of CRUD.
An ORM lib would handle this, but i prefer to stay much closer to SQL queries than pushing everything into an ORM pattern and learn all the quirks and maintenance of such a system.
Ideally i would like to be able to write common functions for every model/table struct generated through jet's code gen, so that i can, for example, provide Create/Read/Update/Delete Rest endpoints for my database entities without having to write/generate these functions for each type.
Describe the solution you'd like
A possibility to access the table functionalities provided by this lib via interface or common struct. For example embed a "jettable" in the generated struct isntead of the postgres.table like this:
type JetTable struct{
postgres.Table
ID postgres.ColumnInteger
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
}
type messageTable struct {
JetTable
// Columns
ChannelID postgres.ColumnInteger
Text postgres.ColumnString
IDUser postgres.ColumnInteger
}
so i could write functions for the jettable that allow me to implement the CRUD operations where i don't need the actual columns, but just ID and MutableColumns.
Would also be possible by providing some interface functions to access these fields instead of the embedded struct.
Also, currently tables and models are completly unrelated, maybe it could be part of the solution to wrap these two packages into one "entity" package, that allows access to either the model or the table of an entity via a single struct, so i don't have to write the boilerplate code to combine an empty struct and its table i.e.:
message := entity.NewEntity(model.Message{}, &table.Message, db, ginEngine)
could be handled in a package in a sleeker way.
This is what i try to achieve:
//main:
message := entity.NewEntity(model.Message{}, &table.Message.JetTable, db, ginEngine)
//entity
type Entity struct {
Name string
Model model.Model
Table *table.JetTable
Db *sql.DB
GinEngine *gin.Engine
}
func NewEntity(model model.Model, table *table.JetTable, db *sql.DB, ginEngine *gin.Engine) (e Entity) {
name := reflect.TypeOf(model).Name()
e = Entity{
Name: name,
Model: model,
Table: table,
Db: db,
GinEngine: ginEngine,
}
---> // automatic create endpoint for any entity created
ginEngine.POST("/"+name, func(ctx *gin.Context) { e.Create(ctx) })
return
}
func (e Entity) Create(ctx *gin.Context) {
if !e.bindModel(ctx) {
return
}
// Insert model into database
stmt := e.Table.
INSERT(e.Table.MutableColumns).
MODEL(e.Model).
RETURNING(e.Table.AllColumns)
err := stmt.Query(e.Db, e.Model)
handleError(ctx, err)
// Return inserted message
ctx.JSON(http.StatusOK, e.Model)
}