I have a loop in which the values are sorted, as well as the comparison of these values. If there are identical values, they are removed from the same array of values. After that, I want to do the following so that the code continues to run until the end. And after that, inform users that these values (which were deleted) were not added. But I wrote the code, so this causes the execution of further code to stop. Tell me how to make it right so that even if the same values meet, the code works to the end and only then output messages about these identical values.
In addition: I give the structure in json without duplicates. But I also want to give information that errors have occurred. Tell me how to implement this moment correctly
type Result struct {
Result int `json:"result"`
Message string `json:"message"`
Status []string
}
var result Result
var searchProject = make([]struct{
ProjectId string
}, 0)
var query string
switch Type {
case sku:
query = fmt.Sprintf(`
SELECT s.project_id
FROM sku.sku_projects s
WHERE s.deleted_at IS NULL
AND s.sku_id = %d
AND s.project_id IN (%s)
`, val.FieldByName("SkuID").Int(), ProjectId)
case user:
query = fmt.Sprintf(`
SELECT u.project_id
FROM users.user_project u
WHERE u.deleted_at IS NULL
AND u.user_id = %d
AND u.project_id IN (%s)
`, val.FieldByName("UserID").Int(), ProjectId)
case reason:
query = fmt.Sprintf(`
SELECT r.project_id
FROM reasons.reason_projects r
WHERE r.deleted_at IS NULL
AND r.reason_id = %d
AND r.project_id IN (%s)
`, val.FieldByName("ReasonID").Int(), ProjectId)
default:
http.NotFound(w, r)
return
}
_ = DB.Raw(query).Scan(&searchProject)
key := make([]int, 0)
double := make([]string, 0)
if len(searchProject) > 0{
for _, v := range searchProject{
for i, value := range Projects{
if value == v.ProjectId{
key = append(key, i)
double = append(double, value)
}
}
}
for _, v := range key{
Projects = append(Projects[:v], Projects[v+1:]...)
}
}
if len(key) > 0{
if (len(Projects) != len(searchProject)) {
http.Error(w, ("You are connecting already existing bindings"), http.StatusBadRequest)
return
}else {
result.Result = 0
result.Message = "The following project bindings already exist:"
result.Status = double
utils.WriteJSON(w, result)
}
}
utils.WriteJSON(w, &Struct)
}
}
Try to use this library from hashicorp. Basically you need to collect all the errors into an array and then return it
Using multierr
var err error
// ... your logic
// where I assume you want to error
if (len(Projects) != len(searchProject)) {
err = multierr.Append(err, errors.New("you new error message"))
}
// when you return a reply
http.Error(w, err.Error(), http.StatusBadRequest)
Related
Consider the following method which executes a gremlin query in Go and then interprets or parses the results.
func (n NeptuneGremlinGraph) Query(assetID string, version string, entityID string) ([]hz.Component, error) {
defer utils.TimeTracker(time.Now(), fmt.Sprintf("Graph Query"))
g := gremlin.Traversal_().WithRemote(n.connection)
anonT := gremlin.T__
results, err := g.V(makeId(assetID, version, entityID)).
Repeat(anonT.As("a").InE().OutV().SimplePath()).
Emit().Until(anonT.OutE().Count().Is(0)).
Filter(anonT.HasLabel("Component")).
Project("entity", "component").
By(anonT.Select("a").ElementMap()).
By(anonT.ElementMap()).
ToList()
if err != nil {
return nil, err
}
cnt := 0
for _, r := range results {
var entityID, componentID, value string
if m, ok := r.Data.(map[any]any); ok {
if entity, ok := m["entity"]; ok {
if entity, ok := entity.(map[any]any); ok {
if id, ok := entity["id"]; ok {
if id, ok := id.(string); ok {
_, _, entityID = splitId(id)
}
}
}
}
if component, ok := m["component"]; ok {
if component, ok := component.(map[any]any); ok {
if id, ok := component["component_id"]; ok {
if id, ok := id.(string); ok {
componentID = id
}
}
if v, ok := component["value"]; ok {
if v, ok := v.(string); ok {
value = v
}
}
}
}
log.Printf("%s, %s, %s\n", entityID, componentID, value)
} else {
log.Printf("not a map\n")
}
}
log.Printf("path cnt = %d\n", cnt)
return nil, nil
}
Obviously I could add helper methods to clean up the query processing code. But either way the query processing code has to deal with multiple layers of map[any]any and any values.
Am I missing some methods in the driver Result object that make this easier?
The Go GLV does not have any built in tools to assist in traversing maps. I would suggest not using the ElementMap() step if you do not need the full map. Since it appears that the only data you are looking for is the id of both “entity” and “component” as well as the component value, you could simplify your result by using a traversal which only selects these items, instead of the full element maps. The following is an example from gremlin console doing something similar to this using a sample dataset:
gremlin> g.V().repeat(__.as("a").inE().outV().simplePath()).emit().until(__.outE().count().is(0)).filter(__.hasLab
el("person")).project("entityID", "personID", "personValue").by(__.select("a").id()).by(__.id()).by(__.values()).toList()
==>{entityID=2, personID=1, personValue=marko}
==>{entityID=3, personID=1, personValue=marko}
==>{entityID=3, personID=4, personValue=josh}
==>{entityID=3, personID=6, personValue=peter}
==>{entityID=4, personID=1, personValue=marko}
==>{entityID=4, personID=1, personValue=marko}
==>{entityID=5, personID=4, personValue=josh}
==>{entityID=4, personID=1, personValue=marko}
This cleans things up, but is obviously not safe, and could lead to panics.
for _, r := range results {
var entityID, componentID, value string
if m, ok := r.Data.(map[any]any); ok {
_, _, entityID = splitId(m["entity"].(map[any]any)["id"].(string))
componentID = m["component"].(map[any]any)["component_id"].(string)
value = m["component"].(map[any]any)["value"].(string)
components = append(components, hz.Component{
EntityID: entityID,
ComponentID: componentID,
Value: value,
})
} else {
log.Printf("not a map\n")
}
}
I use Go to build my game server. I am going to compare a time from time.Now() and one from a Firestore field. How can I do that in Go?
playerDataSnap, err := Instace.FireStoreClient.Collection("PlayerData").Doc(playerUID).Get(Instace.Context)
if err != nil {
log.Printf("EventModeFee Get PlayerData Fail: %v", err)
return
}
playerData := playerDataSnap.Data()
if value, exist := playerData["EventPlayTimes"]; exist {
eventPlayTimes = value.(int64)
}
if discount_Subscribe > 0 {
if value, exist := playerData["SubscriptionExpiredDate"]; exist { //Get Subscribe expired time
var expireTimeStamp = value //<-------------timestamp from firestore field
if time.Now().Before(expireTimeStamp) {//<---------------expireTimeStamp is not a valid type, but How can I convert it to a valid type
isSubscribed = true
}
}
}
expireTimeStamp is not a valid type, but how can I convert it to a valid one?
It turns out that I can directly assert the timestamp from Firestore field to time.Time with the following code:
if time.Now().Before(expireTimeStamp.(time.Time)) {
isSubscribed = true
}
Im working with for each loop and var of information and filtering it by A) regex.matchString B)Timecomparrison. The filtering works well and I have the data I need but currently I'm outputting it to screen via fmt.Println in part of the loop. My goal is to take that data and build another var with the now filtered list. I guess I need to make a new variable and add to it? But how do I return that and something I can use later?
Any assistance is appreciated.
for _, thing := range things {
if thing.element1 != nil {
matched, err := regexp.MatchString(z, element1)
if err != nil {
fmt.Println(err)
}
if matched {
if timecomparrison(element2, a) {
// this is a section that needs to be added new var and returned as a var
fmt.Println("****")
fmt.Println("element1:", element1)
fmt.Println("element2:", element2)
}
}
}
}
}
I think you need something like this.
type Thing struct {
element1 string
element2 string
}
func filter() []Thing {
things := []Thing{
{element1: "element1", element2: "element2"},
}
var result []Thing
regex := "/{}d/"
date := time.Now
for _, thing := range things {
if thing.element1 != nil {
matched, err := regexp.MatchString(regex, thing.element1)
if err != nil {
fmt.Println(err)
}
if matched {
if timeComparison(thing.element2, date) {
// this is a section that needs to be added new var and returned as a var
fmt.Println("****")
fmt.Println("element1:", thing.element1)
fmt.Println("element2:", thing.element2)
result = append(result, thing)
}
}
}
}
return result
}
I cleaned the code, added a type and some data, fixed some issues and renamed some things, but you should get the idea :)
I have been doing some golang programming and usually has been lot of fun. Now I have this code I need to port from C# to go and it is just not working.
The idea is to fill a tree of employees from database but inner slices are not being filled up on each call.
Better to write the code here
func (db *DalBase) TitleAllChildren(tx *gorp.Transaction) (items []Title, err error) {
var dbChildren []entities.Title
_, err = tx.Select(&dbChildren, "select * from title where idparent is null order by name")
if err != nil {
return
}
items = make([]Title, 0)
for i := range dbChildren {
currItem := &dbChildren[i]
item := &Title{Id: currItem.Id, Name: currItem.Name}
err = db.TitleChildrenRecursive(tx, item)
if err != nil {
return
}
items = append(items, *item)
}
return
}
func (db *DalBase) TitleChildrenRecursive(tx *gorp.Transaction, u *Title) (err error) {
var dbChildren []entities.Title
_, err = tx.Select(&dbChildren, "select * from title where idparent = $1 order by name", u.Id)
if err != nil {
return
}
if len(dbChildren) != 0 {
u.Items = make([]Title, 0)
for i := range dbChildren {
currItem := &dbChildren[i]
item := &Title{Id: currItem.Id, Name: currItem.Name}
err = db.TitleChildrenRecursive(tx, item)
if err != nil {
return
}
u.Items = append(item.Items, *item)
}
}
return
}
I have logged the values on each recursive call and they are being filled inside the function, but when it bubbles up to the parent, slices are empty.
I wouldn't like to use pointers to slices, is it possible to implement?
Edit: here is the struct I am trying to fill
type Title struct {
Id string `json:"id"`
Name string `json:"name"`
Items []Title `json:"items"`
}
You won't need a pointer to a slice, as long you are passing around a pointer to the struct which contains your slice.
Each time you call TitleChildrenRecursive, you're replacing your slice with a new one before anything is appended:
u.Items = make([]Title, 0)
There's no need to make a new slice, since append works correctly with a nil slice.
You should also change []Title to []*Title, so that if any append operations happen to children items after they are added to the slice, it's reflected throughout the tree.
I'm looking to iterate over the string fields of a struct so I can do some clean-up/validation (with strings.TrimSpace, strings.Trim, etc).
Right now I have a messy switch-case that's not really scalable, and as this isn't in a hot spot of my application (a web form) it seems leveraging reflect is a good choice here.
I'm at a bit of a roadblock for how to implement this however, and the reflect docs are a little confusing to me (I've been digging through some other validation packages, but they're way too heavyweight + I'm using gorilla/schema for the unmarshalling part already):
Iterate over the struct
For each field of type string, apply whatever I need to from the strings package i.e. field = strings.TrimSpace(field)
If there exists a field.Tag.Get("max"), we'll use that value (strconv.Atoi, then unicode.RuneCountInString)
Provide an error slice that's also compatible with the error interface type
type FormError []string
type Listing struct {
Title string `max:"50"`
Location string `max:"100"`
Description string `max:"10000"`
ExpiryDate time.Time
RenderedDesc template.HTML
Contact string `max:"255"`
}
// Iterate over our struct, fix whitespace/formatting where possible
// and return errors encountered
func (l *Listing) Validate() error {
typ := l.Elem().Type()
var invalid FormError
for i = 0; i < typ.NumField(); i++ {
// Iterate over fields
// For StructFields of type string, field = strings.TrimSpace(field)
// if field.Tag.Get("max") != "" {
// check max length/convert to int/utf8.RuneCountInString
if max length exceeded, invalid = append(invalid, "errormsg")
}
if len(invalid) > 0 {
return invalid
}
return nil
}
func (f FormError) Error() string {
var fullError string
for _, v := range f {
fullError =+ v + "\n"
}
return "Errors were encountered during form processing: " + fullError
}
Thanks in advance.
What you want is primarily the methods on reflect.Value called NumFields() int and Field(int). The only thing you're really missing is the string check and SetString method.
package main
import "fmt"
import "reflect"
import "strings"
type MyStruct struct {
A,B,C string
I int
D string
J int
}
func main() {
ms := MyStruct{"Green ", " Eggs", " and ", 2, " Ham ", 15}
// Print it out now so we can see the difference
fmt.Printf("%s%s%s%d%s%d\n", ms.A, ms.B, ms.C, ms.I, ms.D, ms.J)
// We need a pointer so that we can set the value via reflection
msValuePtr := reflect.ValueOf(&ms)
msValue := msValuePtr.Elem()
for i := 0; i < msValue.NumField(); i++ {
field := msValue.Field(i)
// Ignore fields that don't have the same type as a string
if field.Type() != reflect.TypeOf("") {
continue
}
str := field.Interface().(string)
str = strings.TrimSpace(str)
field.SetString(str)
}
fmt.Printf("%s%s%s%d%s%d\n", ms.A, ms.B, ms.C, ms.I, ms.D, ms.J)
}
(Playground link)
There are two caveats here:
You need a pointer to what you're going to change. If you have a value, you'll need to return the modified result.
Attempts to modify unexported fields generally will cause reflect to panic. If you plan on modifying unexported fields, make sure to do this trick inside the package.
This code is rather flexible, you can use switch statements or type switches (on the value returned by field.Interface()) if you need differing behavior depending on the type.
Edit: As for the tag behavior, you seem to already have that figured out. Once you have field and have checked that it's a string, you can just use field.Tag.Get("max") and parse it from there.
Edit2: I made a small error on the tag. Tags are part of the reflect.Type of a struct, so to get them you can use (this is a bit long-winded) msValue.Type().Field(i).Tag.Get("max")
(Playground version of the code you posted in the comments with a working Tag get).
I got beat to the punch, but since I went to the work, here's a solution:
type FormError []*string
type Listing struct {
Title string `max:"50"`
Location string `max:"100"`
Description string `max:"10000"`
ExpiryDate time.Time
RenderedDesc template.HTML
Contact string `max:"255"`
}
// Iterate over our struct, fix whitespace/formatting where possible
// and return errors encountered
func (l *Listing) Validate() error {
listingType := reflect.TypeOf(*l)
listingValue := reflect.ValueOf(l)
listingElem := listingValue.Elem()
var invalid FormError = []*string{}
// Iterate over fields
for i := 0; i < listingElem.NumField(); i++ {
fieldValue := listingElem.Field(i)
// For StructFields of type string, field = strings.TrimSpace(field)
if fieldValue.Type().Name() == "string" {
newFieldValue := strings.TrimSpace(fieldValue.Interface().(string))
fieldValue.SetString(newFieldValue)
fieldType := listingType.Field(i)
maxLengthStr := fieldType.Tag.Get("max")
if maxLengthStr != "" {
maxLength, err := strconv.Atoi(maxLengthStr)
if err != nil {
panic("Field 'max' must be an integer")
}
// check max length/convert to int/utf8.RuneCountInString
if utf8.RuneCountInString(newFieldValue) > maxLength {
// if max length exceeded, invalid = append(invalid, "errormsg")
invalidMessage := `"`+fieldType.Name+`" is too long (max allowed: `+maxLengthStr+`)`
invalid = append(invalid, &invalidMessage)
}
}
}
}
if len(invalid) > 0 {
return invalid
}
return nil
}
func (f FormError) Error() string {
var fullError string
for _, v := range f {
fullError = *v + "\n"
}
return "Errors were encountered during form processing: " + fullError
}
I see you asked about how to do the tags. Reflection has two components: a type and a value. The tag is associated with the type, so you have to get it separately than the field: listingType := reflect.TypeOf(*l). Then you can get the indexed field and the tag from that.
I don't know if it's a good way, but I use it like this.
https://play.golang.org/p/aQ_hG2BYmMD
You can send the address of a struct to this function.
Sorry for My English is not very good.
trimStruct(&someStruct)
func trimStruct(v interface{}) {
bytes, err := json.Marshal(v)
if err != nil {
fmt.Println("[trimStruct] Marshal Error :", err)
}
var mapSI map[string]interface{}
if err := json.Unmarshal(bytes, &mapSI); err != nil {
fmt.Println("[trimStruct] Unmarshal to byte Error :", err)
}
mapSI = trimMapStringInterface(mapSI).(map[string]interface{})
bytes2, err := json.Marshal(mapSI)
if err != nil {
fmt.Println("[trimStruct] Marshal Error :", err)
}
if err := json.Unmarshal(bytes2, v); err != nil {
fmt.Println("[trimStruct] Unmarshal to b Error :", err)
}
}
func trimMapStringInterface(data interface{}) interface{} {
if values, valid := data.([]interface{}); valid {
for i := range values {
data.([]interface{})[i] = trimMapStringInterface(values[i])
}
} else if values, valid := data.(map[string]interface{}); valid {
for k, v := range values {
data.(map[string]interface{})[k] = trimMapStringInterface(v)
}
} else if value, valid := data.(string); valid {
data = strings.TrimSpace(value)
}
return data
}