v2.3.6 - Rename GoStruct

This commit is contained in:
MickMake 2022-11-04 17:31:46 +11:00
parent c02eacf369
commit 260fd19728
44 changed files with 1723 additions and 1316 deletions

View File

@ -0,0 +1,115 @@
package GoStruct
// These are tags that can be added to a Go structure that GoStruct uses to process the structure.
const (
// NameGoStruct - Name of field within structure that allows for assigning tags to the parent.
// Add like this:
// type ResultData []struct {
// GoStruct GoStruct.GoStruct `json:"GoStruct" DataTable:"true" DataTableSortOn:"UnitConvertId"`
NameGoStruct = "GoStruct"
// PointId - Point id in the form p\d+ or \d+ or free-form text.
PointId = "PointId"
// PointParentId - Associated parent of point.
PointParentId = "PointParentId"
// PointUpdateFreq - Point update frequency - Total, Yearly, Monthly, Day.
PointUpdateFreq = "PointUpdateFreq"
UpdateFreqInstant = "instant"
UpdateFreq5Mins = "5mins"
UpdateFreqBoot = "boot"
UpdateFreqDay = "daily"
UpdateFreqMonth = "monthly"
UpdateFreqYear = "yearly"
UpdateFreqTotal = "total"
// PointValueType - Value type of point: energy, date, battery, temperature.
PointValueType = "PointValueType"
// PointIgnore - Ignore this point.
PointIgnore = "PointIgnore"
// PointIgnoreIfNil - Ignore this point if a child is nil or empty.
PointIgnoreIfNil = "PointIgnoreIfNil"
// PointIgnoreIfNilFromChild - Ignore this point if a child is nil or empty.
PointIgnoreIfNilFromChild = "PointIgnoreIfNilFromChild"
// PointAliasTo - Alias this point to another point.
PointAliasTo = "PointAliasTo"
// PointAliasFrom - Alias this point from another point.
PointAliasFrom = "PointAliasFrom"
// PointUnit - Units: Wh, kWh, C, h.
PointUnit = "PointUnit"
// PointUnitFrom - Get PointUnit from another field structure.
PointUnitFrom = "PointUnitFrom"
// PointUnitFromParent - Get PointUnit from another parent field structure.
PointUnitFromParent = "PointUnitFromParent"
// PointGroupName - Point group name.
PointGroupName = "PointGroupName"
// PointGroupNameFrom - Get PointGroupName from another field structure.
PointGroupNameFrom = "PointGroupNameFrom"
// PointName - Human-readable name of point.
PointName = "PointName"
// PointNameFromChild - Searches child for field value to use for naming when hitting a slice, (as opposed to using an index).
PointNameFromChild = "PointNameFromChild"
// PointNameFromParent - Searches child for field value to use for naming when hitting a slice, (as opposed to using an index).
PointNameFromParent = "PointNameFromParent"
// PointNameDateFormat - Date format when using PointNameFrom, (if the field is a time.Time type).
PointNameDateFormat = "PointNameDateFormat"
// PointNameAppend - Append PointNameFrom instead of replace.
PointNameAppend = "PointNameAppend"
// PointArrayFlatten - Flatten an array into a string. EG: ["one", "two", "three"]
PointArrayFlatten = "PointArrayFlatten"
// PointSplitOn - Split a point into an array separating by defined string.
PointSplitOn = "PointSplitOn"
// PointSplitOnType - What valueTypes will be used for a split.
PointSplitOnType = "PointSplitOnType"
// PointIgnoreZero - Ignore arrays with zero size, (default true).
PointIgnoreZero = "PointIgnoreZero"
// PointTimestampFrom - Pull timestamp from another field structure.
PointTimestampFrom = "PointTimestampFrom"
// IsDataTable - This entity is a data table - Will only traverse down one child.
IsDataTable = "DataTable"
// DataTableId - Table id, (defaults to Json tag).
DataTableId = "DataTableId"
// DataTableName - Table Name, (defaults to DataTableId).
DataTableName = "DataTableName"
// DataTableTitle - Table Title, (defaults to DataTableId in name format).
DataTableTitle = "DataTableTitle"
// DataTableMerge - Merge rows together - useful for when we use, for EG: []valueTypes.Float
DataTableMerge = "DataTableMerge"
// DataTableShowIndex - Show index on table.
DataTableShowIndex = "DataTableShowIndex"
// DataTableSortOn - Sort table using this Field.
DataTableSortOn = "DataTableSortOn"
)
type GoStruct bool

View File

@ -1,5 +1,5 @@
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
package apiReflect
// Package GoStruct - Snaffooed from https://github.com/fatih/structs
package GoStruct
import (
"errors"

View File

@ -7,22 +7,22 @@ import (
"fmt"
"github.com/wcharczuk/go-chart/v2"
"github.com/wcharczuk/go-chart/v2/drawing"
"go.pennock.tech/tabular"
"os"
"strconv"
"strings"
"time"
)
// "go.pennock.tech/tabular"
// tabular "github.com/agrison/go-tablib"
type GraphRequest struct {
Title string `json:"title"`
TimeColumn *int `json:"time_column"`
ValueColumn *int `json:"value_column"`
UnitsColumn *int `json:"units_column"`
NameColumn *int `json:"name_column"`
SearchColumn *int `json:"search_column"`
TimeColumn *string `json:"time_column"`
ValueColumn *string `json:"value_column"`
UnitsColumn *string `json:"units_column"`
NameColumn *string `json:"name_column"`
SearchColumn *string `json:"search_column"`
SearchString *string `json:"search_string"`
MinLeftAxis *float64 `json:"min_left_axis"`
@ -130,67 +130,72 @@ func (t *Table) GetSearchColumn() SearchStrings {
func (t *Table) ProcessGraphData() error {
for range Only.Once {
fmt.Println("This is currently broken!")
break
req := t.graph.req
t.graph.searchName = ""
var units string
var times []time.Time
var values []float64
for row := 0; row < t.table.NRows(); row++ {
for row := 0; row < t.RowLength(); row++ {
// Get the search column
var cell *tabular.Cell
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.SearchColumn})
var cell interface{}
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.SearchColumn})
cell, t.Error = t.GetCell(row, *req.SearchColumn)
if t.Error != nil {
continue
}
if !strings.Contains(cell.String(), *req.SearchString) {
continue
}
// if !strings.Contains(cell.String(), *req.SearchString) {
// continue
// }
if req.Title == "" {
t.SetTitle(cell.String())
t.SetTitle(cell.(string))
}
if t.graph.searchName == "" {
if *req.NameColumn > 0 {
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.NameColumn})
if req.NameColumn != nil {
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.NameColumn})
cell, t.Error = t.GetCell(row, *req.NameColumn)
if t.Error != nil {
continue
}
t.graph.searchName = cell.String()
t.graph.searchName = cell.(string)
}
}
// Get units
if units == "" {
if *req.UnitsColumn > 0 {
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.UnitsColumn})
if req.UnitsColumn != nil {
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.UnitsColumn})
cell, t.Error = t.GetCell(row, *req.UnitsColumn)
if t.Error != nil {
continue
}
units = cell.String()
units = cell.(string)
}
}
//
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.TimeColumn})
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.TimeColumn})
cell, t.Error = t.GetCell(row, *req.TimeColumn)
if t.Error != nil {
continue
}
var tim time.Time
tim, t.Error = time.ParseInLocation(DateTimeSearchLayout, cell.String(), time.Local) // @TODO - May have to revisit this!
tim, t.Error = time.ParseInLocation(DateTimeSearchLayout, cell.(string), time.Local) // @TODO - May have to revisit this!
if t.Error != nil {
continue
}
times = append(times, tim)
//
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.ValueColumn})
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.ValueColumn})
cell, t.Error = t.GetCell(row, *req.ValueColumn)
if t.Error != nil {
continue
}
var val float64
val, t.Error = strconv.ParseFloat(cell.String(), 64)
val, t.Error = strconv.ParseFloat(cell.(string), 64)
if t.Error != nil {
val = 0
}
@ -219,19 +224,22 @@ func (t *Table) ProcessGraphData() error {
type SearchStrings map[string]int
func (t *Table) FindSearchStrings() error {
for range Only.Once {
fmt.Println("This is currently broken!")
break
t.graph.otherSearch = make(SearchStrings)
for row := 0; row < t.table.NRows(); row++ {
for row := 0; row < t.RowLength(); row++ {
// Get the search column
var cell *tabular.Cell
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *t.graph.req.SearchColumn})
var cell interface{}
// cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *t.graph.req.SearchColumn})
cell, t.Error = t.GetCell(row, *t.graph.req.SearchColumn)
if t.Error != nil {
continue
}
if _, ok := t.graph.otherSearch[cell.String()]; ok {
t.graph.otherSearch[cell.String()] += 1
if _, ok := t.graph.otherSearch[cell.(string)]; ok {
t.graph.otherSearch[cell.(string)] += 1
} else {
t.graph.otherSearch[cell.String()] = 0
t.graph.otherSearch[cell.(string)] = 0
}
}
}

View File

@ -2,7 +2,7 @@ package output
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"encoding/json"
"fmt"
)
@ -50,7 +50,7 @@ func GetAsString(r interface{}) string {
break
}
a, e := apiReflect.GetStructName(r)
a, e := reflection.GetStructName(r)
ret += fmt.Sprintf(`"%s.%s": %s`, a, e, j)
}
return ret
@ -65,7 +65,7 @@ func GetRequestString(r interface{}) string {
break
}
a, e := apiReflect.GetStructName(r)
a, e := reflection.GetStructName(r)
ret += fmt.Sprintf(`"%s.%s": %s`, a, e, j)
}
return ret

View File

@ -0,0 +1,349 @@
package output
import (
"GoSungrow/Only"
"errors"
"fmt"
tabular "github.com/agrison/go-tablib"
"os"
)
// "github.com/agrison/go-tablib"
// "go.pennock.tech/tabular"
// "github.com/jbub/tabular"
type Table struct {
filePrefix string
title string
table *tabular.Dataset
graph *Chart
json []byte
raw []byte
OutputType OutputType
saveAsFile bool
graphFilter string
Error error
}
type Tables map[string]Table
func NewTable(headers ...string) Table {
return Table {
filePrefix: "",
title: "",
table: tabular.NewDataset(headers),
Error: nil,
}
}
func NewTables() Tables {
return make(Tables)
}
func (t *Table) String() string {
var ret string
for range Only.Once {
if t == nil {
break
}
if !t.table.Valid() {
break
}
ret = t.table.Tabular("grid").String()
}
return ret
}
func (t *Table) GetHeaders() []string {
return t.table.Headers()
}
func (t *Table) RowLength() int {
return t.table.Height()
}
func (t *Table) GetCell(row int, colName string) (interface{}, error) {
var ret interface{}
for range Only.Once {
var r map[string]interface{}
r, t.Error = t.table.Row(row)
if t.Error != nil {
break
}
ret = r[colName]
}
return ret, t.Error
}
// func (t *Table) AllRows() []*tabular.Row {
// return t.table.AllRows()
// }
type DataSet []DataRow
type DataRow map[string]string
func (t *Table) SetTitle(title string, args ...interface{}) {
t.title = fmt.Sprintf(title, args...)
}
func (t *Table) SetRaw(data []byte) {
t.raw = data
}
func (t *Table) AppendRaw(data []byte) {
t.raw = append(t.raw, data...)
}
func (t *Table) SetJson(data []byte) {
t.json = data
}
func (t *Table) SetSaveFile(ok bool) {
t.saveAsFile = ok
}
func (t *Table) SetGraphFilter(filter string) {
t.graphFilter = filter
}
func (t *Table) Sort(sort string) {
for range Only.Once {
if t.IsNotValid() {
break
}
// Make sure we have a header.
for _, header := range t.table.Headers() {
if header == sort {
t.table = t.table.Sort(sort)
break
}
}
}
}
func (t *Table) IsValid() bool {
var yes bool
for range Only.Once {
if t.table == nil {
break
}
if !t.table.Valid() {
break
}
if t.table.Height() == 0 {
break
}
if t.table.Width() == 0 {
break
}
yes = true
}
return yes
}
func (t *Table) IsNotValid() bool {
return !t.IsValid()
}
func (t *Table) SetFilePrefix(prefix string, args ...interface{}) {
if len(args) == 0 {
t.filePrefix = prefix
return
}
t.filePrefix = fmt.Sprintf(prefix, args...)
}
func (t *Table) SetOutputType(outputType string) {
t.OutputType.Set(outputType)
}
func (t *Table) AddRow(row ...interface{}) error {
t.Error = t.table.Append(row)
return t.Error
}
func (t *Table) writeFile(fn string, data string, perm os.FileMode) error {
for range Only.Once {
fmt.Printf("Writing file '%s'\n", fn)
t.Error = os.WriteFile(fn, []byte(data), perm)
if t.Error != nil {
t.Error = errors.New(fmt.Sprintf("Unable to write to file %s - %v", fn, t.Error))
break
}
}
return t.Error
}
func (t *Table) Output() error {
for range Only.Once {
if t == nil {
break
}
switch {
case t.OutputType.IsNone():
case t.OutputType.IsTable():
t.Error = t.WriteTable()
case t.OutputType.IsList():
t.Error = t.WriteList()
case t.OutputType.IsCsv():
t.Error = t.WriteCsv()
case t.OutputType.IsRaw():
t.Error = t.WriteRaw()
case t.OutputType.IsJson():
t.Error = t.WriteJson()
case t.OutputType.IsGraph():
t.Error = t.SetGraphFromJson(Json(t.graphFilter))
if t.Error != nil {
break
}
t.Error = t.CreateGraph()
if t.Error != nil {
break
}
default:
}
}
return t.Error
}
func (t *Table) GetTable() string {
return t.String()
}
func (t *Table) WriteTable() error {
for range Only.Once {
if t.IsNotValid() {
break
}
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix+"-table.txt", t.String(), DefaultFileMode)
}
fmt.Printf("# %s\n", t.title)
fmt.Print(t.String())
}
return t.Error
}
func (t *Table) WriteList() error {
for range Only.Once {
if t.IsNotValid() {
break
}
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix+".txt", t.String(), DefaultFileMode)
}
fmt.Printf("# %s\n", t.title)
fmt.Print(t.String())
}
return t.Error
}
func (t *Table) GetCsv() string {
var ret string
for range Only.Once {
if t.IsNotValid() {
break
}
var result *tabular.Exportable
result, t.Error = t.table.CSV()
if t.Error != nil {
break
}
ret = result.String()
}
return ret
}
func (t *Table) WriteCsv() error {
for range Only.Once {
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix+".csv", t.GetCsv(), DefaultFileMode)
break
}
fmt.Print(t.GetCsv())
}
return t.Error
}
func (t *Table) GetXml() string {
var ret string
for range Only.Once {
if t.IsNotValid() {
break
}
var result *tabular.Exportable
result, t.Error = t.table.CSV()
if t.Error != nil {
break
}
ret = result.String()
}
return ret
}
func (t *Table) WriteXml() error {
for range Only.Once {
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix+".xml", t.GetXml(), DefaultFileMode)
break
}
fmt.Print(t.GetXml())
}
return t.Error
}
func (t *Table) GetJson() string {
return string(t.raw)
}
func (t *Table) WriteJson() error {
for range Only.Once {
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix + ".json", string(t.json), DefaultFileMode)
break
}
fmt.Printf("%s", t.json)
}
return t.Error
}
func (t *Table) GetRaw() string {
return string(t.json)
}
func (t *Table) GetRawBytes() []byte {
return t.json
}
func (t *Table) WriteRaw() error {
for range Only.Once {
if t.saveAsFile {
t.Error = t.writeFile(t.filePrefix+".raw", string(t.raw), DefaultFileMode)
break
}
fmt.Printf("%s", t.raw)
}
return t.Error
}

View File

@ -0,0 +1,318 @@
package reflection
import (
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"crypto/md5"
"errors"
"fmt"
"github.com/MickMake/GoUnify/Only"
"reflect"
"strings"
"time"
)
func GetPointNameFrom(ref interface{}, name string, intSize int, dateFormat string) string {
var ret string
for range Only.Once {
if dateFormat == "" {
dateFormat = valueTypes.DateTimeAltLayout
}
vo := reflect.ValueOf(ref)
var ra []string
switch vo.Kind() {
case reflect.Struct:
for _, pnf := range strings.Split(name, ".") {
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
fn := vo.Type().Field(i).Name
if fn == pnf {
ra = append(ra, valueTypes.AnyToValueString(vo.Field(i).Interface(), intSize, dateFormat))
break
}
}
}
case reflect.Map:
for _, pnf := range strings.Split(name, ".") {
// Iterate over all available keys, looking for the key name.
for _, key := range vo.MapKeys() {
if key.String() == pnf {
ra = append(ra, valueTypes.AnyToValueString(vo.MapIndex(key).Interface(), intSize, dateFormat))
break
}
}
}
}
ret = strings.Join(ra, ".")
}
return ret
}
func GetStringFrom(ref interface{}, name string) string {
var ret string
for range Only.Once {
vo := reflect.ValueOf(ref)
switch vo.Kind() {
case reflect.Struct:
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
if vo.Type().Field(i).Name == name {
ret = valueTypes.AnyToValueString(vo.Field(i).Interface(), 0, "")
break
}
}
case reflect.Map:
// Iterate over all available fields, looking for the field name.
for _, key := range vo.MapKeys() {
if key.String() == name {
ret = valueTypes.AnyToValueString(vo.MapIndex(key).Interface(), 0, "")
break
}
}
}
}
return ret
}
func GetJsonTag(fieldTo reflect.StructField) string {
var ret string
for range Only.Once {
ret = fieldTo.Tag.Get("json")
ret = strings.ReplaceAll(ret, "omitempty", "")
ret = strings.TrimSuffix(ret, ",")
}
return ret
}
func GetTimestampFrom(ref interface{}, name string, dateFormat string) time.Time {
var ret time.Time
for range Only.Once {
if dateFormat == "" {
dateFormat = valueTypes.DateTimeAltLayout
}
vo := reflect.ValueOf(ref)
switch vo.Kind() {
case reflect.Struct:
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
if vo.Type().Field(i).Name == name {
v := fmt.Sprintf("%v", vo.Field(i).Interface())
ret = valueTypes.SetDateTimeString(v).Time
break
}
}
case reflect.Map:
// Iterate over all available fields, looking for the field name.
for _, key := range vo.MapKeys() {
if key.String() == name {
v := fmt.Sprintf("%v", vo.MapIndex(key).Interface())
ret = valueTypes.SetDateTimeString(v).Time
break
}
}
}
}
return ret
}
func GetFingerprint(ref interface{}) string {
var ret string
for range Only.Once {
// h := hash(GetRequestString(ref))
h := md5.Sum([]byte(GetRequestString(ref)))
ret = fmt.Sprintf("%x", h)
}
return ret
}
func GetRequestString(ref interface{}) string {
var ret string
for range Only.Once {
vo := reflect.ValueOf(ref)
// Iterate over all available fields and read the tag value
for i := 0; i < vo.NumField(); i++ {
fieldVo := vo.Field(i)
ret += fmt.Sprintf("-%v", fieldVo.Interface())
}
}
return ret
}
// GetArea Return an Area name if we are given an Area or EndPoint struct.
func GetArea(trim string, v interface{}) string {
var ret string
for range Only.Once {
if v == nil {
break
}
val := reflect.ValueOf(v)
ret1 := val.Type().PkgPath()
ret1 = strings.TrimPrefix(ret1, trim)
ret2 := val.Type().Name()
if ret2 == "Area" {
s := strings.Split(ret1, "/")
ret = s[len(s)-1]
break
}
if ret2 == "EndPoint" {
s := strings.Split(ret1, "/")
ret = s[len(s)-2]
break
}
ret = ret1
}
return ret
}
// GetName Return an endpoint name if we are given an Area or EndPoint struct.
func GetName(trim string, v interface{}) string {
var ret string
for range Only.Once {
val := reflect.ValueOf(v)
ret1 := val.Type().PkgPath()
ret1 = strings.TrimPrefix(ret1, trim)
ret2 := val.Type().Name()
if ret2 == "Area" {
s := strings.Split(ret1, "/")
ret = s[len(s)-2]
break
}
if ret2 == "EndPoint" {
s := strings.Split(ret1, "/")
ret = s[len(s)-1]
break
}
ret = ret1
}
return ret
}
func HelpOptions(ref interface{}) string {
var ret string
for range Only.Once {
t := reflect.TypeOf(ref)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
required := field.Tag.Get("required")
if required == "" {
ret += fmt.Sprintf("%s: optional\n", field.Name)
continue
}
ret += fmt.Sprintf("%s: required\n", field.Name)
}
}
return ret
}
func GetStructName(v interface{}) (string, string) {
var area string
var endpoint string
for range Only.Once {
val := reflect.ValueOf(v)
// ret = val.Type().Name() // Returns structure, (EndPoint name).
// ret = val.Type().PkgPath() // Returns structure path.
// ret = val.Type().String() // Returns
// @TODO - Need to check for pointers to struct
// if t := reflect.TypeOf(ref); t.Kind() == reflect.Ptr {
// ret = strings.ToLower(t.Elem().Name())
// } else {
// ret = strings.ToLower(t.Name())
// }
s := strings.Split(val.Type().String(), ".")
if len(s) < 2 {
break
}
area = s[0]
endpoint = s[1]
}
return area, endpoint
}
func FindRequestData(ref interface{}) string {
var ret string
for range Only.Once {
vo := reflect.ValueOf(ref)
to := reflect.TypeOf(ref)
// Iterate over all available fields and read the tag value
for i := 0; i < vo.NumField(); i++ {
fieldTo := to.Field(i)
// required := fieldTo.Tag.GetByJson("required")
fmt.Printf(">%s\t", fieldTo.Name)
fieldVo := vo.Field(i)
fmt.Printf(">%s\n", fieldVo.String())
value := fmt.Sprintf("%v", fieldVo.Interface())
if value == "" {
break
}
}
}
return ret
}
func GetType(v interface{}) string {
return reflect.ValueOf(v).Type().Name()
}
func GetPkgType(v interface{}) string {
return reflect.ValueOf(v).Type().String()
}
func DoTypesMatch(a interface{}, b interface{}) error {
var err error
for range Only.Once {
aName := GetType(a)
bName := GetType(b)
if aName == bName {
break
}
err = errors.New(fmt.Sprintf("interface '%s' doesn't match '%s'", aName, bName))
}
return err
}
func DoPkgTypesMatch(a interface{}, b interface{}) error {
var err error
for range Only.Once {
aName := GetPkgType(a)
bName := GetPkgType(b)
if aName == bName {
break
}
err = errors.New(fmt.Sprintf("interface '%s' doesn't match '%s'", aName, bName))
}
return err
}

View File

@ -1,4 +1,4 @@
package apiReflect
package reflection
// type StructKey struct {

View File

@ -1,7 +1,8 @@
package apiReflect
package GoStruct
import (
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"fmt"
"github.com/MickMake/GoUnify/Only"
"os"
@ -11,84 +12,6 @@ import (
)
const (
PointId = "PointId" // Point id in the form p\d+ or \d+
PointParentId = "PointParentId" // Associated parent of point.
PointUpdateFreq = "PointUpdateFreq" // Point update frequency - Total, Yearly, Monthly, Day.
PointValueType = "PointValueType" // Value type of point: energy, date, battery, temperature.
PointIgnore = "PointIgnore" // Ignore this point.
PointIgnoreIfNil = "PointIgnoreIfNil" // Ignore this point if a child is nil or empty.
PointIgnoreIfNilFromChild = "PointIgnoreIfNilFromChild" // Ignore this point if a child is nil or empty.
PointAliasTo = "PointAliasTo" // Alias this point to another point.
PointAliasFrom = "PointAliasFrom" // Alias this point from another point.
PointUnit = "PointUnit" // Units: Wh, kWh, C, h.
PointUnitFrom = "PointUnitFrom" // Get PointUnit from another field structure.
PointUnitFromParent = "PointUnitFromParent" // Get PointUnit from another parent field structure.
PointGroupName = "PointGroupName" // Point group name.
PointGroupNameFrom = "PointGroupNameFrom" // Get PointGroupName from another field structure.
PointName = "PointName" // Human-readable name of point.
PointNameFromChild = "PointNameFromChild" // Searches child for field value to use for naming when hitting a slice, (as opposed to using an index).
PointNameFromParent = "PointNameFromParent" // Searches child for field value to use for naming when hitting a slice, (as opposed to using an index).
PointNameDateFormat = "PointNameDateFormat" // Date format when using PointNameFrom, (if the field is a time.Time type).
PointNameAppend = "PointNameAppend" // Append PointNameFrom instead of replace.
PointArrayFlatten = "PointArrayFlatten" // Flatten an array into a string. EG: ["one", "two", "three"]
PointSplitOn = "PointSplitOn" // Split a point into an array separating by defined string.
PointSplitOnType = "PointSplitOnType" // What valueTypes will be used for a split.
PointIgnoreZero = "PointIgnoreZero" // Ignore arrays with zero size, (default true).
PointTimestampFrom = "PointTimestampFrom" // Pull timestamp from another field structure.
IsDataTable = "DataTable" // This entity is a data table - Will only traverse down one child.
DataTableId = "DataTableId" // Table id, (defaults to Json tag).
DataTableName = "DataTableName" // Table Name, (defaults to DataTableId).
DataTableTitle = "DataTableTitle" // Table Title, (defaults to DataTableId in name format).
DataTableMerge = "DataTableMerge" // Merge rows together - useful for when we use, for EG: []valueTypes.Float
DataTableShowIndex = "DataTableShowIndex" // Show index on table.
)
const (
UpdateFreqInstant = "instant"
UpdateFreq5Mins = "5mins"
UpdateFreqBoot = "boot"
UpdateFreqDay = "daily"
UpdateFreqMonth = "monthly"
UpdateFreqYear = "yearly"
UpdateFreqTotal = "total"
)
type EndPointPath []string
func NewEndPointPath(path ...string) EndPointPath {
var epp EndPointPath
return epp.Append(path...)
}
func (e *EndPointPath) Copy() EndPointPath {
ret := make(EndPointPath, len(*e))
copy(ret, *e)
return ret
}
func (e *EndPointPath) Append(path ...string) EndPointPath {
ret := make(EndPointPath, len(*e))
copy(ret, *e)
for _, p := range path {
ret = append(ret, p)
}
return ret
}
func (e EndPointPath) String() string {
return strings.Join(e, ".")
}
type DataStructure struct {
Required bool
Json string
@ -129,6 +52,7 @@ type DataStructure struct {
DataTableTitle string
DataTableMerge bool
DataTableShowIndex bool
DataTableSortOn string
Value interface{}
ValueType string
@ -145,7 +69,7 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
pointIgnoreIfNil := fieldTo.Tag.Get(PointIgnoreIfNil)
if pointIgnoreIfNil != "" {
ret := GetStringFrom(current, pointIgnoreIfNil)
ret := reflection.GetStringFrom(current, pointIgnoreIfNil)
if (ret == "") || (ret == "--") {
ignore = true
}
@ -173,7 +97,7 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
// pointValueType = "NIL"
// }
pointJson := getJsonTag(fieldTo)
pointJson := reflection.GetJsonTag(fieldTo)
pointId := fieldTo.Tag.Get(PointId)
if pointId == "" {
pointId = pointJson
@ -183,22 +107,22 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
pointUnitFrom := fieldTo.Tag.Get(PointUnitFrom)
pointUnitFromParent := fieldTo.Tag.Get(PointUnitFromParent)
if pointUnitFrom != "" {
pointUnit = GetStringFrom(current, pointUnitFrom)
pointUnit = reflection.GetStringFrom(current, pointUnitFrom)
}
if pointUnitFromParent != "" {
pointUnit = GetStringFrom(parent, pointUnitFromParent)
pointUnit = reflection.GetStringFrom(parent, pointUnitFromParent)
}
pointGroupName := fieldTo.Tag.Get(PointGroupName)
pointGroupNameFrom := fieldTo.Tag.Get(PointGroupNameFrom)
if pointGroupNameFrom != "" {
pointGroupName = GetStringFrom(current, pointGroupNameFrom)
pointGroupName = reflection.GetStringFrom(current, pointGroupNameFrom)
}
pointTimestamp := time.Now()
pointTimestampFrom := fieldTo.Tag.Get(PointTimestampFrom)
if pointTimestampFrom != "" {
pointTimestamp = GetTimestampFrom(current, pointTimestampFrom, valueTypes.DateTimeLayout)
pointTimestamp = reflection.GetTimestampFrom(current, pointTimestampFrom, valueTypes.DateTimeLayout)
}
var valueType string
@ -264,16 +188,6 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
dataTableShowIndex = true
}
dtn := fieldTo.Tag.Get(DataTableName)
if dtn == "" {
dtn = valueTypes.PointToName(pointId)
}
did := fieldTo.Tag.Get(DataTableId)
if did == "" {
did = pointId
}
*ds = DataStructure {
Required: required,
Json: pointJson,
@ -307,12 +221,13 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
PointSplitOnType: fieldTo.Tag.Get(PointSplitOnType),
PointIgnoreZero: pointIgnoreZero,
DataTable: dataTable,
DataTableId: did,
DataTableName: dtn,
DataTableTitle: fieldTo.Tag.Get(DataTableTitle),
DataTableMerge: dataTableMerge,
DataTable: dataTable,
DataTableId: fieldTo.Tag.Get(DataTableId),
DataTableName: fieldTo.Tag.Get(DataTableName),
DataTableTitle: fieldTo.Tag.Get(DataTableTitle),
DataTableMerge: dataTableMerge,
DataTableShowIndex: dataTableShowIndex,
DataTableSortOn: fieldTo.Tag.Get(DataTableSortOn),
Value: fieldVo.Interface(),
ValueType: valueType,
@ -323,14 +238,6 @@ func (ds *DataStructure) Set(parent interface{}, current interface{}, fieldTo re
return *ds
}
func COMPARE(name EndPointPath, ref1 interface{}, ref2 interface{}) {
t1 := fmt.Sprintf("%v", ref1)
t2 := fmt.Sprintf("%v", ref2)
if t1 != t2 {
fmt.Printf("[%s] VALUE ERROR: '%s' != '%s'\n", name, t1, t2)
}
}
type DataStructures struct {
DataMap map[string]DataStructure
DataTables DataTables
@ -338,7 +245,7 @@ type DataStructures struct {
Debug bool
}
func (dss *DataStructures) GetPointTags(Parent Reflect, Current Reflect, name EndPointPath) DataStructures {
func (dss *DataStructures) GetPointTags(Parent *Reflect, Current *Reflect, name EndPointPath) DataStructures {
for range Only.Once {
if Current.DataStructure.DataTable {
@ -456,7 +363,7 @@ func (dss *DataStructures) Append(dsm DataStructures) {
}
}
func (dss *DataStructures) ProcessUnsupported(_ Reflect, Current Reflect, name EndPointPath) {
func (dss *DataStructures) ProcessUnsupported(_ *Reflect, Current *Reflect, name EndPointPath) {
for range Only.Once {
if dss.ShowEmpty {
dss.Add(Current.DataStructure)
@ -466,7 +373,7 @@ func (dss *DataStructures) ProcessUnsupported(_ Reflect, Current Reflect, name E
}
}
func (dss *DataStructures) ProcessSlice(Parent Reflect, Current Reflect, name EndPointPath) {
func (dss *DataStructures) ProcessSlice(Parent *Reflect, Current *Reflect, name EndPointPath) {
for range Only.Once {
// Handle slices here.
if dss.ShowEmpty {
@ -480,7 +387,7 @@ func (dss *DataStructures) ProcessSlice(Parent Reflect, Current Reflect, name En
for si := 0; si < Current.Length; si++ {
var Child Reflect
Child.SetByIndex(Parent, Current, si, name)
Child.SetByIndex(*Parent, *Current, si, reflect.Value{}, name)
if dss.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child: %s\n", Child)
}
@ -489,111 +396,101 @@ func (dss *DataStructures) ProcessSlice(Parent Reflect, Current Reflect, name En
name2 = Current.PointNameFromChild(Child, name)
}
if Child.Kind == reflect.Slice {
if Child.IsUnknown() {
dss.GetPointTags(Current, Child, name2)
continue
}
if dss.PointSplitOn(Current, Child, name2) {
continue
}
COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
dss.Add(Child.DataStructure)
continue
}
if Child.IsUnknown() {
dss.GetPointTags(Current, Child, name2)
dss.GetPointTags(Current, &Child, name2)
continue
}
if dss.PointSplitOn(Current, &Child, name2) {
continue
}
dss.Add(Child.DataStructure)
}
}
}
func (dss *DataStructures) ProcessStruct(Parent Reflect, Current Reflect, name EndPointPath) {
func (dss *DataStructures) ProcessStruct(Parent *Reflect, Current *Reflect, name EndPointPath) {
for range Only.Once {
// Iterate over all available fields and read the tag value
for si := 0; si < Current.Length; si++ {
var Child Reflect
Child.SetByIndex(Parent, Current, si, name)
Child.SetByIndex(*Parent, *Current, si, reflect.Value{}, name)
if dss.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child: %s\n", Child)
}
name2 := Child.DataStructure.Endpoint.Copy()
if Current.DataStructure.PointNameFromChild != "" {
name2 = Current.PointNameFromChild(Child, name)
}
if !Child.IsExported {
_, _ = fmt.Fprintf(os.Stderr, "WARNING: Field '%s' type not exported (%s): Type %s\n", Child.FieldName, name2, Child.Kind.String())
continue
}
if Child.Kind == reflect.Struct {
if Child.IsUnknown() {
dss.GetPointTags(Current, Child, name2)
continue
}
if dss.PointSplitOn(Current, Child, name2) {
continue
}
COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
dss.Add(Child.DataStructure)
if dss.GoStructOptions(Parent, Current, &Child, name) {
continue
}
if Child.IsUnknown() {
dss.GetPointTags(Current, Child, name2)
dss.GetPointTags(Current, &Child, name2)
continue
}
COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
if dss.PointSplitOn(Current, &Child, name2) {
continue
}
// COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
dss.Add(Child.DataStructure)
}
}
}
func (dss *DataStructures) ProcessMap(Parent Reflect, Current Reflect, name EndPointPath) {
func (dss *DataStructures) ProcessMap(Parent *Reflect, Current *Reflect, name EndPointPath) {
for range Only.Once {
for si := range Current.FieldVo.MapKeys() {
for si, sm := range Current.FieldVo.MapKeys() {
// @TODO - Implement pointNameFromChild / pointNameFromParent.
// @TODO - Need to look at other types, besides known types.
var Child Reflect
Child.SetByIndex(Parent, Current, si, name)
Child.SetByIndex(*Parent, *Current, si, sm, name)
if dss.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child: %s\n", Child)
}
name2 := Child.DataStructure.Endpoint.Copy()
if Current.DataStructure.PointNameFromChild != "" {
name2 = Current.PointNameFromChild(Child, name)
}
if Child.IsUnknown() {
dss.GetPointTags(Current, Child, name2)
dss.GetPointTags(Current, &Child, name2)
continue
}
if dss.PointSplitOn(Current, Child, name2) {
if dss.PointSplitOn(Current, &Child, name2) {
continue
}
COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
// COMPARE(Child.DataStructure.Endpoint, Child.DataStructure.Value, Child.Interface)
dss.Add(Child.DataStructure)
}
}
}
func (dss *DataStructures) PointNameAppend(_ Reflect, Current Reflect, name EndPointPath) []string {
func (dss *DataStructures) PointNameAppend(_ *Reflect, Current *Reflect, name EndPointPath) EndPointPath {
for range Only.Once {
if Current.DataStructure.PointNameAppend == false {
if len(name) == 0 {
break
}
name = name[:len(name) - 1]
name = name.PopLast()
}
}
return name
}
func (dss *DataStructures) PointArrayFlatten(_ Reflect, Current Reflect, name EndPointPath) bool {
func (dss *DataStructures) PointArrayFlatten(_ *Reflect, Current *Reflect, name EndPointPath) bool {
var yes bool
for range Only.Once {
if Current.DataStructure.PointArrayFlatten == true {
@ -607,7 +504,7 @@ func (dss *DataStructures) PointArrayFlatten(_ Reflect, Current Reflect, name En
return yes
}
func (dss *DataStructures) PointIgnoreZero(_ Reflect, Current Reflect, _ EndPointPath) bool {
func (dss *DataStructures) PointIgnoreZero(_ *Reflect, Current *Reflect, _ EndPointPath) bool {
var yes bool
for range Only.Once {
if !Current.DataStructure.PointIgnoreZero {
@ -626,7 +523,7 @@ func (dss *DataStructures) PointIgnoreZero(_ Reflect, Current Reflect, _ EndPoin
return yes
}
func (dss *DataStructures) PointIgnoreIfNilFromChild(Parent Reflect, Current Reflect, _ EndPointPath) bool {
func (dss *DataStructures) PointIgnoreIfNilFromChild(Parent *Reflect, Current *Reflect, _ EndPointPath) bool {
var yes bool
for range Only.Once {
if Parent.DataStructure.PointIgnoreIfNilFromChild == "" {
@ -637,7 +534,7 @@ func (dss *DataStructures) PointIgnoreIfNilFromChild(Parent Reflect, Current Ref
yes = false
break
}
ret := GetStringFrom(Current.Interface, Parent.DataStructure.PointIgnoreIfNilFromChild)
ret := reflection.GetStringFrom(Current.Interface, Parent.DataStructure.PointIgnoreIfNilFromChild)
if ret == "" {
yes = false
break
@ -647,7 +544,7 @@ func (dss *DataStructures) PointIgnoreIfNilFromChild(Parent Reflect, Current Ref
return yes
}
func (dss *DataStructures) PointSplitOn(_ Reflect, Current Reflect, _ EndPointPath) bool {
func (dss *DataStructures) PointSplitOn(_ *Reflect, Current *Reflect, _ EndPointPath) bool {
var yes bool
for range Only.Once {
if Current.DataStructure.PointSplitOn == "" {
@ -668,213 +565,50 @@ func (dss *DataStructures) PointSplitOn(_ Reflect, Current Reflect, _ EndPointPa
return yes
}
type DataTables struct {
Map []*DataTable
Merge bool
Index bool
}
func (dt *DataTables) Get() []*DataTable {
return dt.Map
}
type DataTable struct {
Reflect Reflect
Name string
Merge bool
Index bool
Headers []string
Data [][]Reflect
Debug bool
}
func (dss *DataStructures) AddTable(ref Reflect) *DataTable {
var ret *DataTable
func (dss *DataStructures) GoStructOptions(Parent *Reflect, Current *Reflect, Child *Reflect, _ EndPointPath) bool {
var yes bool
for range Only.Once {
if dss.DataTables.Map == nil {
dss.DataTables.Map = []*DataTable{}
}
ret = &DataTable {
Reflect: ref,
Name: ref.DataStructure.DataTableId,
Merge: ref.DataStructure.DataTableMerge,
Index: ref.DataStructure.DataTableShowIndex,
Headers: nil,
Data: nil,
}
dss.DataTables.Map = append(dss.DataTables.Map, ret)
if ref.DataStructure.DataTableMerge {
dss.DataTables.Merge = true
}
if ref.DataStructure.DataTableShowIndex {
dss.DataTables.Index = true
}
if dss.Debug {
_, _ = fmt.Fprintf(os.Stderr, "DEBUG DataStructures.AddTable() %s - Kind:'%s' Type:'%s'\n",
ref.DataStructure.Endpoint.String(), ref.DataStructure.ValueKind, ref.DataStructure.ValueType)
}
}
return ret
}
func (dt *DataTable) GetTable() DataTable {
for range Only.Once {
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"GetTable() Current[%s]: %s\n", dt.Reflect.DataStructure.DataTableId, dt.Reflect)
}
if !dt.Reflect.DataStructure.DataTable {
if Child.FieldName != NameGoStruct {
break
}
if dt.Reflect.Kind == reflect.Pointer {
// Special case:
// We're going to change the pointer to a proper object reference.
if dt.Reflect.IsNil {
break
}
ref2 := dt.Reflect.ValueOf.Elem().Interface()
if valueTypes.IsNil(ref2) {
break
}
dt.Reflect.SetByFieldName(dt.Reflect.Interface, ref2, "")
if dt.Reflect.IsNil {
break
}
// @TODO - Need to check here if the parent is a slice.
// If so - then "parent" is actually Parent.
// If not - then "parent" is actually Current.
// DO NOT BREAK!
// KEEP FIRST!
if Child.DataStructure.DataTable {
Parent.DataStructure.DataTable = Child.DataStructure.DataTable
}
if Child.DataStructure.DataTableMerge {
Parent.DataStructure.DataTableMerge = Child.DataStructure.DataTableMerge
}
if Child.DataStructure.DataTableShowIndex {
Parent.DataStructure.DataTableShowIndex = Child.DataStructure.DataTableShowIndex
}
if Child.DataStructure.DataTableId != "" {
Parent.DataStructure.DataTableId = Child.DataStructure.DataTableId
}
if Child.DataStructure.DataTableName != "" {
Parent.DataStructure.DataTableName = Child.DataStructure.DataTableName
}
if Child.DataStructure.DataTableTitle != "" {
Parent.DataStructure.DataTableTitle = Child.DataStructure.DataTableTitle
}
if Child.DataStructure.DataTableSortOn != "" {
Parent.DataStructure.DataTableSortOn = Child.DataStructure.DataTableSortOn
}
if dt.Reflect.Kind == reflect.Slice {
// Handle slices here.
for row := 0; row < dt.Reflect.Length; row++ {
var Child Reflect
Child.SetByIndex(dt.Reflect, dt.Reflect, row, EndPointPath{})
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child[%s]: %s\n", dt.Reflect.DataStructure.DataTableId, Child)
}
if Child.IsKnown() {
// We have a known value
if row == 0 {
dt.AddHeader(dt.Reflect)
}
dt.AddRow(Child)
continue
}
if Child.Kind == reflect.Struct {
var refs []Reflect
for col := 0; col < Child.Length; col++ {
var ChildStruct Reflect
ChildStruct.SetByIndex(dt.Reflect, Child, col, EndPointPath{})
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child: %s\n", ChildStruct)
}
if !ChildStruct.IsExported {
_, _ = fmt.Fprintf(os.Stderr, "WARNING: Field '%s' type not exported: Type %s\n", ChildStruct.FieldName, ChildStruct.Kind.String())
continue
}
refs = append(refs, ChildStruct)
}
if row == 0 {
dt.AddHeader(refs...)
} else {
dt.AddRow(refs...)
}
}
}
break
}
if dt.Reflect.Kind == reflect.Map {
// Handle maps here.
for row := range dt.Reflect.FieldVo.MapKeys() {
var Child Reflect
Child.SetByIndex(dt.Reflect, dt.Reflect, row, EndPointPath{})
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child[%s]: %s\n", dt.Reflect.DataStructure.DataTableId, Child)
}
if Child.IsKnown() {
// We have a known value
if row == 0 {
dt.AddHeader(dt.Reflect)
}
dt.AddRow(Child)
continue
}
if dt.Reflect.Kind == reflect.Map {
var refs []Reflect
for col := range dt.Reflect.FieldVo.MapKeys() {
var ChildStruct Reflect
ChildStruct.SetByIndex(dt.Reflect, Child, col, EndPointPath{})
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"SetByIndex() Child: %s\n", ChildStruct)
}
if !ChildStruct.IsExported {
_, _ = fmt.Fprintf(os.Stderr, "WARNING: Field '%s' type not exported: Type %s\n", ChildStruct.FieldName, ChildStruct.Kind.String())
continue
}
refs = append(refs, ChildStruct)
}
if row == 0 {
dt.AddHeader(refs...)
} else {
dt.AddRow(refs...)
}
}
}
break
}
_, _ = fmt.Fprintf(os.Stderr,"ERROR: Field '%s' type not supported (%s): Type %s\n",
dt.Reflect.FieldName, dt.Reflect.DataStructure.DataTableId, dt.Reflect.Kind.String())
dss.AddTable(Parent)
yes = true
}
return *dt
return yes
}
func (dt *DataTable) AddHeader(headers ...Reflect) {
for range Only.Once {
for _, header := range headers {
name := valueTypes.PointToName(header.DataStructure.PointName)
if header.DataStructure.PointUnit != "" {
name += "\n" + header.DataStructure.PointUnit
}
dt.Headers = append(dt.Headers, name)
}
func COMPARE(name EndPointPath, ref1 interface{}, ref2 interface{}) {
t1 := fmt.Sprintf("%v", ref1)
t2 := fmt.Sprintf("%v", ref2)
if t1 != t2 {
fmt.Printf("[%s] VALUE ERROR: '%s' != '%s'\n", name, t1, t2)
}
}
func (dt *DataTable) AddRow(refs ...Reflect) {
for range Only.Once {
if dt.Data == nil {
dt.Data = make([][]Reflect, 0)
}
var row []Reflect
row = append(row, refs...)
// for _, ref := range refs {
// }
dt.Data = append(dt.Data, row)
}
}
func (dt *DataTable) GetRow(row int) []Reflect {
return dt.Data[row]
}
func (dt *DataTable) Get() [][]Reflect {
return dt.Data
}

View File

@ -0,0 +1,37 @@
package GoStruct
import "strings"
type EndPointPath []string
func NewEndPointPath(path ...string) EndPointPath {
var epp EndPointPath
return epp.Append(path...)
}
func (e *EndPointPath) Copy() EndPointPath {
ret := make(EndPointPath, len(*e))
copy(ret, *e)
return ret
}
func (e *EndPointPath) Append(path ...string) EndPointPath {
ret := make(EndPointPath, len(*e))
copy(ret, *e)
for _, p := range path {
ret = append(ret, p)
}
return ret
}
func (e *EndPointPath) PopLast() EndPointPath {
if len(*e) == 0 {
return *e
}
return (*e)[:len(*e) - 1]
}
func (e EndPointPath) String() string {
return strings.Join(e, ".")
}

View File

@ -1,14 +1,14 @@
package apiReflect
package GoStruct
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/valueTypes"
"crypto/md5"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"errors"
"fmt"
"os"
"reflect"
"strings"
"time"
)
@ -124,7 +124,7 @@ func (r *Reflect) SetByFieldName(parent interface{}, current interface{}, name s
}
}
func (r *Reflect) SetByIndex(parent Reflect, current Reflect, index int, name EndPointPath) {
func (r *Reflect) SetByIndex(parent Reflect, current Reflect, index int, indexName reflect.Value, name EndPointPath) {
for range Only.Once {
// Get child interface from parent.
// pt := current.TypeOf
@ -143,8 +143,9 @@ func (r *Reflect) SetByIndex(parent Reflect, current Reflect, index int, name En
case reflect.Array:
r.Interface = current.ValueOf.Index(index).Interface()
case reflect.Map:
mk := current.ValueOf.MapKeys()
r.Interface = current.ValueOf.MapIndex(mk[index]).Interface()
// mk := current.ValueOf.MapKeys()
// r.Interface = current.ValueOf.MapIndex(mk[index]).Interface()
r.Interface = current.ValueOf.MapIndex(indexName).Interface()
}
r.Valid = true
@ -192,7 +193,7 @@ func (r *Reflect) SetByIndex(parent Reflect, current Reflect, index int, name En
r.FieldTo = reflect.StructField{}
r.IsExported = true
r.FieldVo = current.ValueOf.Index(index)
r.FieldName = r.FieldVo.String()
r.FieldName = current.FieldName // r.FieldVo.String()
r.DataStructure = r.DataStructure.Set(parent.Interface, current.Interface, r.FieldTo, r.FieldVo)
if r.Length == 0 {
r.DataStructure.PointNameAppend = false
@ -225,13 +226,18 @@ func (r *Reflect) SetByIndex(parent Reflect, current Reflect, index int, name En
// r.IsExported = r.FieldTo.IsExported()
r.FieldTo = reflect.StructField{}
r.IsExported = true
mk := current.ValueOf.MapKeys()
r.FieldVo = current.ValueOf.MapIndex(mk[index])
r.FieldName = mk[index].String()
// mk := current.ValueOf.MapKeys()
// r.FieldVo = current.ValueOf.MapIndex(mk[index])
r.FieldVo = current.ValueOf.MapIndex(indexName)
r.FieldName = current.FieldName // mk[index].String()
r.DataStructure = r.DataStructure.Set(parent.Interface, current.Interface, r.FieldTo, r.FieldVo)
r.DataStructure.Json = mk[index].String()
r.DataStructure.PointId = mk[index].String()
// r.DataStructure.Json = current.ValueOf.MapIndex(indexName).String()
// r.DataStructure.PointId = current.ValueOf.MapIndex(indexName).String()
r.DataStructure.Json = indexName.String()
r.DataStructure.PointId = indexName.String()
// r.DataStructure.Json = r.FieldVo.String()
// r.DataStructure.PointId = r.FieldVo.String()
r.DataStructure.Endpoint = name.Copy()
r.DataStructure.Endpoint = append(r.DataStructure.Endpoint, r.DataStructure.PointId)
@ -265,7 +271,7 @@ func (r *Reflect) setPointName(parent Reflect, current Reflect, name []string, i
switch {
case r.DataStructure.PointNameFromChild != "":
// PointNameFromChild - In this case points to a field within a CHILD struct.
pn = GetPointNameFrom(current.Interface, r.DataStructure.PointNameFromChild, intSize, r.DataStructure.PointNameDateFormat)
pn = reflection.GetPointNameFrom(current.Interface, r.DataStructure.PointNameFromChild, intSize, r.DataStructure.PointNameDateFormat)
if r.DataStructure.PointNameAppend == false {
name = append(name[:len(name) - 1], pn)
} else {
@ -274,7 +280,7 @@ func (r *Reflect) setPointName(parent Reflect, current Reflect, name []string, i
case r.DataStructure.PointNameFromParent != "":
// PointNameFromChild - In this case points to a field within a CHILD struct.
pn = GetPointNameFrom(parent.Interface, r.DataStructure.PointNameFromParent, intSize, r.DataStructure.PointNameDateFormat)
pn = reflection.GetPointNameFrom(parent.Interface, r.DataStructure.PointNameFromParent, intSize, r.DataStructure.PointNameDateFormat)
if r.DataStructure.PointNameAppend == false {
name = append(name[:len(name) - 1], pn)
} else {
@ -297,7 +303,7 @@ func (r *Reflect) PointNameFromChild(child Reflect, name EndPointPath) []string
for range Only.Once {
if r.DataStructure.PointNameFromChild != "" {
// PointNameFromChild - In this case points to a field within a CHILD struct.
pn := GetPointNameFrom(child.Interface, r.DataStructure.PointNameFromChild, 0, r.DataStructure.PointNameDateFormat)
pn := reflection.GetPointNameFrom(child.Interface, r.DataStructure.PointNameFromChild, 0, r.DataStructure.PointNameDateFormat)
name = append(name, pn)
}
}
@ -305,6 +311,98 @@ func (r *Reflect) PointNameFromChild(child Reflect, name EndPointPath) []string
}
func FindStart(fieldName string, Parent Reflect, Current Reflect, name EndPointPath) *Reflect {
var ret Reflect
for range Only.Once {
if Current.Kind == reflect.Pointer {
// Special case:
// We're going to change the pointer to a proper object reference.
if Current.IsNil {
break
}
ref2 := Current.ValueOf.Elem().Interface()
if valueTypes.IsNil(ref2) {
break
}
Current.SetByFieldName(Current.Interface, ref2, "")
if Current.IsNil {
break
}
// DO NOT BREAK!
// KEEP FIRST!
}
if Current.Kind == reflect.Struct {
// Iterate over all available fields and read the tag value
for si := 0; si < Current.Length; si++ {
var Child Reflect
Child.SetByIndex(Parent, Current, si, reflect.Value{}, name)
if Child.FieldName == fieldName {
// if !Child.DataStructure.PointNameAppend {
// Child.DataStructure.Endpoint = Child.DataStructure.Endpoint.PopLast()
// }
name = name.Append(Child.DataStructure.PointId)
ret = Child
break
}
if Child.Kind != reflect.Struct {
continue
}
if Child.IsKnown() {
continue
}
Child = *FindStart(fieldName, Current, Child, name)
// if Child.FieldName == fieldName {
// name = name.Append(Child.DataStructure.PointId)
// ret = Child
// break
// }
}
break
}
if Current.Kind == reflect.Slice {
// Iterate over all available fields and read the tag value
for si := 0; si < Current.Length; si++ {
var Child Reflect
Child.SetByIndex(Parent, Current, si, reflect.Value{}, name)
if Child.FieldName == fieldName {
// if !Child.DataStructure.PointNameAppend {
// Child.DataStructure.Endpoint = Child.DataStructure.Endpoint.PopLast()
// }
name = name.Append(Child.DataStructure.PointId)
ret = Child
break
}
if Child.Kind != reflect.Slice {
continue
}
if Child.IsKnown() {
continue
}
Child = *FindStart(fieldName, Current, Child, name)
// if Child.FieldName == fieldName {
// name = name.Append(Child.DataStructure.PointId)
// ret = Child
// break
// }
}
break
}
_, _ = fmt.Fprintf(os.Stderr,"ERROR: Field '%s' type not supported: Type %s\n", Current.FieldName, Current.Kind.String())
}
return &ret
}
func GetStructFields(ref interface{}) map[string]string {
ret := make(map[string]string)
@ -322,7 +420,7 @@ func GetStructFields(ref interface{}) map[string]string {
// Iterate over all available fields and read the tag value
for i := 0; i < Ref.Length; i++ {
var Child Reflect
Child.SetByIndex(Ref, Ref, i, EndPointPath{})
Child.SetByIndex(Ref, Ref, i, reflect.Value{}, EndPointPath{})
if !Child.IsExported {
continue
@ -354,7 +452,7 @@ func GetStructFieldsAsArray(ref interface{}) []string {
// Iterate over all available fields and read the tag value
for i := 0; i < Ref.Length; i++ {
var Child Reflect
Child.SetByIndex(Ref, Ref, i, EndPointPath{})
Child.SetByIndex(Ref, Ref, i, reflect.Value{}, EndPointPath{})
if !Child.IsExported {
continue
@ -385,7 +483,7 @@ func GetStructValuesAsArray(ref interface{}) []string {
// Iterate over all available fields and read the tag value
for i := 0; i < Ref.Length; i++ {
var Child Reflect
Child.SetByIndex(Ref, Ref, i, EndPointPath{})
Child.SetByIndex(Ref, Ref, i, reflect.Value{}, EndPointPath{})
if !Child.IsExported {
continue
@ -399,238 +497,44 @@ func GetStructValuesAsArray(ref interface{}) []string {
return ret
}
func GetStringFrom(ref interface{}, name string) string {
var ret string
type Required []string
func (r *Required) IsRequired(field string) bool {
var ok bool
for _, f := range *r {
if f == field {
ok = true
}
}
return ok
}
func (r *Required) IsNotRequired(field string) bool {
return !r.IsRequired(field)
}
// GetOptionsRequired Get field options within the structure that are required.
func GetOptionsRequired(ref interface{}) Required {
var ret []string
for range Only.Once {
vo := reflect.ValueOf(ref)
t := reflect.TypeOf(ref)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
required := field.Tag.Get("required")
if required == "" {
continue
}
switch vo.Kind() {
case reflect.Struct:
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
if vo.Type().Field(i).Name == name {
ret = valueTypes.AnyToValueString(vo.Field(i).Interface(), 0, "")
break
}
}
case reflect.Map:
// Iterate over all available fields, looking for the field name.
for _, key := range vo.MapKeys() {
if key.String() == name {
ret = valueTypes.AnyToValueString(vo.MapIndex(key).Interface(), 0, "")
break
}
}
ret = append(ret, field.Name)
}
}
return ret
}
func GetTimestampFrom(ref interface{}, name string, dateFormat string) time.Time {
var ret time.Time
for range Only.Once {
if dateFormat == "" {
dateFormat = valueTypes.DateTimeAltLayout
}
vo := reflect.ValueOf(ref)
switch vo.Kind() {
case reflect.Struct:
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
if vo.Type().Field(i).Name == name {
v := fmt.Sprintf("%v", vo.Field(i).Interface())
ret = valueTypes.SetDateTimeString(v).Time
break
}
}
case reflect.Map:
// Iterate over all available fields, looking for the field name.
for _, key := range vo.MapKeys() {
if key.String() == name {
v := fmt.Sprintf("%v", vo.MapIndex(key).Interface())
ret = valueTypes.SetDateTimeString(v).Time
break
}
}
}
}
return ret
}
func GetPointNameFrom(ref interface{}, name string, intSize int, dateFormat string) string {
var ret string
for range Only.Once {
if dateFormat == "" {
dateFormat = valueTypes.DateTimeAltLayout
}
vo := reflect.ValueOf(ref)
var ra []string
switch vo.Kind() {
case reflect.Struct:
for _, pnf := range strings.Split(name, ".") {
// Iterate over all available fields, looking for the field name.
for i := 0; i < vo.NumField(); i++ {
fn := vo.Type().Field(i).Name
if fn == pnf {
ra = append(ra, valueTypes.AnyToValueString(vo.Field(i).Interface(), intSize, dateFormat))
break
}
}
}
case reflect.Map:
for _, pnf := range strings.Split(name, ".") {
// Iterate over all available keys, looking for the key name.
for _, key := range vo.MapKeys() {
if key.String() == pnf {
ra = append(ra, valueTypes.AnyToValueString(vo.MapIndex(key).Interface(), intSize, dateFormat))
break
}
}
}
}
ret = strings.Join(ra, ".")
}
return ret
}
func getJsonTag(fieldTo reflect.StructField) string {
var ret string
for range Only.Once {
ret = fieldTo.Tag.Get("json")
ret = strings.ReplaceAll(ret, "omitempty", "")
ret = strings.TrimSuffix(ret, ",")
}
return ret
}
// GetArea Return an Area name if we are given an Area or EndPoint struct.
func GetArea(trim string, v interface{}) string {
var ret string
for range Only.Once {
if v == nil {
break
}
val := reflect.ValueOf(v)
ret1 := val.Type().PkgPath()
ret1 = strings.TrimPrefix(ret1, trim)
ret2 := val.Type().Name()
if ret2 == "Area" {
s := strings.Split(ret1, "/")
ret = s[len(s)-1]
break
}
if ret2 == "EndPoint" {
s := strings.Split(ret1, "/")
ret = s[len(s)-2]
break
}
ret = ret1
}
return ret
}
// GetName Return an endpoint name if we are given an Area or EndPoint struct.
func GetName(trim string, v interface{}) string {
var ret string
for range Only.Once {
val := reflect.ValueOf(v)
ret1 := val.Type().PkgPath()
ret1 = strings.TrimPrefix(ret1, trim)
ret2 := val.Type().Name()
if ret2 == "Area" {
s := strings.Split(ret1, "/")
ret = s[len(s)-2]
break
}
if ret2 == "EndPoint" {
s := strings.Split(ret1, "/")
ret = s[len(s)-1]
break
}
ret = ret1
}
return ret
}
func GetType(v interface{}) string {
return reflect.ValueOf(v).Type().Name()
}
func GetPkgType(v interface{}) string {
return reflect.ValueOf(v).Type().String()
}
func GetStructName(v interface{}) (string, string) {
var area string
var endpoint string
for range Only.Once {
val := reflect.ValueOf(v)
// ret = val.Type().Name() // Returns structure, (EndPoint name).
// ret = val.Type().PkgPath() // Returns structure path.
// ret = val.Type().String() // Returns
// @TODO - Need to check for pointers to struct
// if t := reflect.TypeOf(ref); t.Kind() == reflect.Ptr {
// ret = strings.ToLower(t.Elem().Name())
// } else {
// ret = strings.ToLower(t.Name())
// }
s := strings.Split(val.Type().String(), ".")
if len(s) < 2 {
break
}
area = s[0]
endpoint = s[1]
}
return area, endpoint
}
func DoTypesMatch(a interface{}, b interface{}) error {
var err error
for range Only.Once {
aName := GetType(a)
bName := GetType(b)
if aName == bName {
break
}
err = errors.New(fmt.Sprintf("interface '%s' doesn't match '%s'", aName, bName))
}
return err
}
func DoPkgTypesMatch(a interface{}, b interface{}) error {
var err error
for range Only.Once {
aName := GetPkgType(a)
bName := GetPkgType(b)
if aName == bName {
break
}
err = errors.New(fmt.Sprintf("interface '%s' doesn't match '%s'", aName, bName))
}
return err
}
// VerifyOptionsRequired Verify fields within the structure that are required.
// VerifyOptionsRequired Verify fields within the structure are required.
func VerifyOptionsRequired(ref interface{}) error {
var err error
@ -661,112 +565,3 @@ func VerifyOptionsRequired(ref interface{}) error {
return err
}
func HelpOptions(ref interface{}) string {
var ret string
for range Only.Once {
t := reflect.TypeOf(ref)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
required := field.Tag.Get("required")
if required == "" {
ret += fmt.Sprintf("%s: optional\n", field.Name)
continue
}
ret += fmt.Sprintf("%s: required\n", field.Name)
}
}
return ret
}
func FindRequestData(ref interface{}) string {
var ret string
for range Only.Once {
vo := reflect.ValueOf(ref)
to := reflect.TypeOf(ref)
// Iterate over all available fields and read the tag value
for i := 0; i < vo.NumField(); i++ {
fieldTo := to.Field(i)
// required := fieldTo.Tag.GetByJson("required")
fmt.Printf(">%s\t", fieldTo.Name)
fieldVo := vo.Field(i)
fmt.Printf(">%s\n", fieldVo.String())
value := fmt.Sprintf("%v", fieldVo.Interface())
if value == "" {
break
}
}
}
return ret
}
func GetRequestString(ref interface{}) string {
var ret string
for range Only.Once {
vo := reflect.ValueOf(ref)
// Iterate over all available fields and read the tag value
for i := 0; i < vo.NumField(); i++ {
fieldVo := vo.Field(i)
ret += fmt.Sprintf("-%v", fieldVo.Interface())
}
}
return ret
}
func GetFingerprint(ref interface{}) string {
var ret string
for range Only.Once {
// h := hash(GetRequestString(ref))
h := md5.Sum([]byte(GetRequestString(ref)))
ret = fmt.Sprintf("%x", h)
}
return ret
}
type Required []string
func (r *Required) IsRequired(field string) bool {
var ok bool
for _, f := range *r {
if f == field {
ok = true
}
}
return ok
}
func (r *Required) IsNotRequired(field string) bool {
return !r.IsRequired(field)
}
func GetOptionsRequired(ref interface{}) Required {
var ret []string
for range Only.Once {
t := reflect.TypeOf(ref)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
required := field.Tag.Get("required")
if required == "" {
continue
}
ret = append(ret, field.Name)
}
}
return ret
}

View File

@ -0,0 +1,522 @@
package GoStruct
import (
"GoSungrow/iSolarCloud/api/GoStruct/output"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"fmt"
"github.com/MickMake/GoUnify/Only"
"os"
"reflect"
)
type DataTables struct {
Map []*DataTable
Merge bool
Index bool
}
func (dts *DataTables) Get() []*DataTable {
// for index, val := range dt.Map {
// val.Reflect.String()
// }
return dts.Map
}
func (dts *DataTables) GetTables(timestamp valueTypes.DateTime, parentDeviceId string) output.Tables {
ret := make(output.Tables)
for range Only.Once {
for k, v := range dts.GetDataTables() {
ret[k] = v
}
for k, v := range dts.GetDataMergedTables(timestamp, parentDeviceId) {
ret[k] = v
}
}
return ret
}
func (dts *DataTables) GetDataMergedTables(timestamp valueTypes.DateTime, parentDeviceId string) output.Tables {
ret := make(output.Tables)
for range Only.Once {
if !dts.Merge {
break
}
var data [][]interface{}
var headers []string
if dts.Index {
headers = append(headers, "Date/Time", "Index")
}
// var names []string
var name string
for _, f := range dts.Get() {
if f == nil {
continue
}
if !f.Reflect.DataStructure.DataTable {
continue
}
// names = append(names, f.Name)
dt := f.GetTable()
for index := range dt.Headers {
headers = append(headers, dt.Headers[index])
}
name = dt.EndPoint.String()
fmt.Printf("Name:%s\n", name)
for rowIndex := range dt.Data {
if data == nil {
data = make([][]interface{}, 0)
}
for _, col := range dt.Data[rowIndex] {
if col.DataStructure.PointNameDateFormat == "" {
col.DataStructure.PointNameDateFormat = valueTypes.DateTimeLayout
}
value, _, _ := valueTypes.AnyToUnitValue(col.DataStructure.Value, col.DataStructure.PointUnit,
col.DataStructure.PointValueType, col.DataStructure.PointNameDateFormat)
if (len(data) - 1) < rowIndex {
var d []interface{}
d = append(d, value[0].String())
data = append(data, d)
continue
}
// data[rowIndex] = append(data[rowIndex], uvs[0].String())
data[rowIndex] = append(data[rowIndex], value[0].String())
}
}
}
if dts.Index {
for i := range data {
var t []interface{}
t = append(t, timestamp.String(), i)
data[i] = append(t, data[i]...)
}
}
table := output.NewTable(headers...)
for i := range data {
_ = table.AddRow(data[i]...)
}
// _ = table.SetHeader(headers...)
table.SetTitle("Table %s-%s - (%s)", name, parentDeviceId)
table.SetFilePrefix("%s-%s-%s", name, parentDeviceId)
table.SetGraphFilter("")
ret[name] = table
}
return ret
}
func (dts *DataTables) GetDataTables() output.Tables {
ret := make(output.Tables)
for range Only.Once {
if dts.Merge {
break
}
for _, f := range dts.Map {
if !f.Reflect.DataStructure.DataTable {
continue
}
dt := f.GetTable()
table := output.NewTable(dt.Headers...)
for rowIndex := range dt.Data {
// fmt.Printf("ROW[%d] - %v\n", rowIndex, dt.Data[rowIndex])
var data []interface{}
for _, col := range dt.Data[rowIndex] {
// fmt.Printf("\tCOL[%d][%d] - %s - %s - %v\n", rowIndex, colIndex,
// dt.Data[rowIndex][colIndex].FieldName,
// dt.Data[rowIndex][colIndex].DataStructure.PointId,
// dt.Data[rowIndex][colIndex].DataStructure.Value,
// )
if col.DataStructure.PointNameDateFormat == "" {
col.DataStructure.PointNameDateFormat = valueTypes.DateTimeLayout
}
value, _, _ := valueTypes.AnyToUnitValue(col.DataStructure.Value, col.DataStructure.PointUnit,
col.DataStructure.PointValueType, col.DataStructure.PointNameDateFormat)
data = append(data, value[0].String())
}
_ = table.AddRow(data...)
}
title := dt.Reflect.DataStructure.DataTableTitle
if title == "" {
title = dt.Reflect.DataStructure.DataTableName
}
if title == "" {
title = dt.Reflect.DataStructure.DataTableId
}
table.SetTitle("Data table %s - %s - %s", dt.Name, dt.EndPoint.String(), title)
table.SetFilePrefix("%s-%s", dt.EndPoint.String(), dt.Reflect.DataStructure.DataTableId)
table.SetGraphFilter("")
table.Sort(dt.SortOn)
ret[dt.Reflect.DataStructure.DataTableId] = table
}
}
return ret
}
type DataTable struct {
Reflect *Reflect
Name string
EndPoint EndPointPath
SortOn string
Headers []string
Data [][]*Reflect
Debug bool
}
func (dss *DataStructures) AddTable(ref *Reflect) *DataTable {
var ret *DataTable
for range Only.Once {
if ref.FieldName == NameGoStruct {
break
}
if dss.DataTables.Map == nil {
dss.DataTables.Map = []*DataTable{}
}
ret = &DataTable {
Reflect: ref,
Name: ref.DataStructure.DataTableId,
EndPoint: ref.DataStructure.Endpoint,
SortOn: ref.DataStructure.DataTableSortOn,
Headers: nil,
Data: nil,
}
dss.DataTables.Map = append(dss.DataTables.Map, ret)
// dss.DataTables.SortOn = ref.DataStructure.DataTableSortOn
dss.DataTables.Merge = ref.DataStructure.DataTableMerge
dss.DataTables.Index = ref.DataStructure.DataTableShowIndex
if dss.Debug {
_, _ = fmt.Fprintf(os.Stderr, "DEBUG DataStructures.AddTable() %s - Kind:'%s' Type:'%s'\n",
ref.DataStructure.Endpoint.String(), ref.DataStructure.ValueKind, ref.DataStructure.ValueType)
}
}
return ret
}
func (dt *DataTable) GetTable() DataTable {
for range Only.Once {
if dt.Debug {
_, _ = fmt.Fprintf(os.Stderr,"GetTable() Current[%s]: %s\n", dt.Reflect.DataStructure.DataTableId, dt.Reflect)
}
if !dt.Reflect.DataStructure.DataTable {
break
}
if dt.Reflect.Kind == reflect.Pointer {
// Special case:
// We're going to change the pointer to a proper object reference.
if dt.Reflect.IsNil {
break
}
ref2 := dt.Reflect.ValueOf.Elem().Interface()
if valueTypes.IsNil(ref2) {
break
}
dt.Reflect.SetByFieldName(dt.Reflect.Interface, ref2, "")
if dt.Reflect.IsNil {
break
}
// DO NOT BREAK!
// KEEP FIRST!
}
if dt.Reflect.Kind == reflect.Struct {
// Handle slices here.
for row := 0; row < dt.Reflect.Length; row++ {
var Child Reflect
Child.SetByIndex(*dt.Reflect, *dt.Reflect, row, reflect.Value{}, EndPointPath{})
if Child.IsKnown() {
if row == 0 {
dt.AddHeader(dt.Reflect)
}
dt.AddRow(&Child)
continue
}
ok, refs := dt.GetTableStruct2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableMap2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableSlice2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
}
break
}
if dt.Reflect.Kind == reflect.Slice {
// Handle slices here.
for row := 0; row < dt.Reflect.Length; row++ {
var Child Reflect
Child.SetByIndex(*dt.Reflect, *dt.Reflect, row, reflect.Value{}, EndPointPath{})
if Child.IsKnown() {
if row == 0 {
dt.AddHeader(dt.Reflect)
}
dt.AddRow(&Child)
continue
}
ok, refs := dt.GetTableStruct2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableMap2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableSlice2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
}
break
}
if dt.Reflect.Kind == reflect.Map {
// Handle maps here.
for row, rowMap := range dt.Reflect.FieldVo.MapKeys() {
var Child Reflect
Child.SetByIndex(*dt.Reflect, *dt.Reflect, row, rowMap, EndPointPath{})
if Child.IsKnown() {
if row == 0 {
dt.AddHeader(dt.Reflect)
}
dt.AddRow(&Child)
continue
}
ok, refs := dt.GetTableStruct2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableMap2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
ok, refs = dt.GetTableSlice2(dt.Reflect, &Child)
if ok {
if row == 0 {
dt.AddHeader(refs...)
}
dt.AddRow(refs...)
continue
}
}
break
}
_, _ = fmt.Fprintf(os.Stderr,"ERROR: Field '%s' type not supported (%s): Type %s\n",
dt.Reflect.FieldName, dt.Reflect.DataStructure.DataTableId, dt.Reflect.Kind.String())
}
return *dt
}
func (dt *DataTable) GetTableMap2(Parent *Reflect, Child *Reflect) (bool, []*Reflect) {
var ok bool
var refs []*Reflect
for range Only.Once {
if Child.Kind != reflect.Map {
break
}
ok = true
for col, colMap := range dt.Reflect.FieldVo.MapKeys() {
var ChildStruct Reflect
ChildStruct.SetByIndex(*dt.Reflect, *Child, col, colMap, EndPointPath{})
if dt.GoStructOptions(Parent, Child, &ChildStruct) {
continue
}
if dt.Reflect.DataStructure.DataTableSortOn != "" {
// fmt.Printf("\tChildStruct> %s / %s\n", ChildStruct.FieldName, dt.Reflect.DataStructure.DataTableSortOn)
if dt.Reflect.DataStructure.DataTableSortOn == ChildStruct.FieldName {
dt.SortOn = ChildStruct.DataStructure.PointName
dt.Reflect.DataStructure.DataTableSortOn = ""
}
}
refs = append(refs, &ChildStruct)
}
}
return ok, refs
}
func (dt *DataTable) GetTableSlice2(Parent *Reflect, Child *Reflect) (bool, []*Reflect) {
var ok bool
var refs []*Reflect
for range Only.Once {
if Child.Kind != reflect.Slice {
break
}
ok = true
for col := 0; col < Child.Length; col++ {
var ChildStruct Reflect
ChildStruct.SetByIndex(*dt.Reflect, *Child, col, reflect.Value{}, EndPointPath{})
if dt.GoStructOptions(Parent, Child, &ChildStruct) {
continue
}
if dt.Reflect.DataStructure.DataTableSortOn != "" {
// fmt.Printf("\tChildStruct> %s / %s\n", ChildStruct.FieldName, dt.Reflect.DataStructure.DataTableSortOn)
if dt.Reflect.DataStructure.DataTableSortOn == ChildStruct.FieldName {
dt.SortOn = ChildStruct.DataStructure.PointName
dt.Reflect.DataStructure.DataTableSortOn = ""
}
}
refs = append(refs, &ChildStruct)
}
}
return ok, refs
}
func (dt *DataTable) GetTableStruct2(Parent *Reflect, Child *Reflect) (bool, []*Reflect) {
var ok bool
var refs []*Reflect
for range Only.Once {
if Child.Kind != reflect.Struct {
break
}
ok = true
for col := 0; col < Child.Length; col++ {
var ChildStruct Reflect
ChildStruct.SetByIndex(*dt.Reflect, *Child, col, reflect.Value{}, EndPointPath{})
if dt.GoStructOptions(Parent, Child, &ChildStruct) {
continue
}
if dt.Reflect.DataStructure.DataTableSortOn != "" {
// fmt.Printf("\tChildStruct> %s / %s\n", ChildStruct.FieldName, dt.Reflect.DataStructure.DataTableSortOn)
if dt.Reflect.DataStructure.DataTableSortOn == ChildStruct.FieldName {
dt.SortOn = ChildStruct.DataStructure.PointName
dt.Reflect.DataStructure.DataTableSortOn = ""
}
}
refs = append(refs, &ChildStruct)
}
}
return ok, refs
}
func (dt *DataTable) GoStructOptions(Parent *Reflect, Current *Reflect, Child *Reflect) bool {
var yes bool
for range Only.Once {
if Parent.Kind == reflect.Slice {
// @TODO - Need to check here if the parent is a slice.
// If so - then "parent" is actually Parent.
// If not - then "parent" is actually Current.
}
if Child.FieldName != NameGoStruct {
break
}
yes = true
}
return yes
}
func (dt *DataTable) AddHeader(headers ...*Reflect) {
for range Only.Once {
for _, header := range headers {
name := valueTypes.PointToName(header.DataStructure.PointId)
if header.DataStructure.PointUnit != "" {
name += " (" + header.DataStructure.PointUnit + ")"
}
dt.Headers = append(dt.Headers, name)
}
}
}
func (dt *DataTable) AddRow(refs ...*Reflect) {
for range Only.Once {
if dt.Data == nil {
dt.Data = make([][]*Reflect, 0)
}
var row []*Reflect
row = append(row, refs...)
// for _, ref := range refs {
// }
dt.Data = append(dt.Data, row)
}
}
func (dt *DataTable) GetRow(row int) []*Reflect {
return dt.Data[row]
}
func (dt *DataTable) Get() [][]*Reflect {
return dt.Data
}

View File

@ -1,6 +1,6 @@
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
// Package apiReflect contains various utilities functions to work with structs.
package apiReflect
// Package GoStruct - Snaffooed from https://github.com/fatih/structs
// Package GoStruct contains various utilities functions to work with structs.
package GoStruct
import (
"fmt"

View File

@ -1,5 +1,5 @@
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
package apiReflect
// Package GoStruct - Snaffooed from https://github.com/fatih/structs
package GoStruct
import "strings"

View File

@ -113,8 +113,14 @@ func UnitValueType(unit string) string {
case "F":
fallthrough
case "°F":
fallthrough
case "℉":
fallthrough
case "C":
fallthrough
case "°C":
fallthrough
case "℃":
ret = "Temperature"
}

3
iSolarCloud/api/debug.go Normal file
View File

@ -0,0 +1,3 @@
package api
// DEBUG - Used for easy debugging of this package.
const DEBUG = false

View File

@ -2,8 +2,9 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"errors"
"fmt"
"github.com/MickMake/GoUnify/cmdPath"
@ -14,7 +15,7 @@ import (
func (ep *EndPointStruct) ApiSetFilenamePrefix2(ref interface{}, format string, args ...interface{}) string {
f := strings.Join(apiReflect.GetStructValuesAsArray(ref), "-")
f := strings.Join(GoStruct.GetStructValuesAsArray(ref), "-")
fmt.Printf("[%s]\n", f)
if format != "" {
ep.FileNamePrefix = fmt.Sprintf(format, args...)
@ -171,12 +172,12 @@ func (ep *EndPointStruct) ApiRemoveDataFile() error {
}
func (ep *EndPointStruct) ApiCacheFilename(request interface{}) string {
postfix := apiReflect.GetFingerprint(request)
postfix := reflection.GetFingerprint(request)
return fmt.Sprintf("%s_%s-%s.json", ep.Area, ep.Name, postfix)
}
func (ep *EndPointStruct) ApiFingerprint(request interface{}) string {
return apiReflect.GetFingerprint(request)
return reflection.GetFingerprint(request)
}
// func (ep *EndPointStruct) ApiCacheFilePath(request interface{}) string {

View File

@ -1,6 +1,6 @@
package api
import "GoSungrow/iSolarCloud/api/output"
import "GoSungrow/iSolarCloud/api/GoStruct/output"
type Area interface {
Init(*Web) AreaStruct

View File

@ -1,7 +1,7 @@
package api
import (
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"time"
)

View File

@ -274,7 +274,7 @@ package api
// func (dm *DataMap) AddUnitValue(endpoint string, parentId string, pid valueTypes.PointId, name string, groupName string, date valueTypes.DateTime, ref valueTypes.UnitValue) {
// for range Only.Once {
// if endpoint == "" {
// endpoint = apiReflect.GetCallerPackage(2)
// endpoint = GoStruct.GetCallerPackage(2)
// }
//
// ref = ref.UnitValueFix()

View File

@ -1,301 +0,0 @@
package output
import (
"GoSungrow/Only"
"errors"
"fmt"
"go.pennock.tech/tabular"
datatable "go.pennock.tech/tabular/auto"
"os"
"reflect"
)
type Table struct {
filePrefix string
title string
table datatable.RenderTable
graph *Chart
json []byte
raw []byte
OutputType OutputType
saveAsFile bool
graphFilter string
Error error
}
type Tables map[string]Table
func NewTable() Table {
return Table {
filePrefix: "",
title: "",
table: datatable.New("utf8-heavy"),
// graph: graph.New(""),
Error: nil,
}
}
func NewTables() Tables {
return make(Tables)
}
func (t *Table) String() string {
var ret string
for range Only.Once {
if t == nil {
break
}
ret, t.Error = t.table.Render()
if t.Error != nil {
break
}
}
return ret
}
func (t *Table) GetHeaders() []tabular.Cell {
return t.table.Headers()
}
func (t *Table) AllRows() []*tabular.Row {
return t.table.AllRows()
}
type DataSet []DataRow
type DataRow map[string]string
func (t *Table) SetTitle(title string, args ...interface{}) {
t.title = fmt.Sprintf(title, args...)
}
func (t *Table) SetRaw(data []byte) {
t.raw = data
}
func (t *Table) AppendRaw(data []byte) {
t.raw = append(t.raw, data...)
}
func (t *Table) SetJson(data []byte) {
t.json = data
}
func (t *Table) SetSaveFile(ok bool) {
t.saveAsFile = ok
}
func (t *Table) SetGraphFilter(filter string) {
t.graphFilter = filter
}
func (t *Table) SetFilePrefix(prefix string) {
t.filePrefix = prefix
}
func (t *Table) SetOutputType(outputType string) {
t.OutputType.Set(outputType)
}
func (t *Table) SetHeader(header...interface{}) error {
t.table.AddHeaders(header...)
t.Error = t.getErrors()
return t.Error
}
func (t *Table) AddRow(row ...interface{}) error {
t.table.AddRowItems(row...)
t.Error = t.getErrors()
return t.Error
}
func (t *Table) getErrors() error {
if errs := t.table.Errors(); errs != nil {
for _, err := range errs {
t.Error = err
break
}
}
return t.Error
}
func (t *Table) writeFile(fn string, data string, perm os.FileMode) error {
for range Only.Once {
fmt.Printf("Writing file '%s'\n", fn)
t.Error = os.WriteFile(fn, []byte(data), perm)
if t.Error != nil {
t.Error = errors.New(fmt.Sprintf("Unable to write to file %s - %v", fn, t.Error))
break
}
}
return t.Error
}
func (t *Table) Output() error {
for range Only.Once {
if t == nil {
break
}
// switch {
// case sg.OutputType.IsNone():
// if sg.Error != nil {
// fmt.Println(ret.Help())
// break
// }
//
// case sg.OutputType.IsRaw():
// // if sg.Error != nil {
// // fmt.Println(ret.Help())
// // break
// // }
// if sg.SaveAsFile {
// sg.Error = ret.WriteDataFile()
// break
// }
// fmt.Println(ret.GetJsonData(true))
//
// case sg.OutputType.IsJson():
// if sg.Error != nil {
// fmt.Println(ret.Help())
// break
// }
// if sg.SaveAsFile {
// sg.Error = ret.WriteDataFile()
// break
// }
// fmt.Println(ret.GetJsonData(false))
//
// default:
// if sg.Error != nil {
// fmt.Println(ret.Help())
// break
// }
// }
switch {
case t.OutputType.IsNone():
case t.OutputType.IsTable():
t.Error = t.WriteTable()
case t.OutputType.IsList():
t.Error = t.WriteList()
case t.OutputType.IsCsv():
t.Error = t.WriteCsv()
case t.OutputType.IsRaw():
t.Error = t.WriteRaw()
case t.OutputType.IsJson():
t.Error = t.WriteJson()
case t.OutputType.IsGraph():
t.Error = t.SetGraphFromJson(Json(t.graphFilter))
if t.Error != nil {
break
}
t.Error = t.CreateGraph()
if t.Error != nil {
break
}
default:
}
}
return t.Error
}
func (t *Table) GetTable() string {
return t.String()
}
func (t *Table) WriteTable() error {
if t.saveAsFile {
return t.writeFile(t.filePrefix + "-table.txt", t.String(), DefaultFileMode)
}
fmt.Printf("# %s\n", t.title)
fmt.Print(t.String())
return nil
}
func (t *Table) WriteList() error {
if t.saveAsFile {
return t.writeFile(t.filePrefix + ".txt", t.String(), DefaultFileMode)
}
fmt.Printf("# %s\n", t.title)
fmt.Print(t.String())
return nil
}
func (t *Table) GetCsv() string {
var ret string
for range Only.Once {
if t == nil {
break
}
for _, h := range t.GetHeaders() {
ret += fmt.Sprintf("%s,", h)
}
ret += fmt.Sprintf("\n")
for _, r := range t.AllRows() {
for _, c := range r.Cells() {
switch reflect.ValueOf(c.Item()).Type().Name() {
case "string":
ret += fmt.Sprintf("\"%s\",", c)
default:
ret += fmt.Sprintf("%s,", c)
}
}
ret += fmt.Sprintf("\n")
}
}
return ret
}
func (t *Table) WriteCsv() error {
if t.saveAsFile {
return t.writeFile(t.filePrefix+".csv", t.GetCsv(), DefaultFileMode)
}
fmt.Print(t.GetCsv())
return nil
}
func (t *Table) GetJson() string {
return string(t.raw)
}
func (t *Table) WriteJson() error {
if t.saveAsFile {
return t.writeFile(t.filePrefix + ".json", string(t.json), DefaultFileMode)
}
fmt.Printf("%s", t.json)
return nil
}
func (t *Table) GetRaw() string {
return string(t.json)
}
func (t *Table) GetRawBytes() []byte {
return t.json
}
func (t *Table) WriteRaw() error {
if t.saveAsFile {
return t.writeFile(t.filePrefix+".raw", string(t.raw), DefaultFileMode)
}
fmt.Printf("%s", t.raw)
return nil
}

View File

@ -2,7 +2,7 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"errors"
"fmt"
"github.com/olekukonko/tablewriter"

View File

@ -2,14 +2,13 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"encoding/json"
"fmt"
datatable "go.pennock.tech/tabular/auto"
"os"
"reflect"
"sort"
"strings"
"time"
@ -17,7 +16,6 @@ import (
type DataMap struct {
// DataStructures apiReflect.DataStructures
Map map[string]*DataEntries
Table output.Table
DataTables output.Tables
@ -30,21 +28,23 @@ func NewDataMap() DataMap {
}
}
func (dm *DataMap) StructToDataMap(endpoint EndPoint, parentDeviceId string, name apiReflect.EndPointPath) {
func (dm *DataMap) StructToDataMap(endpoint EndPoint, parentDeviceId string, name GoStruct.EndPointPath) DataMap {
for range Only.Once {
epName := apiReflect.NewEndPointPath(apiReflect.GetName("", endpoint))
epName := GoStruct.NewEndPointPath(reflection.GetName("", endpoint))
name = epName.Append(name...)
timestamp := valueTypes.SetDateTimeValue(time.Now().Round(5 * time.Minute))
// Iterate over all available fields and read the tag values
var tp apiReflect.DataStructures
var Parent GoStruct.Reflect
Parent.SetByFieldName(endpoint.ResponseRef(), endpoint.ResponseRef(), name[0])
Current := GoStruct.FindStart("ResultData", Parent, Parent, name)
name = Current.DataStructure.Endpoint.Copy()
var tp GoStruct.DataStructures
tp.Debug = false
tp.ShowEmpty = true
var Ref apiReflect.Reflect
Ref.SetByFieldName(endpoint.ResponseRef(), endpoint.ResponseRef(), "")
Ref = FindResultData(Ref, Ref)
tp.GetPointTags(Ref, Ref, name)
tp.GetPointTags(&Parent, Current, name)
// Convert to DataMap
for _, f := range tp.DataMap {
@ -65,7 +65,10 @@ func (dm *DataMap) StructToDataMap(endpoint EndPoint, parentDeviceId string, nam
}
// fmt.Printf("DEBUG: StructToPoints(): %s / %s\n", f.Endpoint, f.PointId)
uvs, _, ok := valueTypes.AnyToUnitValue(f.Value, f.PointUnit, f.PointValueType, valueTypes.DateTimeLayout)
if f.PointNameDateFormat == "" {
f.PointNameDateFormat = valueTypes.DateTimeLayout
}
uvs, _, ok := valueTypes.AnyToUnitValue(f.Value, f.PointUnit, f.PointValueType, f.PointNameDateFormat)
if !ok {
continue
}
@ -110,160 +113,20 @@ func (dm *DataMap) StructToDataMap(endpoint EndPoint, parentDeviceId string, nam
}
}
// Create data tables.
dm.Table = dm.CreateEndPointResultTable()
dm.Table.SetTitle(fmt.Sprintf("EndPoint Data: %s", name))
dm.Table.SetFilePrefix(fmt.Sprintf("%s_%s", endpoint.GetArea(), endpoint.GetName()))
dm.Table.SetTitle("EndPoint Data: %s", name)
dm.Table.SetFilePrefix("%s_%s", endpoint.GetArea(), endpoint.GetName())
dm.Table.SetJson([]byte(endpoint.GetJsonData(false)))
dm.Table.SetRaw([]byte(endpoint.GetJsonData(true)))
dm.DataTables = output.NewTables()
if tp.DataTables.Merge {
var data [][]interface{}
var headers []interface{}
if tp.DataTables.Index {
headers = append(headers, "Date/Time", "Index")
}
for _, f := range tp.DataTables.Get() {
if f == nil {
continue
}
if !f.Reflect.DataStructure.DataTable {
continue
}
dt := f.GetTable()
for index := range dt.Headers {
headers = append(headers, dt.Headers[index])
}
for rowIndex, _ := range dt.Data {
if data == nil {
data = make([][]interface{}, 0)
}
for _, col := range dt.Data[rowIndex] {
// uvs, _, ok := valueTypes.AnyToUnitValue(col.DataStructure.Value, col.DataStructure.PointUnit, col.DataStructure.PointValueType, valueTypes.DateTimeLayout)
// if !ok {
// continue
// }
if (len(data) - 1) < rowIndex {
var d []interface{}
d = append(d, col.DataStructure.Value)
data = append(data, d)
continue
}
// data[rowIndex] = append(data[rowIndex], uvs[0].String())
data[rowIndex] = append(data[rowIndex], col.DataStructure.Value)
}
}
}
if tp.DataTables.Index {
for i := range data {
var t []interface{}
t = append(t, timestamp.String(), i)
data[i] = append(t, data[i]...)
}
}
table := output.NewTable()
for i := range data {
// fmt.Printf("DEBUG: StructToPoints(): %s / %s\n", f.Endpoint, f.PointId)
_ = table.AddRow(data[i]...)
}
_ = table.SetHeader(headers...)
table.SetTitle(fmt.Sprintf("Table %s-%s - (%s)", endpoint.GetArea(), endpoint.GetName(), parentDeviceId))
table.SetFilePrefix(fmt.Sprintf("%s-%s-%s", endpoint.GetArea(), endpoint.GetName(), parentDeviceId))
table.SetGraphFilter("")
dm.DataTables[fmt.Sprintf("%s.%s", endpoint.GetArea(), endpoint.GetName())] = table
break
}
// for _, f := range tp.DataTables.Get() {
// if f == nil {
// continue
// }
// if !f.Reflect.DataStructure.DataTable {
// continue
// }
//
// dt := f.GetTable()
// for index := range dt.Headers {
// headers = append(headers, dt.Headers[index])
// }
//
// for rowIndex, _ := range dt.Data {
// if data == nil {
// data = make([][]interface{}, 0)
// }
// for _, col := range dt.Data[rowIndex] {
// uvs, _, ok := valueTypes.AnyToUnitValue(col.DataStructure.Value, col.DataStructure.PointUnit, col.DataStructure.PointValueType, valueTypes.DateTimeLayout)
// if !ok {
// continue
// }
//
// // var point Point
// // p := GetPoint(strings.Join(col.DataStructure.Endpoint, ".") + "." + col.DataStructure.PointId)
// // if p == nil {
// // // No point found. Create one.
// // point = CreatePoint(parentDeviceId, valueTypes.SetPointIdString(col.DataStructure.PointId), col.DataStructure.PointName, col.DataStructure.PointGroupName, uvs.Unit(), uvs.Type(), col.DataStructure.PointUpdateFreq)
// // } else {
// // point = *p
// // }
// // point.UpdateFreq = col.DataStructure.PointUpdateFreq
// // point.SetName(col.DataStructure.PointName)
//
// if (len(data) - 1) < rowIndex {
// var d []interface{}
// d = append(d, uvs[0].String())
// data = append(data, d)
// continue
// }
// data[rowIndex] = append(data[rowIndex], uvs[0].String())
// }
// }
// }
for _, f := range tp.DataTables.Get() {
if !f.Reflect.DataStructure.DataTable {
continue
}
table := output.NewTable()
dt := f.GetTable()
var headers []interface{}
for _, h := range dt.Headers {
headers = append(headers, h)
}
_ = table.SetHeader(headers...)
for row := range dt.Data {
var data []interface{}
for _, col := range dt.Data[row] {
data = append(data, col.DataStructure.Value)
}
_ = table.AddRow(data...)
}
title := dt.Reflect.DataStructure.DataTableTitle
if title == "" {
title = dt.Reflect.DataStructure.DataTableName
}
if title == "" {
title = dt.Reflect.DataStructure.DataTableId
}
table.SetTitle(fmt.Sprintf("List %s-%s - %s", endpoint.GetArea(), endpoint.GetName(), title))
table.SetFilePrefix(fmt.Sprintf("%s-%s-%s", endpoint.GetArea(), endpoint.GetName(), dt.Reflect.DataStructure.DataTableId))
table.SetGraphFilter("")
dm.DataTables[dt.Reflect.DataStructure.DataTableId] = table
}
dm.DataTables = tp.DataTables.GetDataMergedTables(timestamp, parentDeviceId)
dm.DataTables = tp.DataTables.GetDataTables()
// dm.GetDataMergedTables(endpoint, tp.DataTables, timestamp, parentDeviceId)
// dm.GetDataTables(endpoint, tp.DataTables)
}
return *dm
}
func (dm *DataMap) AddPointUnitValue(endpoint string, parentDeviceId string, point Point, date valueTypes.DateTime, uv valueTypes.UnitValue) {
@ -451,20 +314,29 @@ func (dm *DataMap) TableSort() []string {
}
func (dm *DataMap) CreateEndPointResultTable() output.Table {
table := output.NewTable()
table := output.NewTable(
"Date",
"Point Id",
"Value",
"Unit",
"Unit Type",
"Group Name",
"Description",
"Update Freq",
)
for range Only.Once {
for _, p := range dm.Sort() {
_ = table.SetHeader(
"Date",
"Point Id",
"Value",
"Unit",
"Unit Type",
"Group Name",
"Description",
"Update Freq",
)
// _ = table.SetHeader(
// "Date",
// "Point Id",
// "Value",
// "Unit",
// "Unit Type",
// "Group Name",
// "Description",
// "Update Freq",
// )
entries := dm.Map[p].Entries
for _, de := range entries {
@ -472,10 +344,9 @@ func (dm *DataMap) CreateEndPointResultTable() output.Table {
continue
}
_ = table.AddRow(
de.Date.Format(valueTypes.DateTimeLayout),
_ = table.AddRow(de.Date.Format(valueTypes.DateTimeLayout),
p,
de.Value,
de.Value.String(),
de.Point.Unit,
de.Point.ValueType,
de.Point.GroupName,
@ -626,58 +497,3 @@ func JoinWithDots(intSize int, dateFormat string, args ...interface{}) string {
}
return ret
}
func FindResultData(Parent apiReflect.Reflect, Current apiReflect.Reflect) apiReflect.Reflect {
var ret apiReflect.Reflect
for range Only.Once {
if Current.Kind == reflect.Pointer {
// Special case:
// We're going to change the pointer to a proper object reference.
if Current.IsNil {
break
}
ref2 := Current.ValueOf.Elem().Interface()
if valueTypes.IsNil(ref2) {
break
}
Current.SetByFieldName(Current.Interface, ref2, "")
if Current.IsNil {
break
}
// DO NOT BREAK!
// KEEP FIRST!
}
if Current.Kind == reflect.Struct {
// Iterate over all available fields and read the tag value
for si := 0; si < Current.Length; si++ {
var Child apiReflect.Reflect
Child.SetByIndex(Parent, Current, si, apiReflect.EndPointPath{})
if Child.DataStructure.PointId == "result_data" {
ret = Child
break
}
if Child.Kind != reflect.Struct {
continue
}
if Child.IsKnown() {
continue
}
Child = FindResultData(Current, Child)
if Child.DataStructure.PointId == "ResultData" {
ret = Child
break
}
}
break
}
_, _ = fmt.Fprintf(os.Stderr,"ERROR: Field '%s' type not supported: Type %s\n", Current.FieldName, Current.Kind.String())
}
return ret
}

View File

@ -1,7 +1,7 @@
package api
import (
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"github.com/MickMake/GoUnify/Only"
)

View File

@ -1,7 +1,7 @@
package api
import (
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"github.com/MickMake/GoUnify/Only"
)

View File

@ -2,8 +2,8 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"encoding/json"
"errors"
"fmt"
@ -12,6 +12,10 @@ import (
type EndPointName string
func (n EndPointName) String() string {
return string(n)
}
type EndPointStruct struct {
ApiRoot Web `json:"-"`
RawResponse []byte
@ -118,9 +122,10 @@ func (ep EndPointStruct) ResponseAsJson(raw bool, r interface{}) output.Json {
}
func (ep EndPointStruct) ApiGetRequestArgNames(req interface{}) map[string]string {
return apiReflect.GetStructFields(req)
return GoStruct.GetStructFields(req)
}
func MarshalJSON(endpoint EndPoint) ([]byte, error) {
e := endpoint.SetError("")
j, err := json.Marshal(&struct {

View File

@ -2,8 +2,8 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"fmt"
"strings"
"time"
@ -76,35 +76,35 @@ func (p Point) String() string {
}
func (p Point) IsInstant() bool {
if p.UpdateFreq == apiReflect.UpdateFreqInstant {
if p.UpdateFreq == GoStruct.UpdateFreqInstant {
return true
}
return false
}
func (p Point) IsDaily() bool {
if p.UpdateFreq == apiReflect.UpdateFreqDay {
if p.UpdateFreq == GoStruct.UpdateFreqDay {
return true
}
return false
}
func (p Point) IsMonthly() bool {
if p.UpdateFreq == apiReflect.UpdateFreqMonth {
if p.UpdateFreq == GoStruct.UpdateFreqMonth {
return true
}
return false
}
func (p Point) IsYearly() bool {
if p.UpdateFreq == apiReflect.UpdateFreqYear {
if p.UpdateFreq == GoStruct.UpdateFreqYear {
return true
}
return false
}
func (p Point) IsTotal() bool {
if p.UpdateFreq == apiReflect.UpdateFreqTotal {
if p.UpdateFreq == GoStruct.UpdateFreqTotal {
return true
}
return false

View File

@ -15,7 +15,6 @@ type Response struct {
type ResponseCommon struct {
ReqSerialNum string `json:"req_serial_num"`
ResultCode string `json:"result_code"`
ResultData []interface{} `json:"result_data"`
ResultMsg string `json:"result_msg"`
}

View File

@ -2,7 +2,7 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/valueTypes"
"GoSungrow/iSolarCloud/api/GoStruct/valueTypes"
"fmt"
"strings"
)

View File

@ -1,7 +1,7 @@
package api
import (
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct/output"
)
@ -35,12 +35,12 @@ func (e *Web) ApiGetEndPointDataTables(endpoint EndPoint) output.Tables {
table := output.NewTables()
// for range Only.Once {
//
// var tp apiReflect.DataStructures
// var tp GoStruct.DataStructures
// tp.Debug = true
// tp.ShowEmpty = true
// var Ref apiReflect.Reflect
// var Ref GoStruct.Reflect
// Ref.SetByFieldName(endpoint.ResponseRef(), endpoint.ResponseRef(), "")
// // tp.FindDataTables(Ref, Ref, apiReflect.EndPointPath{}, false)
// // tp.FindDataTables(Ref, Ref, GoStruct.EndPointPath{}, false)
//
// // data := endpoint.GetEndPointData()
// //

View File

@ -2,7 +2,7 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/GoStruct/reflection"
"fmt"
"net/url"
"reflect"
@ -37,11 +37,11 @@ func AppendUrl(host string, endpoint string) *url.URL {
}
func GetArea(v interface{}) AreaName {
return AreaName(apiReflect.GetArea(thisPackagePath, v))
return AreaName(reflection.GetArea(thisPackagePath, v))
}
func GetName(v interface{}) EndPointName {
return EndPointName(apiReflect.GetName(thisPackagePath, v))
return EndPointName(reflection.GetName(thisPackagePath, v))
}
func GetUrl(u string) *url.URL {
@ -59,7 +59,7 @@ func GetUrl(u string) *url.URL {
// func GetStructKeys(ref interface{}, keys ...string) valueTypes.UnitValueMap {
// ret := make(valueTypes.UnitValueMap)
//
// for _, k := range apiReflect.GetStructKeys(ref, keys...) {
// for _, k := range GoStruct.GetStructKeys(ref, keys...) {
// // p := UnitValue { Value: k.Value, Unit: "" }
// p := valueTypes.SetUnitValueString(k.Value, "", "")
// if k.Type.Name() == "UnitValue" {

View File

@ -2,8 +2,8 @@ package api
import (
"GoSungrow/Only"
"GoSungrow/iSolarCloud/api/apiReflect"
"GoSungrow/iSolarCloud/api/output"
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"github.com/MickMake/GoUnify/cmdPath"
"path/filepath"
"time"
@ -107,7 +107,7 @@ func (w *Web) Get(endpoint EndPoint) EndPoint {
func (w *Web) getApi(endpoint EndPoint) ([]byte, error) {
for range Only.Once {
request := endpoint.RequestRef()
w.Error = apiReflect.VerifyOptionsRequired(request)
w.Error = GoStruct.VerifyOptionsRequired(request)
if w.Error != nil {
break
}