UNPKG

11.7 kBJavaScriptView Raw
1//- JavaScript source code
2
3//- defs-postgres.js ~~
4//
5// These definitions need help from an RDBMS guru.
6//
7// Known shortcomings:
8// - The API definition for `get_avar` does not update `exp_date`.
9// - The API storage definitions do not take advantage of indexing.
10// - The log storage definition assumes that hstore is available.
11//
12// ~~ (c) SRW, 25 Sep 2012
13// ~~ last updated 10 Aug 2014
14
15(function () {
16 'use strict';
17
18 // Pragmas
19
20 /*jshint maxparams: 3, quotmark: single, strict: true */
21
22 /*jslint indent: 4, maxlen: 80, node: true */
23
24 /*properties
25 api, avar_ttl, body, ceil, collect_garbage, connect, error, get_avar,
26 get_list, hasOwnProperty, isMaster, join, key, length, log, map, now,
27 postgres, push, query, rows, set_avar, stringify
28 */
29
30 // Declarations
31
32 var cluster, pg;
33
34 // Definitions
35
36 cluster = require('cluster');
37
38 pg = require('pg'); //- or, use `require('pg').native` ...
39
40 // Out-of-scope definitions
41
42 exports.api = function (options) {
43 // This function needs documentation.
44
45 var collect_garbage, connection_string, exp_date, get_avar, get_list,
46 set_avar;
47
48 collect_garbage = function () {
49 // This function needs documentation.
50 pg.connect(connection_string, function (err, client, done) {
51 // This function needs documentation.
52 if (err !== null) {
53 console.error('Error:', err);
54 done();
55 return;
56 }
57 var now, sql;
58 now = Math.ceil(Date.now() / 1000);
59 sql = 'DELETE FROM avars WHERE (exp_date < $1)';
60 client.query(sql, [now], function (err) {
61 // This function n needs documentation.
62 if (err !== null) {
63 console.error('Error:', err);
64 } else {
65 console.log('Finished collecting garbage.');
66 }
67 done();
68 return;
69 });
70 return;
71 });
72 return;
73 };
74
75 connection_string = options.postgres;
76
77 exp_date = function () {
78 // This function needs documentation.
79 return Math.ceil((Date.now() / 1000) + options.avar_ttl);
80 };
81
82 get_avar = function (params, callback) {
83 // This function needs documentation.
84 pg.connect(connection_string, function (err, client, done) {
85 // This function needs documentation.
86 if (err !== null) {
87 done();
88 return callback(err, undefined);
89 }
90 var x = 'SELECT body FROM avars WHERE box_key = $1';
91 client.query(x, [params.join('&')], function (err, results) {
92 // This function needs documentation.
93 done();
94 if (err !== null) {
95 return callback(err, undefined);
96 }
97 if (results.rows.length < 1) {
98 return callback(null, undefined);
99 }
100 return callback(null, results.rows[0].body);
101 });
102 return;
103 });
104 return;
105 };
106
107 get_list = function (params, callback) {
108 // This function needs documentation.
109 pg.connect(connection_string, function (err, client, done) {
110 // This function needs documentation.
111 if (err !== null) {
112 done();
113 return callback(err, undefined);
114 }
115 var x = 'SELECT key FROM avars WHERE box_status = $1';
116 client.query(x, [params.join('&')], function (err, results) {
117 // This function needs documentation.
118 done();
119 if (err !== null) {
120 return callback(err, undefined);
121 }
122 var y = (results === undefined) ? {rows: []} : results;
123 return callback(null, y.rows.map(function (row) {
124 // This function needs documentation.
125 return row.key;
126 }));
127 });
128 return;
129 });
130 return;
131 };
132
133 set_avar = function (params, callback) {
134 // This function needs documentation.
135 pg.connect(connection_string, function (err, client, done) {
136 // This function needs documentation.
137 if (err !== null) {
138 done();
139 return callback(err, undefined);
140 }
141 var args, sql;
142 if (params.length === 4) {
143 args = [
144 params[3],
145 params[0] + '&' + params[1],
146 params[0] + '&' + params[2],
147 exp_date(),
148 params[1]
149 ];
150 sql = 'SELECT upsert_task($1, $2, $3, $4, $5)';
151 } else {
152 args = [
153 params[2],
154 params[0] + '&' + params[1],
155 exp_date()
156 ];
157 sql = 'SELECT upsert_avar($1, $2, $3)';
158 }
159 client.query(sql, args, function (err, results) {
160 // This function needs documentation.
161 done();
162 return callback(err, results);
163 });
164 return;
165 });
166 return;
167 };
168
169 if (cluster.isMaster) {
170 pg.connect(connection_string, function (err, client, done) {
171 // This function needs documentation.
172 if (err !== null) {
173 done();
174 throw err;
175 }
176 var lines;
177 lines = [
178 'CREATE TABLE IF NOT EXISTS avars (',
179 ' body TEXT NOT NULL,',
180 ' box_key TEXT NOT NULL,',
181 ' box_status TEXT,',
182 ' exp_date INTEGER NOT NULL,',
183 ' key TEXT,', //- this doesn't need to be "NOT NULL"
184 ' PRIMARY KEY (box_key)',
185 ');',
186 'CREATE OR REPLACE FUNCTION upsert_avar' +
187 '(b2 TEXT, bk2 TEXT, ed2 INTEGER) RETURNS VOID AS',
188 '$$',
189 'BEGIN',
190 ' LOOP',
191 ' UPDATE avars',
192 ' SET body = b2,' +
193 ' box_status = NULL,' +
194 ' exp_date = ed2,' +
195 ' key = NULL',
196 ' WHERE box_key = bk2;',
197 ' IF found THEN',
198 ' RETURN;',
199 ' END IF;',
200 ' BEGIN',
201 ' INSERT INTO avars (body, box_key, exp_date)',
202 ' VALUES (b2, bk2, ed2);',
203 ' RETURN;',
204 ' EXCEPTION WHEN unique_violation THEN',
205 ' END;',
206 ' END LOOP;',
207 'END;',
208 '$$',
209 'LANGUAGE plpgsql;',
210 'CREATE OR REPLACE FUNCTION upsert_task' +
211 '(b2 TEXT, bk2 TEXT, bs2 TEXT, ed2 INTEGER, k2 TEXT)' +
212 'RETURNS VOID AS',
213 '$$',
214 'BEGIN',
215 ' LOOP',
216 ' UPDATE avars',
217 ' SET body = b2,' +
218 ' box_status = bs2,' +
219 ' exp_date = ed2,' +
220 ' key = k2',
221 ' WHERE box_key = bk2;',
222 ' IF found THEN',
223 ' RETURN;',
224 ' END IF;',
225 ' BEGIN',
226 ' INSERT INTO avars ' +
227 ' (body, box_key, box_status, exp_date, key)',
228 ' VALUES (b2, bk2, bs2, ed2, k2);',
229 ' RETURN;',
230 ' EXCEPTION WHEN unique_violation THEN',
231 ' END;',
232 ' END LOOP;',
233 'END;',
234 '$$',
235 'LANGUAGE plpgsql;'
236 ];
237 client.query(lines.join('\n'), function (err) {
238 // This function also accepts a second argument that contains
239 // the "results" of the query, but because I don't use it, I
240 // have omitted it to avoid irritating JSLint et al.
241 done();
242 if (err !== null) {
243 throw err;
244 }
245 console.log('API: Postgres storage is ready.');
246 return;
247 });
248 return;
249 });
250 }
251
252 return {
253 collect_garbage: collect_garbage,
254 get_avar: get_avar,
255 get_list: get_list,
256 set_avar: set_avar
257 };
258 };
259
260 exports.log = function (options) {
261 // This function needs documentation.
262 pg.connect(options.postgres, function (err, client, done) {
263 // This function needs documentation.
264 if (err !== null) {
265 done();
266 throw err;
267 }
268 var lines;
269 lines = [
270 'CREATE EXTENSION IF NOT EXISTS hstore;',
271 'CREATE TABLE IF NOT EXISTS traffic (',
272 ' id serial PRIMARY KEY,',
273 ' doc hstore',
274 ');'
275 ];
276 client.query(lines.join('\n'), function (err) {
277 // This function needs documentation.
278 if (err !== null) {
279 console.error('Error:', err);
280 }
281 done();
282 return;
283 });
284 return;
285 });
286 return function (obj) {
287 // This function needs documentation.
288 pg.connect(options.postgres, function (err, client, done) {
289 // This function needs documentation.
290 if (err !== null) {
291 done();
292 throw err;
293 }
294 var doc, key, sql, temp;
295 temp = [];
296 for (key in obj) {
297 if (obj.hasOwnProperty(key)) {
298 temp.push(key + ' => ' + JSON.stringify(obj[key]));
299 }
300 }
301 doc = temp.join(', ');
302 sql = 'INSERT INTO traffic (doc) VALUES (\'' + doc + '\');';
303 client.query(sql, function (err) {
304 // This function needs documentation.
305 if (err !== null) {
306 console.error('Error:', err);
307 }
308 done();
309 return;
310 });
311 return;
312 });
313 return;
314 };
315 };
316
317 // That's all, folks!
318
319 return;
320
321}());
322
323//- vim:set syntax=javascript: