Go Google Datastore nulls - google-app-engine

I have datastore objects that look like:
created (timestamp)
guid (string)
details (string)
start (string)
end (string
Often, the details, start or end are NULL.
In Go, I am trying to do this:
type Edge struct {
created time.Time
details string `datastore: "details,omitempty"`
guid string `datastore: "guid,omitempty"`
start string `datastore: "start,omitempty"`
end string `datastore: "end,omitempty"`
}
for t := client.Run(ctx, q); ; {
var x Edge
key, err := t.Next(&x)
if err == iterator.Done {
break
}
if err != nil {
fmt.Printf("error caught: %v\n\n", err)
}
fmt.Printf("Key=%v\nEdge=%#v\n\n", key, x)
}
The output error is always something like:
error caught: datastore: cannot load field "guid" into a "main.Edge": no such struct field
Key=/edges,4503602429165568
Edge=main.Edge{created:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, details:"", guid:"", start:"", end:""}
When I search for that key in the datastore console, I see that guid is a valid string.
GetAll gave me almost the same problem.
My questions are:
I'm new to Go. Is there anything specific I'm doing wrong here? (Any typos would be Stackoverflow specific. Because I changed a few things here)
Is there anyway to see what datastore is sending back to be before putting it in a struct?
Some of the values will sometimes be null. Like start, end and details. Is that valid for a string in a struct?
Thank you.

Two problems that stand out immediately:
Struct fields must be exported, so start their names with capital letter.
Your tag values are "invalid" (they don't follow the conventions). You must not leave a space between the key datastore: and the value "details,omitempty".
So use the following struct definition:
type Edge struct {
Created time.Time `datastore:"created"`
Details string `datastore:"details,omitempty"`
Guid string `datastore:"guid,omitempty"`
Start string `datastore:"start,omitempty"`
End string `datastore:"end,omitempty"`
}
See similar questions for the above-mentioned 2 problems:
golang mgo getting empty objects
Why struct fields are showing empty?
If a property in the Datastore is null, that's not a problem for a Go struct. In such case the corresponding struct field will be the zero-value of its type, which is the empty string "" in case of the string type. If you want to be able to differentiate between the Datastore null, Datastore "missing property" and the actual empty string "", you may change the field type to be a pointer (like *string), in which case the missing property and the null value will correspond to a nil pointer value, and an existing but empty string value will be a non-nil pointer to an empty string value.

Related

Iterating over a struct in Golang and print the value if set

First of all, apologies if this question is confused since I'm just trying out Go and have no idea what I'm doing. I have a struct composed of a variety of attributes of different types, example:
type foo struct {
bar string
baz int
bez []string
(...)
Initially I wanted to iterate over all these attributes and print the value if it existed, but I realized you cannot range over a struct the same way you could, say, a list or map. So I've tried out a few tricks with no luck (like trying to iterate over a separate list of attributes), and I think it's better I just ask for help because I'm probably in over my head here.
The idea is that if I create a new instance of this struct, I'd like to be able to then only print values that are set:
obj := foo{"bar_string", 1}
Given that the string slice bez is not set in obj, I'd like to be able to do something like (pseudo):
for i in obj:
print i
Giving:
"bar_string"
1
Ideally, not printing [] which I guess is the zero value for bez.
Am I approaching this whole thing wrong? The reason I'm not using a map is because I'd like the attributes to be different types, and I'd like future differing objects I'm working in to be organized into structs for clarity.
Go doesn't have builtin struct iteration. The for ... range statement is applicable only to:
all entries of an array, slice, string or map, or values received on a channel
or defined types with one of those underlying types (e.g. type Foo []int)
If you want to iterate over a struct known at compile time, you might be better off just accessing fields one by one.
If you want to must iterate over a struct not known at compile time, you can use the reflect package (not recommended):
type Foo struct {
Bar string
Baz int
Quux []int
}
// x := Foo{"bar", 1, nil}
func printAny(x interface{}) {
v := reflect.ValueOf(x)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
fmt.Println(field)
// bar
// 1
}
}
}
...but it's slower and there are some gotchas, for example:
field.Interface() panics if the field is unexported
in the if clause you can't just use the comparison operator == because operands might be not comparable:
you have to make sure that the zero value for field types is what you expect
If your goal is to just print the struct, you can simply implement the Stringer interface, where you can do type-safe checks the way you want without reflect:
type Foo struct {
Bar string
Baz int
Quux []int
}
func (f Foo) String() string {
s := []string{f.Bar, strconv.Itoa(f.Baz)}
if f.Quux != nil {
s = append(s, fmt.Sprintf("%v", f.Quux))
}
return strings.Join(s, "\n")
}
func main() {
fmt.Println(Foo{"bar", 1, nil})
// bar
// 1
}
A Go playground

How to convert an array of Strings to a list

I have an array of Strings and I want to use that as a list.
I followed this example but I didn't get for an array. Link
My current code is given below:
struct ListOfPeripherals: Identifiable {
var id = UUID()
var peripheralName: String
}
struct RestaurantRow: View {
var peripheralFromBLE: ListOfPeripherals
var body: some View {
// List to be implemented here
}
func getListOfAlphabets() -> [String] {
let listOfAlphabets = [A,B,C,D,E]
return listOfAlphabets
}
}
You dont have to convert your Array of String objects to make the List work. You should describe your error pasting it along with your code to get helped faster. So, this is my assumption of your concept of error.
The Array type is fine, but however, his Elements, in this case the strings, need to be identified. This means you have to conform your String to the Identifiable protocol, and providing an id property which must be unique (a simple UUID object will do the trick).
In your code, the function getListOfAlphabets returns an array of Strings which cannot be used. If you were to use a [ListOfPeripherals] array that would work because it conforms to the protocol. I think you got a bit of confusion and you are basically returning an array of wrong type.

Duplicate go slices key values

type Developer struct {
Name string `json:"name"`
Skills []interface{} `json:"skills"`
}
This is my struct
var developers []Developer
var devData Developer
if searchResult.TotalHits() > 0 {
for _, hit := range searchResult.Hits.Hits {
err := json.Unmarshal(hit.Source, &devData)
if err != nil {
fmt.Println("error")
}
fmt.Println(devData.Skills) // utp here data are correct
developers = append(developers, devData)
}
//after loop data skills value are not correct
}
but when actual data is made the skills are same throught all arrays
expected : ['name' : 'John Doe','skills': ["php","go"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
But output : ['name' : 'John Doe','skills': ["java","haskel"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
You're reusing the same devData variable, and therefore its allocated memory, in each iteration of the for loop. This means that when you call json.Unmarshal and pass it the pointer to devData you're overwriting what has been written to that memory during the previous iteration.
Instead of declaring the devData variable above the if statment, you should declare it inside the for loop to get a new segment of memory allocated for each of your iteration variables.
Note that if the type of the variable is pointer-less then you could use your original approach since Go is pass-by-value and each time you pass a variable to a function, including append, a shallow copy of that variable's value gets created.
However, since slices in go do hold a pointer to the first element of the slice the Developer type, because of its Skills field, does not qualify.
And that is why you're seeing the Name field getting copied correctly, but the contents of the Skills field getting overwritten.

C adds a reference to array, not a value

I am new to C and have never done anything with a non-OOP language.
I have an array of structs. It is global to the class and I parse a json with the results ending up in above mentioned array. I create an object (?) based on the struct that offers one property for every entry. After adding the items, the array turned out to have the same value on all of the positions.
I did remember C being tricky when it comes to values and pointers/references so I have made a little test to see whether the array actually only took the reference:
typedef struct {
char* name;
} ww_item ;
char nameW[40];
// iterating through json {
// strcpy(nameW, data);
ww_item w = { nameW };
ww_items [ position ] = w;
strcpy(nameW, "d"); //replaces the "Hello" with "d" in all previous ww_items
Obviously it does, which explains why my array ends up being a repetition of the last element that has been added to it instead of listing all the different strings I have added to it.
I am unable to find any short information on this and unfortunately my deadline is too close to read through a whole C book now. I'm pretty sure that my assumptions so far are true but now I do not know what to search for/ to look for in order to solve this problem.
I'm okay with an ugly solution or workaround but at the moment I am just stuck with this.
Thank you for your help.
Change the name member from a pointer to an array.
typedef struct {
char name[40];
} ww_item ;
and then use strcpy()
strcpy(ww_items[position].name, w);
There's no need for the w variable.

How to copy a pointer to an array in Swift?

I'm basically trying to wrap a C structure within a Swift class.
The Swift class has an instance property of type of the C structure.
The C structure contains several properties which are of type const char *.
In order to assign values to the structure, I wrote getters and setters for each property:
public class MyClass: NSObject {
private var configuration = c_structure_config()
}
// Function of MyClass
// f.ex. on "registrationUri:"
private(set) public var registrationUri: String {
get {
return String(cString: configuration.reg_uri)
}
set {
if (configuration.reg_uri != nil) {
configuration.reg_uri.deallocate()
}
let maxLength = newValue.count + 1 // +1 for NULL
var buffer: [CChar] = [CChar](UnsafeMutableBufferPointer<Int8>.allocate(capacity: maxLength))
guard newValue.getCString(&buffer, maxLength: maxLength, encoding: .utf8) == true else {
fatalError("Could not allocate memory for Account Config reg uri")
}
// "configuration" is the instance property (see above)
// reg_uri is of type char const *
configuration.reg_uri = UnsafePointer<Int8>(buffer)
}
}
However, this approach leads to weird crashes and error reports complaining about pointers overlapping range (Fatal error: UnsafeMutablePointer.initialize overlapping range).
I know that I'm deallocating and allocating memory whenever the string is set and that that's probably not very efficient. I haven't found a better solution so far though.
What's wrong here (or is this right, I made a wrong assumption and I gotta search somewhere else)?
There are a couple of problems with your solution.
First, it is ill-advised to use String.count to count to get the size of the underlying C buffer. The reason is that String.count returns the number of actual characters of your string, and not the number of bytes used to represent it. Not all characters fit the 256 bits of Int8 (a.k.a. CChar). Hence, your code will probably crash if you attempt setting your property with non-ascii characters. It is better to use the String.utf8CString property, which returns a contiguous array of CChar.
Second, since your buffer is allocated within the setter, it will be deallocated when your setter returns (Swift arrays are instances of value types, who's lifetime is bound by the stack). That means the pointer corresponding to buffer's base is actually invalidated when your setter returns. I suspect this is the reason why the error you reported occurs at runtime.
Finally, please do not test for true in guards and if statements.
Here is a corrected version:
var registrationUri: String {
get {
return String(cString: reg_uri)
}
set {
if (reg_uri != nil) {
reg_uri.deallocate()
}
newValue.withCString { cString in
// No need to add 1, newValue.utf8CString already has the correct buffer capacity.
let capacity = newValue.utf8CString.count
let buffer: UnsafeMutablePointer<Int8> = .allocate(capacity: capacity)
buffer.assign(from: cString, count: capacity)
reg_uri = UnsafePointer(buffer)
}
}
}
// ...
myInstance.registrationUri = "こんいちは"
print(myInstance.registrationUri)
// Prints "こんいちは"

Resources