Skip to content

Instantly share code, notes, and snippets.

@simianhacker
Last active May 13, 2019 17:40
Show Gist options
  • Save simianhacker/5323651 to your computer and use it in GitHub Desktop.
Save simianhacker/5323651 to your computer and use it in GitHub Desktop.
Here is a set of functions for working with a PostgreSQL+JSON+PLV8 database.
-- Function: json_path(json, text)
-- DROP FUNCTION json_path(json, text);
CREATE OR REPLACE FUNCTION json_path(data json, path text)
RETURNS text AS
$BODY$
/* JSONPath 0.8.0 - XPath for JSON
*
* Copyright (c) 2007 Stefan Goessner (goessner.net)
* Licensed under the MIT (MIT-LICENSE.txt) licence.
*/
function jsonPath(obj, expr, arg) {
var P = {
resultType: arg && arg.resultType || "VALUE",
result: [],
normalize: function(expr) {
var subx = [];
return expr.replace(/[\['](\??\(.*?\))[\]']/g, function($0,$1){return "[#"+(subx.push($1)-1)+"]";})
.replace(/'?\.'?|\['?/g, ";")
.replace(/;;;|;;/g, ";..;")
.replace(/;$|'?\]|'$/g, "")
.replace(/#([0-9]+)/g, function($0,$1){return subx[$1];});
},
asPath: function(path) {
var x = path.split(";"), p = "$";
for (var i=1,n=x.length; i<n; i++)
p += /^[0-9*]+$/.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']");
return p;
},
store: function(p, v) {
if (p) P.result[P.result.length] = P.resultType == "PATH" ? P.asPath(p) : v;
return !!p;
},
trace: function(expr, val, path) {
if (expr) {
var x = expr.split(";"), loc = x.shift();
x = x.join(";");
if (val && val.hasOwnProperty(loc))
P.trace(x, val[loc], path + ";" + loc);
else if (loc === "*")
P.walk(loc, x, val, path, function(m,l,x,v,p) { P.trace(m+";"+x,v,p); });
else if (loc === "..") {
P.trace(x, val, path);
P.walk(loc, x, val, path, function(m,l,x,v,p) { typeof v[m] === "object" && P.trace("..;"+x,v[m],p+";"+m); });
}
else if (/,/.test(loc)) { // [name1,name2,...]
for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)
P.trace(s[i]+";"+x, val, path);
}
else if (/^\(.*?\)$/.test(loc)) // [(expr)]
P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path);
else if (/^\?\(.*?\)$/.test(loc)) // [?(expr)]
P.walk(loc, x, val, path, function(m,l,x,v,p) { if (P.eval(l.replace(/^\?\((.*?)\)$/,"$1"),v[m],m)) P.trace(m+";"+x,v,p); });
else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] phyton slice syntax
P.slice(loc, x, val, path);
}
else
P.store(path, val);
},
walk: function(loc, expr, val, path, f) {
if (val instanceof Array) {
for (var i=0,n=val.length; i<n; i++)
if (i in val)
f(i,loc,expr,val,path);
}
else if (typeof val === "object") {
for (var m in val)
if (val.hasOwnProperty(m))
f(m,loc,expr,val,path);
}
},
slice: function(loc, expr, val, path) {
if (val instanceof Array) {
var len=val.length, start=0, end=len, step=1;
loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);});
start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end);
for (var i=start; i<end; i+=step)
P.trace(i+";"+expr, val, path);
}
},
eval: function(x, _v, _vname) {
try { return $ && _v && eval(x.replace(/@/g, "_v")); }
catch(e) { throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/@/g, "_v").replace(/\^/g, "_a")); }
}
};
var $ = obj;
if (expr && obj && (P.resultType == "VALUE" || P.resultType == "PATH")) {
P.trace(P.normalize(expr).replace(/^\$;/,""), obj, "$");
return P.result.length ? P.result : false;
}
}
var obj = JSON.parse(data);
var results = jsonPath(obj, path);
if(results.length === 1) {
return JSON.stringify(results[0]);
} else {
return JSON.stringify(results);
}
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path(json, text)
OWNER TO ccowan;
-- Function: json_path_float(json, text)
-- DROP FUNCTION json_path_float(json, text);
CREATE OR REPLACE FUNCTION json_path_float(data json, path text)
RETURNS double precision AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return parseFloat(JSON.parse(results[0]['value']));
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_float(json, text)
OWNER TO ccowan;
-- Function: json_path_intarray(json, text)
-- DROP FUNCTION json_path_intarray(json, text);
CREATE OR REPLACE FUNCTION json_path_intarray(data json, path text)
RETURNS integer[] AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return JSON.parse(results[0]['value']);
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_intarray(json, text)
OWNER TO ccowan;
-- Function: json_path_integer(json, text)
-- DROP FUNCTION json_path_integer(json, text);
CREATE OR REPLACE FUNCTION json_path_integer(data json, path text)
RETURNS integer AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return parseInt(JSON.parse(results[0]['value']),10);
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_integer(json, text)
OWNER TO ccowan;
-- Function: json_path_textarray(json, text)
-- DROP FUNCTION json_path_textarray(json, text);
CREATE OR REPLACE FUNCTION json_path_textarray(data json, path text)
RETURNS text[] AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return JSON.parse(results[0]['value']);
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_textarray(json, text)
OWNER TO ccowan;
-- Function: json_path_timestamp(json, text)
-- DROP FUNCTION json_path_timestamp(json, text);
CREATE OR REPLACE FUNCTION json_path_timestamp(data json, path text)
RETURNS timestamp without time zone AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return results[0]['value'];
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_timestamp(json, text)
OWNER TO ccowan;
-- Function: json_path_uuid(json, text)
-- DROP FUNCTION json_path_uuid(json, text);
CREATE OR REPLACE FUNCTION json_path_uuid(data json, path text)
RETURNS uuid AS
$BODY$
var results = plv8.execute('SELECT json_path($1::json, $2) as value', [data, path]);
return JSON.parse(results[0]['value']);
$BODY$
LANGUAGE plv8 IMMUTABLE
COST 100;
ALTER FUNCTION json_path_uuid(json, text)
OWNER TO ccowan;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment