FAQ
I'm using golang on appengine to store data using datastore.
My code to read back a user is


func ReadUser(c appengine.Context, query *datastore.Query) ([]User, error) {
     q := query.Run(c)
     var results []User
     var result User
     for {
         _, err := q.Next(&result)
         if err == datastore.Done {
             break
         }
         if err != nil {
             return nil, err
         }
         results = append(results, result)
     }
     return results, nil
}



Rather than repeat all that for every different type, I want to do
something like


func Read(c appengine.Context, query *datastore.Query, result interface{},
results []interface{}) ([]interface, error) {
     q := query.Run(c)
     for {
         _, err := q.Next(&result)
         if err == datastore.Done {
             break
         }
         if err != nil {
             return nil, err
         }
         results = append(results, result)
     }
     return results, nil
}



but I can't figure out how to give the q.Next a concrete type so that
datastore knows
how to read in the data.

I've tried looking at reflection and type switches, but end up having to
repeat the code
multiple times.

Please could someone point me in the correct direction.

Many thanks

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Tamás Gulácsi at Sep 9, 2014 at 3:28 pm
    But you are: if you give User{} to your Read as result, then it does as you wish.
    (Or maybe an &User{} and remove that & in Scan).

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Adrian Adshead at Sep 9, 2014 at 4:27 pm
    The problem I am having is that the datastore code takes the type of the
    parameter 'result' (interface{}) and then doesn't know how to handle the
    call
    to q.Next. If it has a value to use of the correct type (User), then it
    knows
    which fields to pull back.

    More generally than usage with datastore, is it possible to create a
    variable
    inside the function with the type passed into the interface parameter.




    On Tuesday, September 9, 2014 10:28:08 AM UTC-5, Tamás Gulácsi wrote:

    But you are: if you give User{} to your Read as result, then it does as
    you wish.
    (Or maybe an &User{} and remove that & in Scan).
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Roger peppe at Sep 9, 2014 at 5:28 pm

    On 9 September 2014 11:35, wrote:
    I'm using golang on appengine to store data using datastore.
    My code to read back a user is


    func ReadUser(c appengine.Context, query *datastore.Query) ([]User, error) {
    q := query.Run(c)
    var results []User
    var result User
    for {
    _, err := q.Next(&result)
    if err == datastore.Done {
    break
    }
    if err != nil {
    return nil, err
    }
    results = append(results, result)
    }
    return results, nil
    }



    Rather than repeat all that for every different type, I want to do something
    like


    func Read(c appengine.Context, query *datastore.Query, result interface{},
    results []interface{}) ([]interface, error) {
    q := query.Run(c)
    for {
    _, err := q.Next(&result)
    if err == datastore.Done {
    break
    }
    if err != nil {
    return nil, err
    }
    results = append(results, result)
    }
    return results, nil
    }



    but I can't figure out how to give the q.Next a concrete type so that
    datastore knows
    how to read in the data.
    You could do something like this, passing in a function that
    is used to create the new receiving values:

    func Read(c appengine.Context, query *datastore.Query, newResult
    func() interface{}) ([]interface{}, error) {
         q := query.Run(c)
         for {
             result := newResult()
             _, err := q.Next(result)
             if err == datastore.Done {
                 break
             }
             if err != nil {
                 return nil, err
             }
             results = append(results, result)
         }
         return results, nil
    }


    Alternatively, you could use reflection, which will probably
    be less efficient, but the client code may look a little prettier.

    // Read appends all the results of the given query to the
    // results value (which must be a slice) and returns the
    // resulting slice.
    func Read(c appengine.Context, query *datastore.Query, results
    interface{}) (interface{}, error) {
         resultsv := reflect.ValueOf(results)
         q := query.Run(c)

         elem := reflect.New(resultsv.Type().Elem())
         for i := resultsv.Len(); ; i++ {
             _, err := q.Next(elem.Interface())
             if err == datastore.Done {
                 break
             }
             if err != nil {
                 return nil, err
             }
             resultsv = reflect.Append(resultsv, elem.Elem())
         }
         return resultsv.Interface(), nil
    }

    Beware, I haven't tested or even compiled any of the above code.
    Another possibility might be to send the results on a channel
    or make a callback - that way you could lose the dynamic type
    coercion in client code, though at some efficiency cost.

       cheers,
        rog.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tahir at Sep 9, 2014 at 10:03 pm
    Are you planning to have a fixed number of types (stored in the datastore)
    that you Next method can iterate over ?

    if yes, instead of using User as in your ReadUser, I would define something
    such as :

    type GlobalItem struct{
        Usertype *User
        Objecttype *Object
        Whatevertype *Whatever
    }

    to Read over.

    Maybe you can even use a struct tag or define a field of type string to
    make sure of the type of each GlobalItem you create.

    But if you extend the number of types in your datastore, this solution
    won't work anymore.
    On Tuesday, September 9, 2014 11:35:52 AM UTC+1, adr...@adshead.net wrote:

    I'm using golang on appengine to store data using datastore.
    My code to read back a user is


    func ReadUser(c appengine.Context, query *datastore.Query) ([]User, error)
    {
    q := query.Run(c)
    var results []User
    var result User
    for {
    _, err := q.Next(&result)
    if err == datastore.Done {
    break
    }
    if err != nil {
    return nil, err
    }
    results = append(results, result)
    }
    return results, nil
    }



    Rather than repeat all that for every different type, I want to do
    something like


    func Read(c appengine.Context, query *datastore.Query, result interface{},
    results []interface{}) ([]interface, error) {
    q := query.Run(c)
    for {
    _, err := q.Next(&result)
    if err == datastore.Done {
    break
    }
    if err != nil {
    return nil, err
    }
    results = append(results, result)
    }
    return results, nil
    }



    but I can't figure out how to give the q.Next a concrete type so that
    datastore knows
    how to read in the data.

    I've tried looking at reflection and type switches, but end up having to
    repeat the code
    multiple times.

    Please could someone point me in the correct direction.

    Many thanks
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedSep 9, '14 at 12:28p
activeSep 9, '14 at 10:03p
posts5
users5
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase