-
Notifications
You must be signed in to change notification settings - Fork 6
/
supascript--1.1.sql
96 lines (82 loc) · 4.03 KB
/
supascript--1.1.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
--complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION supascript CASCADE" to load this file. \quit
/* the alter database line below needs to be run ONCE on your database */
SET PLV8.START_PROC = 'supascript_init';
ALTER DATABASE POSTGRES SET PLV8.START_PROC TO 'supascript_init';
CREATE TABLE IF NOT EXISTS SUPASCRIPT_JS_MODULES (MODULE text UNIQUE PRIMARY KEY,
AUTOLOAD BOOL DEFAULT FALSE,
SOURCE text);
CREATE OR REPLACE FUNCTION supascript_init() RETURNS VOID
AS $$
/* plv8.execute('set search_path to "$user", public, auth, extensions'); */
this.moduleCache = {};
// execute a Postgresql function
// i.e. exec('my_function',['parm1', 123, {"item_name": "test json object"}])
this.exec = function(function_name, parms) {
var func = plv8.find_function(function_name);
return func(...parms);
}
this.load = function(key, source) {
var module = {exports: {}};
try {
eval("(function(module, exports) {" + source + "; })")(module, module.exports);
} catch (err) {
plv8.elog(ERROR, `eval error in source: ${err} (SOURCE): ${source}`);
}
// store in cache
moduleCache[key] = module.exports;
return module.exports;
};
// execute a sql statement against the Postgresql database with optional args
// i.e. sql('select * from people where first_name = $1 and last_name = $2', ['John', 'Smith'])
this.sql = function(sql_statement, args) {
if (args) {
return plv8.execute(sql_statement, args);
} else {
return plv8.execute(sql_statement);
}
};
// emulate node.js "require", with automatic download from the internet via CDN sites
// optional autoload (boolean) parameter allows the module to be preloaded later
// i.e. var myModule = require('https://some.cdn.com/module_content.js', true)
this.require = function(module, autoload) {
if (module === 'http' || module === 'https') {
// emulate NodeJS require('http')
module = 'https://raw.githubusercontent.com/burggraf/SupaScript/main/modules/http.js';
}
if(moduleCache[module])
return moduleCache[module];
var rows = plv8.execute(
'select source from supascript_js_modules where module = $1',
[module]
);
if (rows.length === 0 && module.substr(0,4) === 'http') {
try {
source = plv8.execute(`SELECT content FROM http_get('${module}');`)[0].content;
} catch (err) {
plv8.elog(ERROR, `Could not load module through http: ${module}`, JSON.stringify(err));
}
try {
/* the line below is written purely for esthetic reasons, so as not to mess up the online source editor */
/* when using standard regExp expressions, the single-quote char messes up the code highlighting */
/* in the editor and everything looks funky */
const quotedSource = source.replace(new RegExp(String.fromCharCode(39), 'g'), String.fromCharCode(39, 39));
plv8.execute(`insert into supascript_js_modules (module, autoload, source) values ('${module}', ${autoload ? true : false}, '${quotedSource}')`);
} catch (err) {
plv8.elog(ERROR, `Error inserting module into supascript_js_modules: ${err} ${module}, ${autoload ? true : false}, '${plv8.quote_literal(source)}'`);
}
return load(module, source);
} else if(rows.length === 0) {
plv8.elog(NOTICE, `Could not load module: ${module}`);
return null;
} else {
return load(module, rows[0].source);
}
};
// Grab modules worth auto-loading at context start and let them cache
var query = `select module, source from supascript_js_modules where autoload = true`;
plv8.execute(query).forEach(function(row) {
this.load(row.module, row.source);
});
$$ LANGUAGE PLV8;
/* SET search_path TO "$user", public, auth, extensions; */