Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[guide] add a section for JSON serialization with Dry::Types::Constructor #283

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/4.0/guides/index.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Guides
sections:
- sql-quick-start
- sql-how-to
---

Guides are a collection of short articles explaining how to achieve common tasks
Expand Down
8 changes: 8 additions & 0 deletions source/4.0/guides/sql-how-to/index.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
chapter: SQL How To
sections:
- store-data-json-formatting
---

In this section you can learn some tricks with ROM and SQL.

51 changes: 51 additions & 0 deletions source/4.0/guides/sql-how-to/store-data-json-formatting.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
chapter: SQL How To
title: Store data as JSON Strings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the general concept of this guide, but it may beess confusing if we used an example other than JSON so Postgres users can benefit. What about using an XML snippet, or CSV?

---

Let's assume that you are using a storage system like MySQL and you want to store some data in JSON format. Let's also
assume that you don't have Hash kind like Type provided by default by this storage system (like HStore on Postgres,
in such case you can use [built-in PG types](https://rom-rb.org/4.0/learn/sql/schemas/#postgresql-types)).

You can use `Dry::Types:Constructor` in order to make your own way to process data, and give it to your ROM::Relation
in order that ROM uses this to store and read this data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also explain the concept of "read" types here?


You can use same technique if you need any data processing before it goes to your Datastore (like YAML serialization).

```ruby
JSONRead = Dry::Types::Constructor.new(Dry::Types['string'], fn: ->(v) { JSON.parse(v) })
JSONWrite = Dry::Types::Constructor.new(Dry::Types['string'], fn: ->(v) { JSON.dump(v) })
```
Those `Dry::Types::Constructor` defines the way to translate input object to String.

You can test those by doing this:
```ruby
h = {'a'=>'a', 'b'=>{ 'c'=>'c'}}
JSONWrite[h]
=> "{\"a\":\"a\",\"b\":{\"c\":\"c\"}}"

JSONRead[JSONWrite[h]]
=> {"a"=>"a", "b"=>{"c"=>"c"}}

JSONRead[JSONWrite[h]] == h
=> true
```
Tips: You can use [Oj gem](https://github.com/ohler55/oj) if you want to keep symbol keys when serializing JSON.

Then on your relations:
```ruby
module Relations
class Users < ROM::Relation[:sql]
schema(:users) do
attribute :hash_attribute, JSONWrite, read: JSONRead
attribute :array_attribute, JSONWrite, read: JSONRead
end
end
end
```
Here, we assume that you're using SQL datastore, with a `users` table that has `hash_attribute` column which is a String
and a `array_attribute` column that is also a String.

Now you'll have ruby Hash on your ROM::Struct automatically instead of Strings in JSON format.

This article as been inspired by this [forum post](https://discourse.rom-rb.org/t/methods-of-storing-arrays-in-mysql/305).