Browse Source

Merge pull request #94 from seriyps/jsonb

support for postgresql json/jsonb type
David N. Welton 9 years ago
parent
commit
4c88076498
6 changed files with 37 additions and 4 deletions
  1. 2 2
      .travis.yml
  2. 2 0
      README.md
  3. 8 0
      src/epgsql_binary.erl
  4. 8 0
      src/epgsql_types.erl
  5. 14 1
      test/epgsql_tests.erl
  6. 3 1
      test_data/test_schema.sql

+ 2 - 2
.travis.yml

@@ -6,9 +6,9 @@ otp_release:
   - 18.2
 before_script:
   - sudo apt-get update -qq
-  - sudo apt-get install postgresql-9.3-postgis-2.1 postgresql-contrib-9.3
+  - sudo apt-get install postgresql-9.4-postgis-2.1 postgresql-contrib-9.4
 addons:
-  postgresql: "9.3"
+  postgresql: "9.4"
 script:
   - sudo chmod 777 /var/run/postgresql/
   - ./setup_test_db.sh

+ 2 - 0
README.md

@@ -400,6 +400,8 @@ PG type       | Representation
   point       |  `{10.2, 100.12}`
   int4range   | `[1,5)`
   hstore      | `{list({binary(), binary() | null})}`
+  json/jsonb  | `<<"{ \"key\": [ 1, 1.0, true, \"string\" ] }">>`
+
 
   `timestamp` and `timestamptz` parameters can take `erlang:now()` format: `{MegaSeconds, Seconds, MicroSeconds}`
 

+ 8 - 0
src/epgsql_binary.erl

@@ -22,6 +22,7 @@
 -define(IP6_SIZE, 16).
 -define(MAX_IP_MASK, 32).
 -define(MAX_IP6_MASK, 128).
+-define(JSONB_VERSION_1, 1).
 
 new_codec([]) -> #codec{}.
 
@@ -69,6 +70,8 @@ encode(interval = Type, B, _)               -> ?datetime:encode(Type, B);
 encode(bytea, B, _) when is_binary(B)       -> <<(byte_size(B)):?int32, B/binary>>;
 encode(text, B, _) when is_binary(B)        -> <<(byte_size(B)):?int32, B/binary>>;
 encode(varchar, B, _) when is_binary(B)     -> <<(byte_size(B)):?int32, B/binary>>;
+encode(json, B, _) when is_binary(B)        -> <<(byte_size(B)):?int32, B/binary>>;
+encode(jsonb, B, _) when is_binary(B)       -> <<(byte_size(B) + 1):?int32, ?JSONB_VERSION_1:8, B/binary>>;
 encode(uuid, B, _) when is_binary(B)        -> encode_uuid(B);
 encode({array, char}, L, Codec) when is_list(L) -> encode_array(bpchar, type2oid(bpchar, Codec), L, Codec);
 encode({array, Type}, L, Codec) when is_list(L) -> encode_array(Type, type2oid(Type, Codec), L, Codec);
@@ -90,6 +93,7 @@ decode(int8, <<N:1/big-signed-unit:64>>, _)    -> N;
 decode(float4, <<N:1/big-float-unit:32>>, _)   -> N;
 decode(float8, <<N:1/big-float-unit:64>>, _)   -> N;
 decode(record, <<_:?int32, Rest/binary>>, Codec) -> list_to_tuple(decode_record(Rest, [], Codec));
+decode(jsonb, <<?JSONB_VERSION_1:8, Value/binary>>, _) -> Value;
 decode(time = Type, B, _)                      -> ?datetime:decode(Type, B);
 decode(timetz = Type, B, _)                    -> ?datetime:decode(Type, B);
 decode(date = Type, B, _)                      -> ?datetime:decode(Type, B);
@@ -282,6 +286,8 @@ supports(cidr)        -> true;
 supports(inet)        -> true;
 supports(geometry)    -> true;
 supports(point)       -> true;
+supports(json)        -> true;
+supports(jsonb)        -> true;
 supports({array, bool})   -> true;
 supports({array, int2})   -> true;
 supports({array, int4})   -> true;
@@ -302,4 +308,6 @@ supports({array, uuid})   -> true;
 supports({array, cidr})   -> true;
 supports({array, inet})   -> true;
 supports({array, record}) -> true;
+supports({array, json})   -> true;
+supports({array, jsonb})   -> true;
 supports(_Type)       -> false.

+ 8 - 0
src/epgsql_types.erl

@@ -21,7 +21,9 @@ oid2type(71)    -> pg_type_reltype;
 oid2type(75)    -> pg_attribute_reltype;
 oid2type(81)    -> pg_proc_reltype;
 oid2type(83)    -> pg_class_reltype;
+oid2type(114)   -> json;
 oid2type(142)   -> xml;
+oid2type(199)   -> {array, json};
 oid2type(600)   -> point;
 oid2type(601)   -> lseg;
 oid2type(602)   -> path;
@@ -96,6 +98,8 @@ oid2type(2776)  -> anynonarray;
 oid2type(2950)  -> uuid;
 oid2type(2951)  -> {array, uuid};
 oid2type(3500)  -> anyenum;
+oid2type(3802)  -> jsonb;
+oid2type(3807)  -> {array, jsonb};
 oid2type(3904)  -> int4range;
 oid2type(Oid)   -> {unknown_oid, Oid}.
 
@@ -118,7 +122,9 @@ type2oid(pg_type_reltype)       -> 71;
 type2oid(pg_attribute_reltype)  -> 75;
 type2oid(pg_proc_reltype)       -> 81;
 type2oid(pg_class_reltype)      -> 83;
+type2oid(json)                  -> 114;
 type2oid(xml)                   -> 142;
+type2oid({array, json})         -> 199;
 type2oid(point)                 -> 600;
 type2oid(lseg)                  -> 601;
 type2oid(path)                  -> 602;
@@ -193,5 +199,7 @@ type2oid(anynonarray)           -> 2776;
 type2oid(uuid)                  -> 2950;
 type2oid({array, uuid})         -> 2951;
 type2oid(anyenum)               -> 3500;
+type2oid(jsonb)                 -> 3802;
+type2oid({array, jsonb})        -> 3807;
 type2oid(int4range)             -> 3904;
 type2oid(Type)                  -> {unknown_type, Type}.

+ 14 - 1
test/epgsql_tests.erl

@@ -576,6 +576,17 @@ date_time_type_test(Module) ->
                          [{{0,0,0.0},0,-178000000 * 12}, {{0,0,0.0},0,178000000 * 12}])
       end).
 
+json_type_test(Module) ->
+    with_connection(
+      Module,
+      fun(C) ->
+              check_type(Module, json, "'{}'", <<"{}">>,
+                         [<<"{}">>, <<"[]">>, <<"1">>, <<"1.0">>, <<"true">>, <<"\"string\"">>, <<"{\"key\": []}">>]),
+              check_type(Module, jsonb, "'{}'", <<"{}">>,
+                         [<<"{}">>, <<"[]">>, <<"1">>, <<"1.0">>, <<"true">>, <<"\"string\"">>, <<"{\"key\": []}">>])
+      end
+    ).
+
 misc_type_test(Module) ->
     check_type(Module, bool, "true", true, [true, false]),
     check_type(Module, bytea, "E'\001\002'", <<1,2>>, [<<>>, <<0,128,255>>]).
@@ -642,7 +653,9 @@ array_type_test(Module) ->
           Select(hstore, [{[{null, null}, {a, 1}, {1, 2}, {b, undefined}]}]),
           Select(hstore, [[{[{null, null}, {a, 1}, {1, 2}, {b, undefined}]}, {[]}], [{[{a, 1}]}, {[{null, 2}]}]]),
           Select(cidr, [{{127,0,0,1}, 32}, {{0,0,0,0,0,0,0,1}, 128}]),
-          Select(inet, [{127,0,0,1}, {0,0,0,0,0,0,0,1}])
+          Select(inet, [{127,0,0,1}, {0,0,0,0,0,0,0,1}]),
+          Select(json, [<<"{}">>, <<"[]">>, <<"1">>, <<"1.0">>, <<"true">>, <<"\"string\"">>, <<"{\"key\": []}">>]),
+          Select(jsonb, [<<"{}">>, <<"[]">>, <<"1">>, <<"1.0">>, <<"true">>, <<"\"string\"">>, <<"{\"key\": []}">>])
       end).
 
 custom_types_test(Module) ->

+ 3 - 1
test_data/test_schema.sql

@@ -63,7 +63,9 @@ CREATE TABLE test_table2 (
   c_geometry geometry,
   c_cidr cidr,
   c_inet inet,
-  c_int4range int4range);
+  c_int4range int4range,
+  c_json json,
+  c_jsonb jsonb);
 
 CREATE LANGUAGE plpgsql;