JGo provides an easier configuration for writing sql, log, and cron jobs.
JGo Web:https://jgo.dev
JGo Web Project:https://github.com/xjustloveux/jgo.web
JGo minimizes dependencies on third-party middleware to avoid conflicts.
jlog only import logrus middleware.
jsql only import govaluate middleware, but it is designed on the basis of mysql, go-mssqldb, godror and pq.
go get github.com/xjustloveux/jgo
Configuration file default json
format, you can use jsql.SetFormat
to set you want, but you must be used
jfile.RegisterCodec register codec.
Property Name | Required | Type | Default Value | Comment |
---|---|---|---|---|
DaoPath | true | string | empty | It your xml files folder path. |
Default | true | string | empty | It your default DataSource name. |
DataSource | true | map[string]interface{} | empty | |
DataSource.Type | true | string | empty | You can set MySql , MSSql , Oracle or PostgreSql , others as long as the sql parameter supports '?'. |
DataSource.DSN | true | string | empty | DataSourceName. If you have information security considerations, you can encrypt the DataSource into a string, and set the decryption function. |
DataSource.DN | false | string | empty | DriverName. If your type is MySql , MSSql , Oracle or PostgreSql , the DriverName default use mysql, go-mssqldb, godror and pq driver. You also can set this value to use your DriverName. |
DataSource.DbName | false | string | empty | It your db name. |
DataSource.ConnMaxLifetime | false | time.Duration | 120 | |
DataSource.ConnMaxLifetimeDuration | false | string | Second | Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day |
DataSource.ConnMaxIdleTime | false | time.Duration | 0 | |
DataSource.ConnMaxIdleTimeDuration | false | string | Hour | Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day |
DataSource.MaxOpenConns | false | int | 0 | |
DataSource.MaxIdleConns | false | int | 0 | |
DataSource.EncodeData | false | string | empty | If you have information security considerations, you can encrypt the DataSource into a string, and set the decryption Format and function. |
DataSource.Format | false | jfile.Format | jfile.Json | DataSource.EncodeData format. If you want use other format, you must be use jfile.RegisterCodec register codec. |
{
"db": {
"daoPath": "dao/",
"default": "exampleMySql",
"dataSource": {
"exampleMySql": {
"type": "MySql",
"dsn": "user:password@tcp(192.168.1.1:3306)/DBName?checkConnLiveness=false&maxAllowedPacket=0&charset=utf8mb4&parseTime=true",
"dbName": "DBName"
},
"exampleMSSql": {
"type": "MSSql",
"dsn": "Data Source=192.168.1.1,1433;Initial Catalog=DBName;Integrated Security=False;User ID=user;Password=password;Connection Timeout=120;MultipleActiveResultSets=True",
"dbName": "DBName"
},
"exampleOracle": {
"type": "Oracle",
"dsn": "user/password@192.168.1.1:1521/ORCLCDB",
"dbName": "DBName"
},
"examplePostgreSql": {
"type": "PostgreSql",
"dsn": "postgresql://user:password@192.168.1.1:5432/DBName?sslmode=disable",
"dbName": "DBName"
}
}
}
}
For details, please refer to XmlTag.
<?xml version="1.0" encoding="UTF-8"?>
<dao>
<select id="example1">
SELECT * FROM TABLE1
</select>
<select id="example2">
SELECT * FROM TABLE2
<where>
COL1 = @{COL1}
<if test="!nil(COL2) and COL2 != ''">
AND COL2 = @{COL2}
</if>
</where>
</select>
<select id="example3">
SELECT ${COL1}, ${COL2} FROM TABLE3
<orderBy last="true">
${SORT} DESC
</orderBy>
</select>
<select id="example4">
SELECT
<foreach params="list" open="" separator="," close="">
#{val}
</foreach>
FROM TABLE4
</select>
<insert id="insertExample">
INSERT INTO ${TABLE}
<foreach params="list" open="(" separator="," close=")">
#{val}
</foreach>
VALUES
<foreach params="list" open="(" separator="," close=")">
@{#{val}}
</foreach>
</insert>
</dao>
package main
import (
"fmt"
_ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql"
_ "github.com/godror/godror"
_ "github.com/lib/pq"
"github.com/xjustloveux/jgo/jsql"
)
func main() {
if err := jsql.Init(); err != nil {
fmt.Println(err)
return
}
}
package main
func example1() {
// SELECT * FROM TABLE1
if agent, err := jsql.GetAgent(); err != nil {
fmt.Println(err)
} else {
var res jsql.Result
if res, err = agent.Query("example1"); err != nil {
fmt.Println(err)
} else {
for _, item := range res.Rows() {
fmt.Println(item)
}
}
}
}
package main
func example2() {
// SELECT * FROM TABLE2 WHERE COL1 = ? AND COL2 = ?
param := make(map[string]interface{})
param["COL1"] = "VAL1"
param["COL2"] = "VAL2"
if agent, err := jsql.GetAgent(); err != nil {
fmt.Println(err)
} else {
var res jsql.Result
if res, err = agent.QueryPage("example2", 6, 10, param); err != nil {
fmt.Println(err)
} else {
fmt.Println(res.TotalRecord())
for _, item := range res.Rows() {
fmt.Println(item)
}
}
}
}
package main
func example3() {
// SELECT COL_NAME1, COL_NAME2 FROM TABLE3 ORDER BY SORT_COL_NAME DESC
param := make(map[string]interface{})
param["COL1"] = "COL_NAME1"
param["COL2"] = "COL_NAME2"
param["SORT"] = "SORT_COL_NAME"
if agent, err := jsql.GetAgent("exampleMSSql"); err != nil {
fmt.Println(err)
} else {
var res jsql.Result
if res, err = agent.QueryPage("example3", 6, 10, param); err != nil {
fmt.Println(err)
} else {
fmt.Println(res.TotalRecord())
for _, item := range res.Rows() {
fmt.Println(item)
}
}
}
// you also can use struct
type Param struct {
COL1 string
COL2 string
SORT string
}
param2 := Param{
COL1: "COL_NAME1",
COL2: "COL_NAME2",
SORT: "SORT_COL_NAME",
}
type Data struct {
COL_NAME1 string
COL_NAME2 string
}
type List struct {
Rows []Data
}
var list List
if agent, err := jsql.GetAgent("exampleMSSql"); err != nil {
fmt.Println(err)
} else {
if _, err = agent.QueryPage("example3", 6, 10, param2, &list); err != nil {
fmt.Println(err)
} else {
fmt.Println(list)
}
}
}
package main
func example4() {
// SELECT COL_NAME1, COL_NAME2 FROM TABLE4
param := make(map[string]interface{})
list := []string{"COL_NAME1", "COL_NAME2"}
param["list"] = list
if agent, err := jsql.GetAgent("exampleOracle"); err != nil {
fmt.Println(err)
} else {
var res jsql.Result
if res, err = agent.QueryPage("example4", 6, 10, param); err != nil {
fmt.Println(err)
} else {
fmt.Println(res.TotalRecord())
for _, item := range res.Rows() {
fmt.Println(item)
}
}
}
}
package main
func example5() {
// INSERT INTO TABLE5 (COL_NAME1, COL_NAME2, COL_NAME3) VALUES (?, ?, ?)
list := []string{"COL_NAME1", "COL_NAME2", "COL_NAME3"}
param := make(map[string]interface{})
param["list"] = list
param["TABLE"] = "TABLE5"
param["COL_NAME1"] = 123
param["COL_NAME2"] = "Test"
param["COL_NAME3"] = time.Now()
if agent, err := jsql.GetAgent(); err != nil {
fmt.Println(err)
} else {
if _, err = agent.Insert("insertExample", param); err != nil {
fmt.Println(err)
}
}
}
package main
func example6() {
// INSERT INTO TABLE5 (COL_NAME1, COL_NAME2, COL_NAME3) VALUES (?, ?, ?)
list := []string{"COL_NAME1", "COL_NAME2", "COL_NAME3"}
param := make(map[string]interface{})
param["list"] = list
param["TABLE"] = "TABLE5"
param["COL_NAME1"] = 123
param["COL_NAME2"] = "Test1"
param["COL_NAME3"] = time.Now()
if agent, err := jsql.GetAgent(); err != nil {
fmt.Println(err)
} else {
// or you can use agent.UseTx easier
if _, err = agent.Begin(); err != nil {
fmt.Println(err)
} else {
defer func() {
if err != nil {
if e := agent.Rollback(); e != nil {
fmt.Println(e)
}
}
}()
if _, err = agent.InsertTx("insertExample", param); err != nil {
fmt.Println(err)
return
}
param["COL_NAME1"] = 456
param["COL_NAME2"] = "Test2"
param["COL_NAME3"] = time.Now()
if _, err = agent.InsertTx("insertExample", param); err != nil {
fmt.Println(err)
return
}
if err = agent.Commit(); err != nil {
fmt.Println(err)
}
}
}
}
package main
func example7() {
// SELECT * FROM TABLE6 WHERE COL1 = ?
var res jsql.Result
ta := &jsql.TableAgent{Table: "TABLE6"}
ta.Equal("COL1", "VAL1")
if res, err = ta.QueryPage(6, 10); err != nil {
fmt.Println(err)
} else {
fmt.Println(res.TotalRecord())
for _, item := range res.Rows() {
fmt.Println(item)
}
}
}
Tag Name | Layer | Attr Name | Required | Type | Comment |
---|---|---|---|---|---|
dao | 1 | true | |||
select | 2 | ||||
id | true | string | |||
insert | 2 | ||||
id | true | string | |||
update | 2 | ||||
id | true | string | |||
delete | 2 | string | |||
id | true | string | |||
other | 2 | string | |||
id | true | string | |||
if | 3 up | ||||
test | true | string | expression, support nil check use nil() middleware: govaluate |
||
foreach | 3 up | ||||
params | true | string | param key, param type can be map or slice | ||
open | false | string | |||
separator | false | string | |||
close | false | string | |||
where | 3 up | ||||
orderBy | 3 up | ||||
last | false | bool | for QueryPage |
Configuration file default json
format, you can use jcron.SetFormat
to set you want, but you must be used
jfile.RegisterCodec register codec.
Property Name | Required | Type | Default Value | Comment |
---|---|---|---|---|
Location | false | string | empty | time location |
Schedule | true | []*SchInfo | empty | |
Schedule.Name | true | string | empty | schedule name. |
Schedule.Cron | true | string | empty | CronExpression. |
Schedule.JobName | true | string | empty | schedule job name. |
Schedule.JobData | false | map[string]interface{} | empty | schedule job data. |
Schedule.Desc | false | string | empty | schedule job description. |
Schedule.Status | false | string | run | schedule status. |
{
"cron": {
"schedule": [
{
"Name": "Sch01",
"Cron": "7-43/13 * * * * ? *",
"JobName": "Job01",
"JobData": {
"data": "val"
},
"Desc": "this is schedule 01-----------"
},
{
"Name": "Sch02",
"Cron": "3,7,11,32-57/7 * * * * ? *",
"JobName": "Job02",
"JobData": {},
"Desc": "this is schedule 02-----------"
}
]
}
}
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jcron"
"github.com/xjustloveux/jgo/jtime"
"time"
)
func main() {
if err := jcron.Init(); err != nil {
fmt.Println(err)
return
}
if err := jcron.AddJobFunc("Job01", Job01); err != nil {
fmt.Println(err)
return
}
if err := jcron.AddJobFunc("Job02", Job02); err != nil {
fmt.Println(err)
return
}
jcron.Start()
select {
case <-time.After(3 * jtime.Minute):
}
jcron.Wait()
}
func Job01(data map[string]interface{}) {
// do something
}
func Job02(data map[string]interface{}) {
// do something
}
Name | Required | Allowed Values | Allowed Special Characters |
---|---|---|---|
Seconds | true | 0-59 | ,-*/ |
Minutes | true | 0-59 | ,-*/ |
Hours | true | 0-23 | ,-*/ |
Day of month | true | 1-31 | ,-*/? |
Month | true | 1-12 or January-December or JAN-DEC | ,-*/ |
Day of week | true | 0-6 or Sunday-Saturday or SUN-SAT | ,-*/? |
Year | false | 2020-2080 | ,-*/ |
Configuration file default json
format, you can use jlog.SetFormat
to set you want, but you must be used
jfile.RegisterCodec register codec.
Property Name | Required | Type | Default Value | Comment |
---|---|---|---|---|
Params | false | map[string]interface{} | empty | Appender.Output.P and Appender.Output.LinkName replace params |
Default | false | []string | empty | Appender name |
Appender | true | map[string]interface{} | empty | |
Appender.Level | false | string | info | logrus.Level |
Appender.ReportCaller | false | bool | true | logrus.ReportCaller |
Appender.Formatter | false | *formatter | default formatter | |
Appender.Formatter.Type | false | string | TEXT | TEXT , JSON |
Appender.Formatter.Location | false | string | empty | time location |
Appender.Formatter.Text | false | *logrus.TextFormatter | &logrus.TextFormatter{TimestampFormat: jtime.DateTime} | |
Appender.Formatter.Json | false | *logrus.JSONFormatter | &logrus.JSONFormatter{TimestampFormat: jtime.DateTime} | |
Appender.Output | true | *output | default output | |
Appender.Output.Name | false | string | empty | writer name. you can use .AddWriter add writer before .Init |
Appender.Output.P | true | string | empty | log file path. default ${Program} tag replace program name. time format refer to FormatString |
Appender.Output.Clock | false | string | Local | *time.Location string, use for file path time format. |
Appender.Output.LinkName | false | string | empty | symlink file path. default ${Program} tag replace program name. time format refer to FormatString |
Appender.Output.MaxAge | false | time.Duration | 365 | MaxAge number |
Appender.Output.MaxAgeDuration | false | string | Day | Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day |
Appender.Output.RotationTime | false | time.Duration | 24 | RotationTime number |
Appender.Output.RotationTimeDuration | false | string | Hour | Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day |
Appender.Output.RotationSize | false | int64 | 10 | RotationSize number |
Appender.Output.RotationSizeUnit | false | string | MB | Byte, Kb, KB, Mb, MB, Gb, GB, Tb, TB, Pb, PB, Eb, EB |
Appender.Output.RotationCount | false | int | 0 | RotationCount number |
Appender.Output.Handler | false | string | empty | handler name. you can use .AddHandler add handler before .Init |
Logs | true | []*logs | empty | |
Logs.Program | true | []string | empty | go program name. ex: main or main.go or pkg:sample |
Logs.Appender | true | []string | empty | Appender name. |
Note: jlog.Init
default create 'default' program name and 'console' appender name.
{
"log": {
"params": {
"path": "/log"
},
"appender": {
"sys": {
"level": "Error",
"formatter": {
"type": "JSON"
},
"output": {
"p": "${path}/sys/%yyyy-%MM-%dd/system.log",
"utc": false,
"linkName": "${path}/sys/system",
"rotationSize": 100,
"rotationSizeUnit": "KB"
}
},
"web": {
"formatter": {
"text": {
"timestampFormat": "2006-01-02"
}
},
"output": {
"p": "${path}/web/%yyyy-%MM-%dd/website.log",
"linkName": "${path}/web/website"
}
}
},
"logs": [
{
"program": [
"program1",
"main"
],
"appender": [
"sys"
]
},
{
"program": [
"program2"
],
"appender": [
"console",
"web"
]
},
{
"program": [
"pkg:packageName"
],
"appender": [
"console",
"sys"
]
}
]
}
}
sys appender log
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jlog"
"time"
)
func main() {
if err := jlog.Init(); err != nil {
fmt.Println(err)
return
}
jlog.Info("info message")
jlog.Warn(time.Now())
jlog.Error(fmt.Errorf("error message"))
}
console and web appender log
package main
func example() {
jlog.Info("this is program2")
}
type Example struct{
str string
}
m := make(map[string]interface{})
m["str"] = "example"
ex := Example{}
jfile.Convert(m, &ex)
package main
import (
"encoding/json"
"github.com/xjustloveux/jgo/jfile"
)
type jsonCodec struct{}
func (jsonCodec) Encode(m map[string]interface{}) ([]byte, error) {
return json.MarshalIndent(m, "", " ")
}
func (jsonCodec) Decode(b []byte, m map[string]interface{}) error {
return json.Unmarshal(b, &m)
}
func main() {
jfile.RegisterCodec(jfile.Json.String(), jsonCodec{})
}
E.g. 2022-06-20 14:44:55.012345678 -0700 MST IN America/Phoenix Location
Pattern | Description | E.g. |
---|---|---|
%d | day in month, 1-31 | 20 |
%dd | day in month, 01-31 | 20 |
%ddd | day in week, Sun-Mon | Mon |
%dddd | day in week, Sunday-Monday | Monday |
%D | day in year, 1-366 | 171 |
%DD | day in year, 01-366 | 171 |
%DDD | day in year, 001-366 | 171 |
%f | nanosecond, 0-9999 | 0 |
%ff | nanosecond, 00-9999 | 01 |
%fff | nanosecond, 000-9999 | 012 |
%ffff | nanosecond, 0000-9999 | 0123 |
%F | nanosecond, -9999 | |
%FF | nanosecond, -9999 | 01 |
%FFF | nanosecond, -9999 | 012 |
%FFFF | nanosecond, -9999 | 0123 |
%g | Era designator, A.D. or B.C. | A.D. |
%h | hour in day, 0-11 | 2 |
%hh | hour in day, 00-11 | 02 |
%H | hour in day, 0-23 | 14 |
%HH | hour in day, 00-23 | 14 |
%k | hour in day, 1-12 | 2 |
%kk | hour in day, 01-12 | 02 |
%K | hour in day, 1-24 | 14 |
%KK | hour in day, 01-24 | 14 |
%l | time zone name | America/Phoenix |
%m | minute in hour, 0-59 | 44 |
%mm | minute in hour, 00-59 | 44 |
%M | month in year, 1-12 | 6 |
%MM | month in year, 01-12 | 06 |
%MMM | month in year, Jan-Dec | Jun |
%MMMM | month in year, January-December | June |
%s | second in minute, 0-59 | 55 |
%ss | second in minute, 00-59 | 55 |
%t | AM/PM marker | P |
%tt | AM/PM marker | PM |
%w | week in year, 1-53 | 25 |
%W | day in week, 0-6 | 1 |
%y | year | 22 |
%yy | year | 22 |
%yyy | year | 2022 |
%yyyy | year | 2022 |
%z | time zone offset from UTC, hour | -7 |
%zz | time zone offset from UTC, hour | -07 |
%zzz | time zone offset from UTC, hour and minute | -07:00 |
%zzzz | time zone offset from UTC, second | -25200 |
%Z | time zone name | MST |
jsql, jlog, jcron, jconf support environment variables.
Config required to be set file name, this file will be basic setting.
jsql, jlog, jcron default file name is 'config.json'.
You can override the basic setting by setting the env file name, env val or env key.
{
"val": 123,
"type": "default"
}
{
"type": "override",
"name": "test"
}
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jconf"
)
func main() {
conf := jconf.New()
conf.SetFileName("default.json")
conf.SetEnvFileName("override.json")
if err := conf.Load(); err != nil {
fmt.Println(err)
}
}
{
"val": 123,
"type": "override",
"name": "test"
}
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jconf"
)
func main() {
conf := jconf.New()
conf.SetFileName("default.json")
conf.SetEnvVal("dev")
// Override file name is 'default-dev.json'.
if err := conf.Load(); err != nil {
fmt.Println(err)
}
}
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jconf"
)
func main() {
conf := jconf.New()
conf.SetFileName("default.json")
conf.SetEnvKey("goEnv")
// If the 'default.json' file or os have 'goEnv' environment variables.
// Override file name is 'default-$goEnv.json'.
// E.g. goEnv value is 'dev', then the override file name is 'default-dev.json'.
if err := conf.Load(); err != nil {
fmt.Println(err)
}
}
package main
import (
"fmt"
"github.com/xjustloveux/jgo/jconf"
)
func main() {
conf := jconf.New()
conf.SetFileName("default.json")
// If the 'default.json' file or os have 'jEnv' environment variables.
// Override file name is 'default-$jEnv.json'.
// E.g. jEnv value is 'dev', then the override file name is 'default-dev.json'.
if err := conf.Load(); err != nil {
fmt.Println(err)
}
}
jcast , jconf , jcron , jevent , jfile , jlog , jruntime , jslice , jsql , jtime