add: impl tags, template, payee query api

This commit is contained in:
leo 2021-11-22 18:05:12 +08:00
parent 09e75df763
commit 9a0bd56cb2
5 changed files with 146 additions and 26 deletions

View File

@ -9,9 +9,12 @@ import (
) )
type QueryParams struct { type QueryParams struct {
Where bool `bql:"where"`
Year int `bql:"year ="` Year int `bql:"year ="`
Month int `bql:"month ="` Month int `bql:"month ="`
AccountType string `bql:"account ~"` AccountType string `bql:"account ~"`
OrderBy string `bql:"order by"`
Limit int `bql:"limit"`
} }
func BQLQueryOne(ledgerConfig *Config, queryParams *QueryParams, queryResultPtr interface{}) error { func BQLQueryOne(ledgerConfig *Config, queryParams *QueryParams, queryResultPtr interface{}) error {
@ -62,9 +65,9 @@ func bqlRawQuery(ledgerConfig *Config, queryParamsPtr *QueryParams, queryResultP
} }
} }
} }
bql += " '\\'"
// 查询条件不为空时,拼接查询条件 // 查询条件不为空时,拼接查询条件
if queryParamsPtr != nil { if queryParamsPtr != nil {
bql += " '\\' WHERE"
queryParamsType := reflect.TypeOf(queryParamsPtr).Elem() queryParamsType := reflect.TypeOf(queryParamsPtr).Elem()
queryParamsValue := reflect.ValueOf(queryParamsPtr).Elem() queryParamsValue := reflect.ValueOf(queryParamsPtr).Elem()
for i := 0; i < queryParamsType.NumField(); i++ { for i := 0; i < queryParamsType.NumField(); i++ {
@ -74,7 +77,13 @@ func bqlRawQuery(ledgerConfig *Config, queryParamsPtr *QueryParams, queryResultP
case reflect.String: case reflect.String:
val := valueField.String() val := valueField.String()
if val != "" { if val != "" {
bql = fmt.Sprintf("%s %s '%s' AND", bql, typeField.Tag.Get("bql"), val) if typeField.Name == "OrderBy" {
// 去除上一个条件后缀的 AND 关键字
bql = strings.Trim(bql, " AND")
bql = fmt.Sprintf("%s %s %s", bql, typeField.Tag.Get("bql"), val)
} else {
bql = fmt.Sprintf("%s %s '%s' AND", bql, typeField.Tag.Get("bql"), val)
}
} }
break break
case reflect.Int: case reflect.Int:
@ -83,11 +92,15 @@ func bqlRawQuery(ledgerConfig *Config, queryParamsPtr *QueryParams, queryResultP
bql = fmt.Sprintf("%s %s %d AND", bql, typeField.Tag.Get("bql"), val) bql = fmt.Sprintf("%s %s %d AND", bql, typeField.Tag.Get("bql"), val)
} }
break break
case reflect.Bool:
val := valueField.Bool()
if val {
bql = fmt.Sprintf("%s %s ", bql, typeField.Tag.Get("bql"))
}
break
} }
} }
bql = strings.TrimRight(bql, " AND") bql = strings.TrimRight(bql, " AND")
} else {
bql += " '\\'"
} }
return queryByBQL(ledgerConfig, bql) return queryByBQL(ledgerConfig, bql)
} }
@ -120,7 +133,10 @@ func parseResult(output string, queryResultPtr interface{}, selectOne bool) erro
} }
switch field.Type.Kind() { switch field.Type.Kind() {
case reflect.String: case reflect.String:
temp[jsonName] = strings.Trim(val, " ") v := strings.Trim(val, " ")
if v != "" {
temp[jsonName] = v
}
break break
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
// 去除空格 // 去除空格

View File

@ -13,3 +13,7 @@ func GetExampleLedgerConfigDirPath() string {
} }
return currentPath + "/example" return currentPath + "/example"
} }
func GetLedgerTransactionsTemplateFilePath(dataPath string) string {
return dataPath + "/.beancount-ns/transaction_template.json"
}

View File

@ -47,9 +47,14 @@ func RegisterRouter(router *gin.Engine) {
// need authorized // need authorized
authorized.GET("/stats/months", service.MonthsList) authorized.GET("/stats/months", service.MonthsList)
authorized.GET("/transactions", service.QueryTransactions) authorized.GET("/transactions", service.QueryTransactions)
authorized.GET("/transactions/payee", service.QueryTransactionsPayee)
authorized.GET("/transactions/template", service.QueryTransactionsTemplate)
authorized.GET("/tags", service.QueryTags)
// 兼容旧版本 // 兼容旧版本
authorized.GET("/entry", service.QueryTransactions) authorized.GET("/entry", service.QueryTransactions)
authorized.GET("/payee", service.QueryTransactionsPayee)
authorized.GET("/transaction/template", service.QueryTransactionsTemplate)
} }
} }

29
service/tags.go Normal file
View File

@ -0,0 +1,29 @@
package service
import (
"github.com/beancount-gs/script"
"github.com/gin-gonic/gin"
)
type Tags struct {
Value string `bql:"distinct tags" json:"value"`
}
func QueryTags(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
tags := make([]Tags, 0)
err := script.BQLQueryList(ledgerConfig, nil, &tags)
if err != nil {
InternalError(c, err.Error())
return
}
result := make([]string, 0)
for _, t := range tags {
if t.Value != "" {
result = append(result, t.Value)
}
}
OK(c, result)
}

View File

@ -1,12 +1,38 @@
package service package service
import ( import (
"github.com/beancount-gs/script" "encoding/json"
script "github.com/beancount-gs/script"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"strconv" "strconv"
"strings" "strings"
) )
func getQueryModel(c *gin.Context) script.QueryParams {
var queryParams script.QueryParams
var hasWhere bool
if c.Query("year") != "" {
val, err := strconv.Atoi(c.Query("year"))
if err == nil {
queryParams.Year = val
hasWhere = true
}
}
if c.Query("month") != "" {
val, err := strconv.Atoi(c.Query("month"))
if err == nil {
queryParams.Month = val
hasWhere = true
}
}
if c.Query("type") != "" {
queryParams.AccountType = c.Query("type")
hasWhere = true
}
queryParams.Where = hasWhere
return queryParams
}
type Transactions struct { type Transactions struct {
Id string `bql:"id" json:"id"` Id string `bql:"id" json:"id"`
Date string `bql:"date" json:"date"` Date string `bql:"date" json:"date"`
@ -20,29 +46,11 @@ type Transactions struct {
CommoditySymbol string `json:"commoditySymbol"` CommoditySymbol string `json:"commoditySymbol"`
} }
func getQueryModel(c *gin.Context) script.QueryParams {
var queryParams script.QueryParams
if c.Query("year") != "" {
val, err := strconv.Atoi(c.Query("year"))
if err == nil {
queryParams.Year = val
}
}
if c.Query("month") != "" {
val, err := strconv.Atoi(c.Query("month"))
if err == nil {
queryParams.Month = val
}
}
if c.Query("type") != "" {
queryParams.AccountType = c.Query("type")
}
return queryParams
}
func QueryTransactions(c *gin.Context) { func QueryTransactions(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c) ledgerConfig := script.GetLedgerConfigFromContext(c)
queryParams := getQueryModel(c) queryParams := getQueryModel(c)
// 倒序查询
queryParams.OrderBy = "date desc"
transactions := make([]Transactions, 0) transactions := make([]Transactions, 0)
err := script.BQLQueryList(ledgerConfig, &queryParams, &transactions) err := script.BQLQueryList(ledgerConfig, &queryParams, &transactions)
if err != nil { if err != nil {
@ -61,3 +69,61 @@ func QueryTransactions(c *gin.Context) {
} }
OK(c, transactions) OK(c, transactions)
} }
type transactionsPayee struct {
Value string `bql:"distinct payee" json:"value"`
}
func QueryTransactionsPayee(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
payeeList := make([]transactionsPayee, 0)
queryParams := script.QueryParams{Where: false, OrderBy: "date desc", Limit: 100}
err := script.BQLQueryList(ledgerConfig, &queryParams, &payeeList)
if err != nil {
InternalError(c, err.Error())
return
}
result := make([]string, 0)
for _, payee := range payeeList {
if payee.Value != "" {
result = append(result, payee.Value)
}
}
OK(c, result)
}
type transactionsTemplate struct {
Id string `json:"id"`
Date string `json:"date"`
TemplateName string `json:"templateName"`
Payee string `json:"payee"`
Desc string `json:"desc"`
Entries []transactionsTemplateEntity `json:"entries"`
}
type transactionsTemplateEntity struct {
Account string `json:"account"`
Commodity string `json:"commodity"`
Amount string `json:"amount"`
}
func QueryTransactionsTemplate(c *gin.Context) {
ledgerConfig := script.GetLedgerConfigFromContext(c)
filePath := script.GetLedgerTransactionsTemplateFilePath(ledgerConfig.DataPath)
if script.FileIfExist(filePath) {
bytes, err := script.ReadFile(filePath)
if err != nil {
InternalError(c, err.Error())
return
}
result := make([]transactionsTemplate, 0)
err = json.Unmarshal(bytes, &result)
if err != nil {
InternalError(c, err.Error())
return
}
OK(c, result)
} else {
OK(c, new([]string))
}
}