From 18e4e8cbab53a51c2a4b90ec0c519ba4a8ffa214 Mon Sep 17 00:00:00 2001 From: Holden Omans Date: Tue, 14 Aug 2018 14:47:10 -0400 Subject: [PATCH 1/3] Added basic JSON column support https://github.com/crystal-lang/crystal-mysql/issues/64 --- spec/db_spec.cr | 1 + src/mysql/types.cr | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/spec/db_spec.cr b/spec/db_spec.cr index e42885f..61f2527 100644 --- a/spec/db_spec.cr +++ b/spec/db_spec.cr @@ -49,6 +49,7 @@ DB::DriverSpecs(MySql::Any).run do sample_value Time.utc(2016, 2, 15, 10, 15, 30, nanosecond: 543_012_000), "timestamp(6)", "TIMESTAMP '2016-02-15 10:15:30.543012'" sample_value Time::Span.new(0, 10, 15, 30, nanoseconds: 543_000_000), "Time(3)", "TIME '10:15:30.543'" sample_value Time::Span.new(0, 10, 15, 30, nanoseconds: 543_012_000), "Time(6)", "TIME '10:15:30.543012'" + sample_value "{\"example\": \"json\"}", "JSON", "'{\"example\": \"json\"}'" end end diff --git a/src/mysql/types.cr b/src/mysql/types.cr index a047761..b0d0de8 100644 --- a/src/mysql/types.cr +++ b/src/mysql/types.cr @@ -60,6 +60,10 @@ abstract struct MySql::Type MySql::Type::Null end + def self.type_for(t : ::JSON::Any.class) + MySql::Type::Json + end + def self.type_for(t) raise "MySql::Type does not support #{t} values" end @@ -144,6 +148,7 @@ abstract struct MySql::Type nil end end + decl_type Timestamp, 0x07u8, ::Time do def self.write(packet, v : ::Time) MySql::Type::DateTime.write(packet, v) @@ -315,4 +320,24 @@ abstract struct MySql::Type end end decl_type Geometry, 0xffu8 + + # Parse the JSON column type + decl_type Json, 245_u8, String do + + def self.write(packet, v : String) + packet.write_string v + end + + def self.write(packet, v : ::JSON::Any) + packet.write_string v.to_json + end + + def self.read(packet) + packet.read_string.lchop("\u0013") + end + + def self.parse(str : ::String) + str + end + end end From 506ae7b1c4aa90bb8c7718de833f0b7c2aeecac1 Mon Sep 17 00:00:00 2001 From: Holden Omans Date: Tue, 14 Aug 2018 15:13:04 -0400 Subject: [PATCH 2/3] Added JSON::Any deseralization --- spec/db_spec.cr | 2 +- src/mysql.cr | 3 ++- src/mysql/types.cr | 16 +++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/spec/db_spec.cr b/spec/db_spec.cr index 61f2527..9dfb7dd 100644 --- a/spec/db_spec.cr +++ b/spec/db_spec.cr @@ -49,7 +49,7 @@ DB::DriverSpecs(MySql::Any).run do sample_value Time.utc(2016, 2, 15, 10, 15, 30, nanosecond: 543_012_000), "timestamp(6)", "TIMESTAMP '2016-02-15 10:15:30.543012'" sample_value Time::Span.new(0, 10, 15, 30, nanoseconds: 543_000_000), "Time(3)", "TIME '10:15:30.543'" sample_value Time::Span.new(0, 10, 15, 30, nanoseconds: 543_012_000), "Time(6)", "TIME '10:15:30.543012'" - sample_value "{\"example\": \"json\"}", "JSON", "'{\"example\": \"json\"}'" + sample_value JSON::Any.new({"example" => JSON::Any.new("json")}), "JSON", "'{\"example\": \"json\"}'", type_safe_value: false end end diff --git a/src/mysql.cr b/src/mysql.cr index ceaff6b..e454407 100644 --- a/src/mysql.cr +++ b/src/mysql.cr @@ -1,4 +1,5 @@ require "db" +require "json" require "./mysql/*" module MySql @@ -10,7 +11,7 @@ module MySql end end - alias Any = DB::Any | Int16 | Int8 | Time::Span + alias Any = DB::Any | Int16 | Int8 | Time::Span | JSON::Any # :nodoc: TIME_ZONE = Time::Location::UTC diff --git a/src/mysql/types.cr b/src/mysql/types.cr index b0d0de8..a5fa2d9 100644 --- a/src/mysql/types.cr +++ b/src/mysql/types.cr @@ -1,3 +1,4 @@ +require "json" # :nodoc: abstract struct MySql::Type # Column types @@ -322,22 +323,27 @@ abstract struct MySql::Type decl_type Geometry, 0xffu8 # Parse the JSON column type - decl_type Json, 245_u8, String do + decl_type Json, 245_u8, JSON::Any do def self.write(packet, v : String) - packet.write_string v + packet.write_lenenc_string v end def self.write(packet, v : ::JSON::Any) - packet.write_string v.to_json + packet.write_lenenc_string v.to_json end def self.read(packet) - packet.read_string.lchop("\u0013") + str = packet.read_lenenc_string.lchop("\u0013") + JSON.parse(str) + rescue e + nil end def self.parse(str : ::String) - str + JSON.parse(str) + rescue e + nil end end end From f74cde19bd805641235827203bd51fc89fe4b960 Mon Sep 17 00:00:00 2001 From: Holden Omans Date: Tue, 14 Aug 2018 15:18:01 -0400 Subject: [PATCH 3/3] formatting --- src/mysql/types.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mysql/types.cr b/src/mysql/types.cr index a5fa2d9..83053ab 100644 --- a/src/mysql/types.cr +++ b/src/mysql/types.cr @@ -1,4 +1,5 @@ require "json" + # :nodoc: abstract struct MySql::Type # Column types @@ -324,7 +325,6 @@ abstract struct MySql::Type # Parse the JSON column type decl_type Json, 245_u8, JSON::Any do - def self.write(packet, v : String) packet.write_lenenc_string v end