# How to serialize a struct from any type?

**URL:** <https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542>\
**Category:** Help & Support\
**Created:** [December 26, 2019, 9:59am UTC](https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542 "2019-12-26T09:59:04Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![TheOnlyArtz](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/theonlyartz/32/668_2.png) [@TheOnlyArtz](https://forum.crystal-lang.org/u/TheOnlyArtz)\
**Post date:** [December 26, 2019, 9:59am UTC](https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542/1 "2019-12-26T09:59:04Z")

</div>

let’s say I have a struct with the ability to take a Hash and assign it’s properties accordingly.  
I will provide an example with rethinkDB but really it can happen with every database library out there.

When querying the database the result of the query is of a type called `RethinkDB::QueryResult` which is really just an alias for many primitives available in Crystal.  
On the other hand I got a struct which looks like:

```auto
abstract struct Cybergarden::Items::Server
  include JSON::Serializable
  property capacity
  property processors
  property price # money per second
  property maintability    

  def analyze_mps()
      mps = 0
      processor.each {|cpu| mps+=cpu.mps}
      mps
  end

  def as_h()
      {
          capacity: @capacity,
          processors: @processors.map &.as_h,
          price: @price,
          maintability: @maintability
      } 
  end

  def from_h(payload : Hash(String, String | Array(Hash(String, String | Int32) | Int32)))
      @capacity = payload["capacity"]
      @processors = payload["processors"].map Cybergarden::Items::CpuTypes[&["type"]].new().from_h()
      @price = payload["price"]
      @maintability = payload["maintabiltiy"]
  end
end

```

so when querying the database to find the servers a user own I would like to make a new struct instance out of the available data, the only issue is, the data is `RethinkDB::QueryResult` and when calling `.as_h` on it it’s still `Hash(String, RethinkDB::QueryResult)` and I still won’t be able to do something like

```auto
server = CyberServerTierOne.new.from_h(theHashFromTheQuery)

```

since it doesn’t expect a QueryResult but more specific `Hash(String, String | Array(Hash(String, String | Int32) | Int32))`  
Someone has an idea on how I can implement such stuff? without doing the obvious of making all the property types to be `Rethink::QueryResult`  
Thank you.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [December 26, 2019, 1:09pm UTC](https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542/2 "2019-12-26T13:09:19Z")

</div>

Have you considered to simply omit the type restriction for `payload`?  
I assume the method implementation would work with both `QueryResult` and `Hash` if it’s just using duck typing?

---

<div class="post-metadata">

**Author:** ![kingsleyh](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kingsleyh/32/151_2.png) [@kingsleyh](https://forum.crystal-lang.org/u/kingsleyh)\
**Post date:** [December 26, 2019, 7:04pm UTC](https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542/3 "2019-12-26T19:04:49Z")

</div>

Hi - There are 2 things you could get back from a query:

- QueryResult
- Cursor

QueryResult is a single item whereas Cursor is many items. This is how you could handle each case:

given a container class such as User:

```auto
class User
  JSON.mapping(id: String, email: String, name: String)
end

```

and a find method:

```auto
class UserRepo
  def initialize(@connection : RethinkDB::Connection) ; end

   # the important thing here is the use of `raw`
  def find_by_id(id) : User | Nil
    result = r.table("users").get(id).run(@connection)
    result.raw.nil? ? Nil : User.from_json(result.raw.to_json)   
  end

  # the important thing here is the use of `to_a` and `map`
  def all : Array(User) | Nil
    query = r.table("users").run(@connection)
   case query
   when RethinkDB::Cursor
     query.to_a.map{ |u| User.from_json(u.raw.to_json) }
   else
     Nil  
  end
end

```

Personally I usually return a container from the db queries using the CRZ functional library:

```auto
def find_by_id(id) : Result(User, SystemError)

```

and then when I use it later:

```auto
Result.match user_repo.find_by_id(id), {
  [Ok, user] => {user: user}.to_json,
  [Err, error] => {error: handle_error(error)}.to_json
}

```

}

Using this patterns I can send back on the API the user or the error (after categorising the error and adding an appropriate message for users to see)

Hope that helps

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [December 26, 2019, 7:46pm UTC](https://forum.crystal-lang.org/t/how-to-serialize-a-struct-from-any-type/1542/4 "2019-12-26T19:46:16Z")

</div>

Can’t you create the objects without the intermediate json? It seems like some kind of mapping would be handy.
