Documentation ¶
Index ¶
- Variables
- func AdaptNamedParams(dialect, statement string, variables map[string]any, unsafe ...bool) (string, []any, error)
- func AddTrigger(onTable, col, bf_af_UpdateInsertDelete string, stmt string, dbName ...string)
- func AutoMigrate[T any](tableName string, dbName ...string) error
- func Benchmark(f func(), name string, iterations int)
- func DifferenceBetweenSlices[T comparable](slice1 []T, slice2 []T) []T
- func DisableCache()
- func DownloadFile(filepath string, url string) error
- func DropTrigger(tableName, column string, dbName ...string)
- func EnableCheck()
- func Exec(dbName, query string, args ...any) error
- func ExecContext(ctx context.Context, dbName, query string, args ...any) error
- func ExecContextNamed(ctx context.Context, query string, args map[string]any, dbName ...string) error
- func ExecNamed(query string, args map[string]any, dbName ...string) error
- func FlushCache()
- func GenerateUUID() string
- func GetAllColumnsTypes(table string, dbName ...string) (map[string]string, []string)
- func GetAllTables(dbName ...string) []string
- func GetConnection(dbName ...string) *sql.DB
- func GetMemoryTableAndDB(tbName string, dbName ...string) (TableEntity, DatabaseEntity, error)
- func InitShell() bool
- func IsValidEmail(email string) bool
- func JSON_ARRAY(values []any, as string, dialect ...string) string
- func JSON_CAST(value string, as string, dialect ...string) string
- func JSON_EXTRACT(dataJson string, opt ...JsonOption) string
- func JSON_OBJECT(values []any, as string, dialect ...string) string
- func JSON_REMOVE(dataJson string, opt ...JsonOption) string
- func JSON_SET(dataJson string, opt ...JsonOption) string
- func LinkModel[T any](to_table_name string, dbName ...string)
- func LogQueries()
- func ManyToMany(table1, table2 string, dbName ...string) error
- func New(dbType Dialect, dbName string, dbDriver driver.Driver, dbDSN ...string) error
- func OnDelete(fn func(database, table string, query string, args ...any) error)
- func OnDrop(fn func(database, table string) error)
- func OnInsert(fn DbHook)
- func OnSet(fn DbHook)
- func RegisterTable[T any](table TableRegistration[T], gendocs ...bool) error
- func RemoveFromSlice[T comparable](slice *[]T, elemsToRemove ...T)
- func RunEvery(t time.Duration, fn func(cancelChan chan struct{}))
- func SetAdminPath(path string)
- func SetCacheMaxMemory(megaByte int)
- func Shutdown(dbNames ...string) error
- func SliceContains[T comparable](elems []T, vs ...T) bool
- func SliceToString(slice interface{}) string
- func StorageSize(dbName string) float64
- func Transaction(dbName ...string) (*sql.Tx, error)
- func UnsafeNamedQuery(query string, args map[string]any) (string, error)
- func WithAPI(rootPath string, middws ...func(handler ksmux.Handler) ksmux.Handler) *ksbus.Server
- func WithBus(options ...ksbus.ServerOpts) *ksbus.Server
- func WithDashboard(addr string, options ...DashOpts) *ksbus.Server
- func WithDocs(generateJsonDocs bool, outJsonDocs string, ...) *ksbus.Server
- func WithEmbededDocs(embeded embed.FS, embededDirPath string, ...) *ksbus.Server
- func WithMetrics(httpHandler http.Handler) *ksbus.Server
- func WithPprof(path ...string) *ksbus.Server
- func WithShell()
- func Wrap(driver driver.Driver, hooks Hooks) driver.Driver
- func WrapConn(conn driver.Conn, hooks Hooks) driver.Conn
- type BuilderM
- func (b *BuilderM) AddRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
- func (b *BuilderM) All() ([]map[string]any, error)
- func (b *BuilderM) BulkInsert(rowsData ...map[string]any) ([]int, error)
- func (b *BuilderM) Context(ctx context.Context) *BuilderM
- func (b *BuilderM) Database(dbName string) *BuilderM
- func (b *BuilderM) Debug() *BuilderM
- func (b *BuilderM) Delete() (int, error)
- func (b *BuilderM) DeleteRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
- func (b *BuilderM) Drop() (int, error)
- func (b *BuilderM) GetRelated(relatedTable string, dest *[]map[string]any) error
- func (b *BuilderM) Insert(rowData map[string]any) (int, error)
- func (b *BuilderM) InsertR(rowData map[string]any) (map[string]any, error)
- func (b *BuilderM) JoinRelated(relatedTable string, dest *[]map[string]any) error
- func (b *BuilderM) Limit(limit int) *BuilderM
- func (b *BuilderM) NoCache() *BuilderM
- func (b *BuilderM) One() (map[string]any, error)
- func (b *BuilderM) OrderBy(fields ...string) *BuilderM
- func (b *BuilderM) Page(pageNumber int) *BuilderM
- func (b *BuilderM) QueryM(statement string, args ...any) ([]map[string]any, error)
- func (b *BuilderM) QueryMNamed(statement string, args map[string]any, unsafe ...bool) ([]map[string]any, error)
- func (b *BuilderM) Select(columns ...string) *BuilderM
- func (b *BuilderM) Set(query string, args ...any) (int, error)
- func (b *BuilderM) Where(query string, args ...any) *BuilderM
- func (b *BuilderM) WhereNamed(query string, args map[string]any) *BuilderM
- type BuilderS
- func (b *BuilderS[T]) AddRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
- func (b *BuilderS[T]) All() ([]T, error)
- func (b *BuilderS[T]) BulkInsert(models ...*T) ([]int, error)
- func (b *BuilderS[T]) Context(ctx context.Context) *BuilderS[T]
- func (b *BuilderS[T]) Database(dbName string) *BuilderS[T]
- func (b *BuilderS[T]) Debug() *BuilderS[T]
- func (b *BuilderS[T]) Delete() (int, error)
- func (b *BuilderS[T]) DeleteRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
- func (b *BuilderS[T]) Drop() (int, error)
- func (b *BuilderS[T]) GetRelated(relatedTable string, dest any) error
- func (b *BuilderS[T]) Insert(model *T) (int, error)
- func (b *BuilderS[T]) InsertR(model *T) (T, error)
- func (b *BuilderS[T]) JoinRelated(relatedTable string, dest any) error
- func (b *BuilderS[T]) Limit(limit int) *BuilderS[T]
- func (b *BuilderS[T]) NoCache() *BuilderS[T]
- func (b *BuilderS[T]) One() (T, error)
- func (b *BuilderS[T]) OrderBy(fields ...string) *BuilderS[T]
- func (b *BuilderS[T]) Page(pageNumber int) *BuilderS[T]
- func (b *BuilderS[T]) QueryS(statement string, args ...any) ([]T, error)
- func (b *BuilderS[T]) QuerySNamed(statement string, args map[string]any, unsafe ...bool) ([]T, error)
- func (b *BuilderS[T]) Select(columns ...string) *BuilderS[T]
- func (b *BuilderS[T]) Set(query string, args ...any) (int, error)
- func (b *BuilderS[T]) ToChan(ptrChan *chan T) ([]T, error)
- func (b *BuilderS[T]) Where(query string, args ...any) *BuilderS[T]
- func (b *BuilderS[T]) WhereNamed(query string, args map[string]any) *BuilderS[T]
- type DashOpts
- type DatabaseEntity
- type DbHook
- type Dialect
- type DocsError
- type DocsSuccess
- type Driver
- type ErrorHook
- type ExecerQueryerContext
- func (conn ExecerQueryerContext) Begin() (driver.Tx, error)
- func (conn ExecerQueryerContext) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)
- func (conn ExecerQueryerContext) Close() error
- func (conn ExecerQueryerContext) Exec(query string, args []driver.Value) (driver.Result, error)
- func (conn ExecerQueryerContext) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)
- func (conn ExecerQueryerContext) Prepare(query string) (driver.Stmt, error)
- func (conn ExecerQueryerContext) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)
- func (conn ExecerQueryerContext) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)
- type ExecerQueryerContextWithSessionResetter
- func (conn ExecerQueryerContextWithSessionResetter) Begin() (driver.Tx, error)
- func (conn ExecerQueryerContextWithSessionResetter) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)
- func (conn ExecerQueryerContextWithSessionResetter) Close() error
- func (conn ExecerQueryerContextWithSessionResetter) Exec(query string, args []driver.Value) (driver.Result, error)
- func (conn ExecerQueryerContextWithSessionResetter) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)
- func (conn ExecerQueryerContextWithSessionResetter) Prepare(query string) (driver.Stmt, error)
- func (conn ExecerQueryerContextWithSessionResetter) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)
- func (conn ExecerQueryerContextWithSessionResetter) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)
- type Hook
- type Hooks
- type JsonOption
- type KV
- type OnErrorer
- type Selector
- func (sl *Selector[T]) Ctx(ct context.Context) *Selector[T]
- func (sl *Selector[T]) Database(dbName string) *Selector[T]
- func (sl *Selector[T]) Debug() *Selector[T]
- func (sl *Selector[T]) Named(statement string, args map[string]any, unsafe ...bool) error
- func (sl *Selector[T]) NoCache() *Selector[T]
- func (sl *Selector[T]) Query(statement string, args ...any) error
- type SessionResetter
- func (conn SessionResetter) Begin() (driver.Tx, error)
- func (conn SessionResetter) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)
- func (conn SessionResetter) Close() error
- func (conn SessionResetter) Prepare(query string) (driver.Stmt, error)
- func (conn SessionResetter) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)
- type Stmt
- func (stmt *Stmt) Close() error
- func (stmt *Stmt) Exec(args []driver.Value) (driver.Result, error)
- func (stmt *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)
- func (stmt *Stmt) NumInput() int
- func (stmt *Stmt) Query(args []driver.Value) (driver.Rows, error)
- func (stmt *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)
- type TableEntity
- type TableRegistration
- type User
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoConnection = errors.New("no connection") ErrNoData = errors.New("no data") )
var ( BASIC_AUTH_USER = "notset" BASIC_AUTH_PASS = "testnotsetbutwaititshouldbeset" )
var ( // Debug when true show extra useful logs for queries executed for migrations and queries statements Debug = false // FlushCacheEvery execute korm.FlushCache() every 10 min by default, you should not worry about it, but useful that you can change it FlushCacheEvery = 10 * time.Minute // MaxOpenConns set max open connections for db pool MaxOpenConns = 50 // MaxIdleConns set max idle connections for db pool MaxIdleConns = 30 // MaxLifetime set max lifetime for a connection in the db pool MaxLifetime = 30 * time.Minute // MaxIdleTime set max idletime for a connection in the db pool MaxIdleTime = 30 * time.Minute )
var ( ErrTableNotFound = errors.New("unable to find tableName") ErrBigData = kmap.ErrLargeData )
var Admin = func(handler ksmux.Handler) ksmux.Handler { return func(c *ksmux.Context) { session, err := c.GetCookie("session") if err != nil || session == "" { c.DeleteCookie("session") c.Status(http.StatusTemporaryRedirect).Redirect(adminPathNameGroup + "/login") return } session, err = aes.Decrypt(session) if err != nil { c.Status(http.StatusTemporaryRedirect).Redirect(adminPathNameGroup + "/login") return } user, err := Model[User]().Where("uuid = ?", session).One() if err != nil { c.Status(http.StatusTemporaryRedirect).Redirect(adminPathNameGroup + "/login") return } if !user.IsAdmin { c.Status(403).Text("Middleware : Not allowed to access this page") return } c.SetKey("korm-user", user) handler(c) } }
var AllModelsGet = func(c *ksmux.Context) { model := c.Param("model") if model == "" { c.Json(map[string]any{ "error": "Error: No model given in params", }) return } dbMem, _ := GetMemoryDatabase(defaultDB) if dbMem == nil { lg.ErrorC("unable to find db in mem", "db", defaultDB) dbMem = &databases[0] } idString := "id" var t *TableEntity for i, tt := range dbMem.Tables { if tt.Name == model { idString = tt.Pk t = &dbMem.Tables[i] } } rows, err := Table(model).Database(defaultDB).OrderBy("-" + idString).Limit(paginationPer).Page(1).All() if err != nil { rows, err = Table(model).Database(defaultDB).All() if err != nil { if err != ErrNoData { c.Error(404, "Unable to find this model") return } } } dbCols, cols := GetAllColumnsTypes(model) mmfkeys := map[string][]any{} if t != nil { for _, fkey := range t.Fkeys { spFrom := strings.Split(fkey.FromTableField, ".") if len(spFrom) == 2 { spTo := strings.Split(fkey.ToTableField, ".") if len(spTo) == 2 { q := "select " + spTo[1] + " from " + spTo[0] + " order by " + spTo[1] mm := []map[string]any{} err := To(&mm).Query(q) if !lg.CheckError(err) { ress := []any{} for _, res := range mm { ress = append(ress, res[spTo[1]]) } if len(ress) > 0 { mmfkeys[spFrom[1]] = ress } } else { lg.ErrorC("error:", "q", q, "spTo", spTo) } } } } } else { idString = cols[0] } if dbMem != nil { data := map[string]any{ "dbType": dbMem.Dialect, "model_name": model, "rows": rows, "dbcolumns": dbCols, "pk": idString, "fkeys": mmfkeys, "columnsOrdered": cols, } if t != nil { data["columns"] = t.ModelTypes } else { data["columns"] = dbCols } data["admin_path"] = adminPathNameGroup data["static_url"] = staticUrl c.Html("admin/admin_all_models.html", data) } else { lg.ErrorC("table not found", "table", model) c.Error(404, "Unable to find this model") } }
var AllModelsSearch = func(c *ksmux.Context) { model := c.Param("model") if model == "" { c.Json(map[string]any{ "error": "Error: No model given in params", }) return } body := c.BodyJson() blder := Table(model).Database(defaultDB) if query, ok := body["query"]; ok { if v, ok := query.(string); ok { if v != "" { blder.Where(v) } } else { c.Json(map[string]any{ "error": "Error: No query given in body", }) return } } oB := "" t, err := GetMemoryTable(model, defaultDB) if lg.CheckError(err) { c.Json(map[string]any{ "error": err, }) return } if orderby, ok := body["orderby"]; ok { if v, ok := orderby.(string); ok && v != "" { oB = v } else { oB = "-" + t.Pk } } else { oB = "-" + t.Pk } blder.OrderBy(oB) if v, ok := body["page_num"]; ok && v != "" { if page, ok := v.(string); !ok { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "expecting page_num to be a sring", }) return } else { pagenum, err := strconv.Atoi(page) if err == nil { blder.Limit(paginationPer).Page(pagenum) } else { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } } } else { blder.Limit(paginationPer).Page(1) } data, err := blder.All() if err != nil { c.Json(map[string]any{ "error": err.Error(), }) return } c.Json(map[string]any{ "rows": data, "cols": t.Columns, "types": t.ModelTypes, }) }
var ApiIndexHandler = func(c *ksmux.Context) { m := map[string]TableEntity{} for _, t := range registeredTables { tb, _ := GetMemoryTable(t) m[t] = tb } if len(tableMethods) == 0 { c.Text("error: no method are allowed for the api") return } if len(registeredTables) == 0 { c.Text("error: no registered tables") return } c.Html("admin/api.html", map[string]any{ "admin_path": adminPathNameGroup, "tables": registeredTables, "tbMem": m, "tbMethods": tableMethods, "static_url": staticUrl, "EndWithSlash": func(str string) bool { q := []rune(str) return q[len(q)-1] == '/' }, }) }
var Auth = func(handler ksmux.Handler) ksmux.Handler { return func(c *ksmux.Context) { session, err := c.GetCookie("session") if err != nil || session == "" { c.DeleteCookie("session") handler(c) return } session, err = aes.Decrypt(session) if err != nil { handler(c) return } user, err := Model[User]().Where("uuid = ?", session).One() if err != nil { handler(c) return } c.SetKey("korm-user", user) handler(c) } }
var BasicAuth = func(handler ksmux.Handler) ksmux.Handler { return ksmux.BasicAuth(handler, BASIC_AUTH_USER, BASIC_AUTH_PASS) }
var CreateModelView = func(c *ksmux.Context) { parseErr := c.Request.ParseMultipartForm(int64(ksmux.MultipartSize)) if parseErr != nil { lg.ErrorC(parseErr.Error()) return } data := c.Request.Form defer func() { err := c.Request.MultipartForm.RemoveAll() lg.CheckError(err) }() model := data["table"][0] m := map[string]any{} for key, val := range data { switch key { case "table": continue case "uuid": if v := m[key]; v == "" { m[key] = GenerateUUID() } else { m[key] = val[0] } case "password": hash, _ := argon.Hash(val[0]) m[key] = hash case "email": if !IsValidEmail(val[0]) { c.Json(map[string]any{ "error": "email not valid", }) return } m[key] = val[0] default: if key != "" && val[0] != "" && val[0] != "null" { m[key] = val[0] } } } _, err := Table(model).Database(defaultDB).Insert(m) if err != nil { lg.ErrorC("CreateModelView error", "err", err) c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } c.Json(map[string]any{ "success": "Done !", }) }
var DeleteRowPost = func(c *ksmux.Context) { data := c.BodyJson() if data["mission"] == "delete_row" { if model, ok := data["model_name"]; ok { if mm, ok := model.(string); ok { idString := "id" t, _ := GetMemoryTable(mm, defaultDB) if t.Pk != "" && t.Pk != "id" { idString = t.Pk } modelDB, err := Table(mm).Database(defaultDB).Where(idString+" = ?", data["id"]).One() if lg.CheckError(err) { lg.ErrorC("data received DeleteRowPost", "data", data) c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } if val, ok := modelDB["image"]; ok { if vv, ok := val.(string); ok && vv != "" { _ = c.DeleteFile(vv) } } if idS, ok := data["id"].(string); ok { _, err = Table(mm).Database(defaultDB).Where(idString+" = ?", idS).Delete() if err != nil { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) } else { c.Json(map[string]any{ "success": "Done !", "id": data["id"], }) return } } } else { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "expecting model_name to be string", }) return } } else { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "no model_name found in request body", }) return } } }
var DropTablePost = func(c *ksmux.Context) { data := c.BodyJson() if table, ok := data["table"]; ok && table != "" { if t, ok := data["table"].(string); ok { _, err := Table(t).Database(defaultDB).Drop() if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } } else { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "expecting 'table' to be string", }) } } else { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "missing 'table' in body request", }) } c.Json(map[string]any{ "success": fmt.Sprintf("table %s Deleted !", data["table"]), }) }
var ExportCSVView = func(c *ksmux.Context) { table := c.Param("table") if table == "" { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "no param table found", }) return } data, err := Table(table).Database(defaultDB).All() lg.CheckError(err) var buff bytes.Buffer writer := csv.NewWriter(&buff) cols := []string{} tab, _ := GetMemoryTable(table, defaultDB) if len(tab.Columns) > 0 { cols = tab.Columns } else if len(data) > 0 { d := data[0] for k := range d { cols = append(cols, k) } } err = writer.Write(cols) lg.CheckError(err) for _, sd := range data { values := []string{} for _, k := range cols { switch vv := sd[k].(type) { case string: values = append(values, vv) case bool: if vv { values = append(values, "true") } else { values = append(values, "false") } case int: values = append(values, strconv.Itoa(vv)) case int64: values = append(values, strconv.Itoa(int(vv))) case uint: values = append(values, strconv.Itoa(int(vv))) case time.Time: values = append(values, vv.String()) default: values = append(values, fmt.Sprintf("%v", vv)) } } err = writer.Write(values) lg.CheckError(err) } writer.Flush() c.Download(buff.Bytes(), table+".csv") }
var ExportView = func(c *ksmux.Context) { table := c.Param("table") if table == "" { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "no param table found", }) return } data, err := Table(table).Database(defaultDB).All() lg.CheckError(err) data_bytes, err := json.Marshal(data) lg.CheckError(err) c.Download(data_bytes, table+".json") }
var ImportView = func(c *ksmux.Context) { table := c.Request.FormValue("table") if table == "" { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "no table !", }) return } t, err := GetMemoryTable(table, defaultDB) if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } fname, dataBytes, err := c.UploadFile("thefile", "backup", "json", "csv") if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } isCsv := strings.HasSuffix(fname, ".csv") modelsOld, _ := Table(table).Database(defaultDB).All() if len(modelsOld) > 0 { modelsOldBytes, err := json.Marshal(modelsOld) if !lg.CheckError(err) { _ = os.MkdirAll(mediaDir+"/backup/", 0770) dst, err := os.Create(mediaDir + "/backup/" + table + "-" + time.Now().Format("2006-01-02") + ".json") lg.CheckError(err) defer dst.Close() _, err = dst.Write(modelsOldBytes) lg.CheckError(err) } } list_map := []map[string]any{} if isCsv { reader := csv.NewReader(bytes.NewReader(dataBytes)) lines, err := reader.ReadAll() if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } for _, values := range lines { m := map[string]any{} for i := range values { m[t.Columns[i]] = values[i] } list_map = append(list_map, m) } } else { err := json.Unmarshal(dataBytes, &list_map) if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } } // create models in database var retErr []error for _, m := range list_map { _, err = Table(table).Database(defaultDB).Insert(m) if err != nil { retErr = append(retErr, err) } } if len(retErr) > 0 { c.Json(map[string]any{ "success": "some data could not be added, " + errors.Join(retErr...).Error(), }) return } c.Json(map[string]any{ "success": "Import Done , you can see uploaded backups at ./" + mediaDir + "/backup folder", }) }
var IndexView = func(c *ksmux.Context) { allTables := GetAllTables(defaultDB) c.Html("admin/admin_index.html", map[string]any{ "admin_path": adminPathNameGroup, "static_url": staticUrl, "tables": allTables, }) }
var LoginPOSTView = func(c *ksmux.Context) { requestData := c.BodyJson() email := requestData["email"] passRequest := requestData["password"] data, err := Table("users").Database(defaultDB).Where("email = ?", email).One() if err != nil { c.Status(500).Json(map[string]any{ "error": err.Error(), }) return } if data["email"] == "" || data["email"] == nil { c.Status(http.StatusNotFound).Json(map[string]any{ "error": "User doesn not Exist", }) return } if data["is_admin"] == int64(0) || data["is_admin"] == 0 || data["is_admin"] == false { c.Status(http.StatusForbidden).Json(map[string]any{ "error": "Not Allowed to access this page", }) return } if passDB, ok := data["password"].(string); ok { if pp, ok := passRequest.(string); ok { if !argon.Match(passDB, pp) { c.Status(http.StatusForbidden).Json(map[string]any{ "error": "Wrong Password", }) return } else { if uuid, ok := data["uuid"].(string); ok { uuid, err = aes.Encrypt(uuid) lg.CheckError(err) c.SetCookie("session", uuid) c.Json(map[string]any{ "success": "U Are Logged In", }) return } } } } }
var LoginView = func(c *ksmux.Context) { c.Html("admin/admin_login.html", map[string]any{ "admin_path": adminPathNameGroup, "static_url": staticUrl, }) }
var LogoutView = func(c *ksmux.Context) { c.DeleteCookie("session") c.Status(http.StatusTemporaryRedirect).Redirect("/") }
var LogsView = func(c *ksmux.Context) { d := map[string]any{ "admin_path": adminPathNameGroup, "static_url": staticUrl, "secure": ksmux.IsTLS, } if v := lg.GetLogs(); v != nil { d["logs"] = reverseSlice[string](v.Slice) } c.Html("admin/logs.html", d) }
var ManifestView = func(c *ksmux.Context) { if embededDashboard { f, err := staticAndTemplatesFS[0].ReadFile(staticDir + "/manifest.json") if err != nil { lg.ErrorC("cannot embed manifest.json", "err", err) return } c.ServeEmbededFile("application/json; charset=utf-8", f) } else { c.ServeFile("application/json; charset=utf-8", staticDir+"/manifest.json") } }
var OfflineView = func(c *ksmux.Context) {
c.Text("<h1>YOUR ARE OFFLINE, check connection</h1>")
}
var RobotsTxtView = func(c *ksmux.Context) {
c.ServeFile("text/plain; charset=utf-8", "."+staticUrl+"/robots.txt")
}
var ServiceWorkerView = func(c *ksmux.Context) { if embededDashboard { f, err := staticAndTemplatesFS[0].ReadFile(staticDir + "/sw.js") if err != nil { lg.ErrorC("cannot embed sw.js", "err", err) return } c.ServeEmbededFile("application/javascript; charset=utf-8", f) } else { c.ServeFile("application/javascript; charset=utf-8", staticDir+"/sw.js") } }
var SingleModelGet = func(c *ksmux.Context) { model := c.Param("model") if model == "" { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "param model not defined", }) return } id := c.Param("id") if id == "" { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": "param id not defined", }) return } idString := "id" t, _ := GetMemoryTable(model, defaultDB) if t.Pk != "" && t.Pk != "id" { idString = t.Pk } modelRow, err := Table(model).Database(defaultDB).Where(idString+" = ?", id).One() if lg.CheckError(err) { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } dbCols, colsOrdered := GetAllColumnsTypes(model) mmfkeys := map[string][]any{} for _, fkey := range t.Fkeys { spFrom := strings.Split(fkey.FromTableField, ".") if len(spFrom) == 2 { spTo := strings.Split(fkey.ToTableField, ".") if len(spTo) == 2 { q := "select " + spTo[1] + " from " + spTo[0] + " order by " + spTo[1] mm, err := Table(spTo[0]).Database(defaultDB).QueryM(q) if !lg.CheckError(err) { ress := []any{} for _, res := range mm { ress = append(ress, res[spTo[1]]) } if len(ress) > 0 { mmfkeys[spFrom[1]] = ress } } } } } c.Html("admin/admin_single_model.html", map[string]any{ "admin_path": adminPathNameGroup, "static_url": staticUrl, "model": modelRow, "model_name": model, "id": id, "fkeys": mmfkeys, "columns": t.ModelTypes, "dbcolumns": dbCols, "pk": t.Pk, "columnsOrdered": colsOrdered, }) }
var UpdateRowPost = func(c *ksmux.Context) { data, files := c.ParseMultipartForm() id := data["row_id"][0] idString := "id" t, _ := GetMemoryTable(data["table"][0], defaultDB) if t.Pk != "" && t.Pk != "id" { idString = t.Pk } err := handleFilesUpload(files, data["table"][0], id, c, idString) if err != nil { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } modelDB, err := Table(data["table"][0]).Database(defaultDB).Where(idString+" = ?", id).One() if err != nil { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } ignored := []string{idString, "file", "image", "photo", "img", "fichier", "row_id", "table"} toUpdate := map[string]any{} for key, val := range data { if !SliceContains(ignored, key) { if modelDB[key] == val[0] { continue } toUpdate["`"+key+"`"] = val[0] } } s := "" values := []any{} if len(toUpdate) > 0 { for col, v := range toUpdate { if s == "" { s += col + "= ?" } else { s += "," + col + "= ?" } values = append(values, v) } } if s != "" { _, err := Table(data["table"][0]).Database(defaultDB).Where(idString+" = ?", id).Set(s, values...) if err != nil { c.Status(http.StatusBadRequest).Json(map[string]any{ "error": err.Error(), }) return } } s = "" if len(files) > 0 { for f := range files { if s == "" { s += f } else { s += "," + f } } } if len(toUpdate) > 0 { for k := range toUpdate { if s == "" { s += k } else { s += "," + k } } } c.Json(map[string]string{ "success": s + " updated successfully", }) }
Functions ¶
func AdaptNamedParams ¶ added in v1.8.0
func AddTrigger ¶
AddTrigger add trigger tablename_trig if col empty and tablename_trig_col if not
func DifferenceBetweenSlices ¶ added in v1.4.1
func DifferenceBetweenSlices[T comparable](slice1 []T, slice2 []T) []T
func DisableCache ¶
func DisableCache()
DisableCache disable the cache system, if and only if you are having problem with it, also you can korm.FlushCache on command too
func DownloadFile ¶ added in v1.6.1
func DropTrigger ¶
DropTrigger drop trigger tablename_trig if column empty and tablename_trig_column if not
func ExecContext ¶ added in v1.8.0
ExecContext exec sql and return error if any
func ExecContextNamed ¶ added in v1.8.0
func ExecContextNamed(ctx context.Context, query string, args map[string]any, dbName ...string) error
ExecContextNamed exec named sql and return error if any
func FlushCache ¶
func FlushCache()
FlushCache send msg to the cache system to Flush all the cache, safe to use in concurrent mode, and safe to use in general, it's done every 30 minutes(korm.FlushCacheEvery) and on update , create, delete , drop
func GenerateUUID ¶
func GenerateUUID() string
func GetAllColumnsTypes ¶
GetAllColumnsTypes get columns and types from the database
func GetAllTables ¶
GetAllTables get all tables for the optional dbName given, otherwise, if not args, it will return tables of the first connected database
func GetConnection ¶ added in v0.2.0
GetConnection get connection of dbName, if not specified , it return default, first database connected
func GetMemoryTableAndDB ¶ added in v1.4.1
func GetMemoryTableAndDB(tbName string, dbName ...string) (TableEntity, DatabaseEntity, error)
GetMemoryTable get a table from memory for specified or first connected db
func InitShell ¶
func InitShell() bool
InitShell init the shell and return true if used to stop main
func IsValidEmail ¶ added in v1.5.4
func JSON_ARRAY ¶ added in v1.93.2
func JSON_EXTRACT ¶ added in v1.93.2
func JSON_EXTRACT(dataJson string, opt ...JsonOption) string
func JSON_OBJECT ¶ added in v1.93.2
func JSON_REMOVE ¶ added in v1.93.2
func JSON_REMOVE(dataJson string, opt ...JsonOption) string
func JSON_SET ¶ added in v1.93.2
func JSON_SET(dataJson string, opt ...JsonOption) string
func LogQueries ¶ added in v1.7.7
func LogQueries()
LogQueries enable logging sql statements with time tooked
func ManyToMany ¶ added in v1.1.0
ManyToMany create m2m_table1_table2 many 2 many table
func New ¶ added in v0.4.0
New the generic way to connect to all handled databases
Example: korm.New(korm.SQLITE, "db", sqlitedriver.Use()) korm.New(korm.MYSQL,"dbName", mysqldriver.Use(), "user:password@localhost:3333") korm.New(korm.POSTGRES,"dbName", pgdriver.Use(), "user:password@localhost:5432")
func RegisterTable ¶ added in v1.4.7
func RegisterTable[T any](table TableRegistration[T], gendocs ...bool) error
func RemoveFromSlice ¶ added in v1.4.1
func RemoveFromSlice[T comparable](slice *[]T, elemsToRemove ...T)
func SetAdminPath ¶ added in v1.91.92
func SetAdminPath(path string)
SetAdminPath set admin path, default '/admin'
func SetCacheMaxMemory ¶ added in v1.4.3
func SetCacheMaxMemory(megaByte int)
SetCacheMaxMemory set max size of each cache cacheAllS AllM, minimum of 50 ...
func SliceContains ¶
func SliceContains[T comparable](elems []T, vs ...T) bool
func SliceToString ¶ added in v1.93.2
func SliceToString(slice interface{}) string
func StorageSize ¶ added in v1.4.5
func Transaction ¶ added in v1.3.9
Transaction create new database/sql transaction and return it, it can be rollback ...
func UnsafeNamedQuery ¶ added in v1.8.1
func WithBus ¶ added in v0.4.0
func WithBus(options ...ksbus.ServerOpts) *ksbus.Server
WithBus return ksbus.NewServer() that can be Run, RunTLS, RunAutoTLS
func WithDashboard ¶ added in v1.3.0
WithDashboard enable admin dashboard
func WithDocs ¶ added in v1.6.1
func WithDocs(generateJsonDocs bool, outJsonDocs string, handlerMiddlewares ...func(handler ksmux.Handler) ksmux.Handler) *ksbus.Server
WithDocs enable swagger docs at DocsUrl default to '/docs/'
func WithEmbededDocs ¶ added in v1.6.4
func WithEmbededDocs(embeded embed.FS, embededDirPath string, handlerMiddlewares ...func(handler ksmux.Handler) ksmux.Handler) *ksbus.Server
WithEmbededDocs same as WithDocs but embeded, enable swagger docs at DocsUrl default to '/docs/'
func WithMetrics ¶ added in v1.5.9
WithMetrics enable path /metrics (default), it take http.Handler like promhttp.Handler()
Types ¶
type BuilderM ¶
type BuilderM struct {
// contains filtered or unexported fields
}
BuilderM is query builder map string any
func BuilderMap ¶
func BuilderMap() *BuilderM
func (*BuilderM) AddRelated ¶ added in v1.1.0
func (b *BuilderM) AddRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
AddRelated used for many to many, and after korm.ManyToMany, to add a class to a student or a student to a class, class or student should exist in the database before adding them
func (*BuilderM) BulkInsert ¶ added in v1.2.6
BulkInsert insert many row at the same time in one query
func (*BuilderM) Delete ¶
Delete data from database, can be multiple, depending on the where, return affected rows(Not every database or database driver may support affected rows)
func (*BuilderM) DeleteRelated ¶ added in v1.1.0
func (b *BuilderM) DeleteRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
DeleteRelated delete a relations many to many
func (*BuilderM) GetRelated ¶ added in v1.1.0
GetRelated used for many to many to get related classes to a student or related students to a class
func (*BuilderM) Insert ¶
Insert add row to a table using input map, and return PK of the inserted row
func (*BuilderM) InsertR ¶ added in v1.3.6
InsertR add row to a table using input map, and return the inserted row
func (*BuilderM) JoinRelated ¶ added in v1.1.0
JoinRelated same as get, but it join data
func (*BuilderM) OrderBy ¶
OrderBy can be used like: OrderBy("-id","-email") OrderBy("id","-email") OrderBy("+id","email")
func (*BuilderM) QueryMNamed ¶ added in v1.9.5
func (b *BuilderM) QueryMNamed(statement string, args map[string]any, unsafe ...bool) ([]map[string]any, error)
QueryMNamed query sql and return result as slice maps
Example:
QueryMNamed("select * from users where email = :email",map[string]any{ "email":"email@mail.com", })
func (*BuilderM) Set ¶
Set used to update, Set("email,is_admin","example@mail.com",true) or Set("email = ? AND is_admin = ?","example@mail.com",true)
type BuilderS ¶
type BuilderS[T any] struct { // contains filtered or unexported fields }
BuilderS is query builder for struct using generics
func BuilderStruct ¶ added in v1.0.2
BuilderStruct empty query to struct starter, default db first connected
func ModelTable ¶ added in v1.4.9
func (*BuilderS[T]) AddRelated ¶ added in v1.3.6
func (b *BuilderS[T]) AddRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
AddRelated used for many to many, and after korm.ManyToMany, to add a class to a student or a student to a class, class or student should exist in the database before adding them
func (*BuilderS[T]) BulkInsert ¶ added in v1.3.6
BulkInsert insert many row at the same time in one query
func (*BuilderS[T]) Database ¶ added in v1.3.6
Database allow to choose database to execute query on
func (*BuilderS[T]) Debug ¶ added in v1.3.6
Debug print prepared statement and values for this operation
func (*BuilderS[T]) Delete ¶ added in v1.3.6
Delete data from database, can be multiple, depending on the where, return affected rows(Not every database or database driver may support affected rows)
func (*BuilderS[T]) DeleteRelated ¶ added in v1.3.6
func (b *BuilderS[T]) DeleteRelated(relatedTable string, whereRelatedTable string, whereRelatedArgs ...any) (int, error)
DeleteRelated delete a relations many to many
func (*BuilderS[T]) GetRelated ¶ added in v1.3.6
GetRelated used for many to many to get related classes to a student or related students to a class
func (*BuilderS[T]) InsertR ¶ added in v1.3.6
InsertR add row to a table using input struct, and return the inserted row
func (*BuilderS[T]) JoinRelated ¶ added in v1.3.6
JoinRelated same as get, but it join data
func (*BuilderS[T]) OrderBy ¶ added in v1.3.6
OrderBy can be used like: OrderBy("-id","-email") OrderBy("id","-email") OrderBy("+id","email")
func (*BuilderS[T]) Page ¶ added in v1.3.6
Page return paginated elements using Limit for specific page
func (*BuilderS[T]) QuerySNamed ¶ added in v1.9.5
func (b *BuilderS[T]) QuerySNamed(statement string, args map[string]any, unsafe ...bool) ([]T, error)
QueryNamedS query sql and return result as slice of structs T
Example:
QuerySNamed[models.User]("select * from users where email = :email",map[string]any{ "email":"email@mail.com", })
func (*BuilderS[T]) Set ¶ added in v1.3.6
Set used to update, Set("email,is_admin","example@mail.com",true) or Set("email = ? , is_admin = ?","example@mail.com",true)
type DashOpts ¶ added in v1.92.8
type DashOpts struct { ServerOpts *ksbus.ServerOpts EmbededStatic embed.FS EmbededTemplates embed.FS PaginatePer int // default 10 DocsUrl string // default docs MediaDir string // default media BaseDir string // default assets StaticDir string // default BaseDir/static TemplatesDir string // default BaseDir/templates Path string // default /admin RepoUser string // default kamalshkeir RepoName string // default korm-dashboard }
type DatabaseEntity ¶
type DatabaseEntity struct { Tables []TableEntity Name string Dialect string Conn *sql.DB }
DatabaseEntity hold memory db state
func GetMemoryDatabase ¶
func GetMemoryDatabase(dbName string) (*DatabaseEntity, error)
GetMemoryDatabase return the first connected database korm.DefaultDatabase if dbName "" or "default" else the matched db
func GetMemoryDatabases ¶
func GetMemoryDatabases() []DatabaseEntity
GetMemoryDatabases get all databases from memory
type Dialect ¶ added in v1.1.0
type Dialect = string
Dialect db dialects are SQLITE, POSTGRES, MYSQL, MARIA, COCKROACH
type DocsError ¶ added in v1.6.9
type DocsError struct {
Error string `json:"error" example:"error message"`
}
type DocsSuccess ¶ added in v1.6.9
type DocsSuccess struct {
Success string `json:"success" example:"success message"`
}
type ExecerQueryerContext ¶ added in v1.7.7
type ExecerQueryerContext struct {
// contains filtered or unexported fields
}
ExecerQueryerContext implements database/sql.driver.ExecerContext and database/sql.driver.QueryerContext
func (ExecerQueryerContext) ExecContext ¶ added in v1.8.0
func (ExecerQueryerContext) PrepareContext ¶ added in v1.8.0
func (ExecerQueryerContext) QueryContext ¶ added in v1.8.0
type ExecerQueryerContextWithSessionResetter ¶ added in v1.7.7
type ExecerQueryerContextWithSessionResetter struct { *SessionResetter // contains filtered or unexported fields }
ExecerQueryerContext implements database/sql.driver.ExecerContext and database/sql.driver.QueryerContext
func (ExecerQueryerContextWithSessionResetter) Close ¶ added in v1.8.0
func (conn ExecerQueryerContextWithSessionResetter) Close() error
func (ExecerQueryerContextWithSessionResetter) ExecContext ¶ added in v1.8.0
func (ExecerQueryerContextWithSessionResetter) PrepareContext ¶ added in v1.8.0
func (ExecerQueryerContextWithSessionResetter) QueryContext ¶ added in v1.8.0
type Hooks ¶ added in v1.7.7
type Hooks interface { Before(ctx context.Context, query string, args ...interface{}) (context.Context, error) After(ctx context.Context, query string, args ...interface{}) (context.Context, error) }
Hooks instances may be passed to Wrap() to define an instrumented driver
type JsonOption ¶ added in v1.93.2
type OnErrorer ¶ added in v1.7.7
type OnErrorer interface {
OnError(ctx context.Context, err error, query string, args ...interface{}) error
}
OnErrorer instances will be called if any error happens
type Selector ¶ added in v1.9.6
type Selector[T any] struct { // contains filtered or unexported fields }
type SessionResetter ¶ added in v1.7.7
type SessionResetter struct {
// contains filtered or unexported fields
}
type Stmt ¶ added in v1.7.7
Stmt implements a database/sql/driver.Stmt
func (*Stmt) ExecContext ¶ added in v1.7.7
func (*Stmt) QueryContext ¶ added in v1.7.7
type TableEntity ¶
type TableEntity struct { Types map[string]string ModelTypes map[string]string Tags map[string][]string Columns []string Fkeys []kormFkey Pk string Name string }
DatabaseEntity hold table state
func GetMemoryTable ¶
func GetMemoryTable(tbName string, dbName ...string) (TableEntity, error)
GetMemoryTable get a table from memory for specified or first connected db
type TableRegistration ¶ added in v1.4.6
type TableRegistration[T any] struct { TableName string Middws []func(handler ksmux.Handler) ksmux.Handler Methods []string BuilderGetAll func(modelBuilder *BuilderS[T]) *BuilderS[T] BuilderGetOne func(modelBuilder *BuilderS[T]) *BuilderS[T] }
func (*TableRegistration[T]) HaveMethod ¶ added in v1.4.6
func (tr *TableRegistration[T]) HaveMethod(method string) bool
type User ¶ added in v1.3.0
type User struct { Id int `json:"id,omitempty" korm:"pk"` Uuid string `json:"uuid,omitempty" korm:"size:40;iunique"` Email string `json:"email,omitempty" korm:"size:50;iunique"` Password string `json:"password,omitempty" korm:"size:150;default:''"` IsAdmin bool `json:"is_admin,omitempty" korm:"default:false"` Image string `json:"image,omitempty" korm:"size:100;default:''"` CreatedAt time.Time `json:"created_at,omitempty" korm:"now"` }