Using (sub)struct located in other package in Datastore - go

I haven't been able to find any information related to this.. let's say you call an API and save the resulted json into a struct in package Foo, like this:
package foo
type FooData struct {
A string `json:"c"`
B int `json:"c"`
C int64 `json:"c"`
}
Then you have your own model package:
package bar
import (
"github.com/bla/bla/foo"
)
type BarData struct {
A float
Foo foo.FooData
}
Is this possible? Is there anything negative about doing it this way? The reason is the structs are over a hundred lines, so I feel it would be wasteful to duplicate it.
Also, what if I only want to index in B? Then I can just change it to:
type FooData struct {
A string `datastore:",noindex" `json:"c"`
B int `json:"c"`
C int64 `datastore:",noindex" `json:"c"`
}
?
Edit: Just to make it clear, my intention is to save the BarData struct in Datastore

The Go Datastore package has some documentation relating to this - https://cloud.google.com/appengine/docs/standard/go/datastore/reference#hdr-Structured_Properties
"Structured Properties
If the struct pointed to contains other structs, then the nested or embedded structs are flattened. For example, given these definitions:
type Inner1 struct {
W int32
X string
}
type Inner2 struct {
Y float64
}
type Inner3 struct {
Z bool
}
type Outer struct {
A int16
I []Inner1
J Inner2
Inner3
}
then an Outer's properties would be equivalent to those of:
type OuterEquivalent struct {
A int16
IDotW []int32 `datastore:"I.W"`
IDotX []string `datastore:"I.X"`
JDotY float64 `datastore:"J.Y"`
Z bool
}
If Outer's embedded Inner3 field was tagged as datastore:"Foo" then the equivalent field would instead be: FooDotZ bool datastore:"Foo.Z".
If an outer struct is tagged "noindex" then all of its implicit flattened fields are effectively "noindex"."
So there shouldn't be any issues with you storing nested structs, just be aware that they will be flattened in datastore. It also mentions the no indexing, saying any field inherits a "noindex" from its parent struct. I don't see why your "noindex" tagging of the inner fields wouldn't work.

Related

Iterating through struct values from embedded struct

I have the following struct
type ChartOpts struct {
Name mypackage.Sometype
Repo mypackage.Anothertype
mypackage.SomeSpecialStructType
}
Then I create the following receiver for mypackage.SomeSpecialStructType as follows:
func (c SomeSpecialStructType) BindFlags() {
fields := reflect.TypeOf(c)
values := reflect.ValueOf(c)
num := fields.NumField()
for i := 0; i < num; i++ {
switch v := values.Field(i).Interface().(type) {
case OrmosFlag:
fmt.Printf("%#T\n", v)
//v.BindPersistentFlag(cobCom)
log.Println("HERE")
default:
log.Println("ERROR")
}
}
}
As (perhaps) becomes evident from the code, I want to leverage embedding so that the embedded type (that I was expecting to have access to the outer struct fields) can perform some operations on them.
The code does not works given that num is 0 here (makes since given that SomeSpecialStructType has zero fields, just a receiver)
I know I can just copy-paste the specific receiver on each and every ChartOpts struct I create (there will be plenty of them coming) but just trying to be DRY here.
Embedding is not inheritance. When you embed a struct type into another, you are essentially composing a new type, not extending the embedded type.
type Inner struct {
X int
}
type Outer struct {
Inner
}
Above, Outer is a struct containing Inner. When you declare a variable of type Outer, you can access the fields of the Inner struct by:
x:=Outer{}
x.Inner.X=1
x.X=1
So in fact this is no different from:
type Outer struct {
Inner Inner
}
with the difference that the field name is omitted. So you can shortcut the field name when you access the variables.
in short: there is no way a method of an inner struct can access the embedding struct. If you need that, have a constructor method for the outer struct that sets a pointer in the inner struct. Also, pass around a pointer to the returned struct. If you copy the struct, the pointer needs to be adjusted.
type Outer struct {
Inner
}
type Inner struct {
X int
o *Outer
}
func NewOuter() *Outer {
ret:=&Outer{}
ret.outer=ret
return ret
}

Wrapped structs referencing

I am little consfused about value type struct wrapped by pointer type struct.
Example:
package main
import (
"fmt"
)
type A struct {
id int
B
}
func (a *A) setId(val int) {
a.id = val
}
type B struct {
name string
}
func (b B) setNameViaValue(val string) {
b.name = val
}
func (b *B) setNameViaPointer(val string) {
b.name = val
}
func main() {
a := new(A)
a.setId(1)
a.setNameViaValue("valuename")
fmt.Println(a)
a.setNameViaPointer("pointername")
fmt.Println(a)
}
I would expect that referencing through pointer type A struct(which addresses concrete memory) that wraps B value type struct will set inner value no matter what kind of refence to B is used (B/*B). This is also related to type definition. Can anyone also explain what is different when I define it like this? Is there any usecase scenario?
type A struct {
id int
*B
}
Why doesn't setNameViaValue end up setting the name
If you declare a method with a value (non-pointer) receiver, then that method cannot "modify" the receiver cause it will actually receive a copy.
That's why the "name" is not set as you expected with the setNameViaValue method.
If you want to be able to set the name of B in that way, only setNameViaPointer is an option.
You can read more about the differences between method and value receivers here:
https://tour.golang.org/methods/8
Why can you actually invoke the inner struct methods on the outer struct
That's because you "embedded" the inner struct in the outer one.
When you include a struct type name without giving it a field name, then all of the "inner" struct methods and fields are "promoted" to the outer one.
That means you can call a.setNameViaValue and it will be equivalent to doing a.B.setNameViaValue.
Is there any difference if I embedded as a pointer
If you define A this way:
type A struct {
id int
*B
}
Then:
The "setNameViaValue" will still not work (that's only related to the method being defined over a value instead of a pointer receiver, it has nothing to do with how A references B).
You will need to initialize B explicitly when creating an A object, otherwise *B will end up being nil. (if you reference it as a value, it will be initialized as an empty B)
You can change what *B points to later on (if it was a value, then it will always reference the same "value")

Go struct inside of same struct type?

I want a relationship between structs, example:
type A struct {
X string
Y int
*A
}
It's possible this?
And if it's possible, what is the right way to marshal and unmarshal to JSON this?
When i marshal this struct to JSON the field A is lost.
The code is correct, but the anonimous filed A is lost because have the same names as the struct.
Solution:
type A struct {
X string
Y int
Z *A
}

Construct struct literal with embedded structs

How do I construct a struct literal with embedded struct?
Go:
package main
import "fmt"
type Ping struct {
Content struct {
name string
}
}
func main() {
p := Ping{Content{"hello"}}
fmt.Println(p)
}
http://play.golang.org/p/UH4YO6CAFv
This works if I had written the structs this way:
Go:
type Ping struct {
Content
}
type Content struct {
name string
}
http://play.golang.org/p/ERGsO4CMEN
How do I do it with the embedded struct version in the first code version?
You can't, and you really shouldn't either, but if you insist anyway you can use something like:
p := Ping{struct{ name string }{"don't do it"}}
or
p := Ping{}
p.Content.name = "hello"
playground
This doesn't seem to be supported, looking at the spec for Struct type
A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct.
An embedded type must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type.
That means T must be defined somewhere else.

encoding/xml handle unmapped elements

From http://golang.org/pkg/encoding/xml/#Unmarshal
If the XML element contains a sub-element that hasn't matched any of the above rules and the struct has a field with tag ",any",
unmarshal maps the sub-element to that struct field.
I'm having trouble getting the remainder of an XML envelope into my struct (to show that I have an incomplete mapping)
http://play.golang.org/p/mnFqAcguJQ
I know you can use exactly this method with bson.M from the mgo packages using ,inline - but it looks like map[string]interface{} isn't the answer here.
EDIT:
After some additional playing, I've found what I believe to be some additional unexpected behavior.
Switching to []string as a type starts to accept input, but no key/value pairs: http://play.golang.org/p/wCAJeeQa4m
I also planned on adapting encode/xml in order to parse html. I do not see in the documentation that if an element exists more than once, it will save the last instance of it, rather than erroring out: http://play.golang.org/p/0MY__R-Xi3
Here: http://play.golang.org/p/iY8YlxYym0
Since c is something concrete, it shouldn't use ",any", hence it should have a struct definition. C itself contains a list of arbitrary tags, hence it should contain an []Tag xml:'",any"'... now to capture the Tag itself, you need xml.Name to get the tag name and something with ",innerxml".
Finally the result is this:
const xmlString = `<foo><a>1</a><b>2</b><c><c1>3</c1><c2>4</c2></c></foo>`
type Foo struct {
A int `xml:"a"`
B int `xml:"b"`
C Extra `xml:"c"`
}
type Extra struct {
Items []Tag `xml:",any"`
}
type Tag struct {
XMLName xml.Name
Content string `xml:",innerxml"`
}
Or the shorter version:
type Foo struct {
A int `xml:"a"`
B int `xml:"b"`
C struct {
Items []struct {
XMLName xml.Name
Content string `xml:",innerxml"`
} `xml:",any"`
} `xml:"c"`
}
For HTML there is go.net/html. Using xml parser for html will be complicated.

Resources