-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.cjs
More file actions
146 lines (124 loc) · 3.88 KB
/
index.cjs
File metadata and controls
146 lines (124 loc) · 3.88 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const R = require("ramda");
const pg = require("pg");
const mustache = require("mustache");
const fs = require("fs");
const url = require("url");
const readdir = require("recursive-readdir-sync");
const debug = require("debug");
const info = debug("postache:info");
const sensitive = debug("postache:sensitive");
const error = debug("postache:error");
const dollarFollowedByAscii = /\$([a-zA-Z0-9_.]+)/g;
/* Remove the password from a given url string */
const obscurePassword = (conStr, password) => {
if (password === "") return conStr;
return conStr.replace(password, "\x1B[31m{password omitted}\x1B[39m");
};
// Deprecated: Parse a connection string to a pg configuration object
const urlToObj = (conStr) => {
if (typeof conStr !== "string") {
return conStr;
}
const conParams = url.parse(conStr, true);
const hasAuth = conParams.auth !== null;
const auth = {
username: "",
password: "",
};
if (hasAuth) {
if (conParams.auth.indexOf(":") === -1) {
auth.username = conParams.auth;
info("No password supplied, using only username");
} else {
const [username, password] = conParams.auth.split(":");
auth.username = username;
auth.password = password;
}
} else {
info("No username or password supplied, using blank name and password");
}
if (conParams.pathname === null) {
error(
`
You must define a valid database url!
A database URL looks like:
postgres://localhost/omni/
But you gave me:
${obscurePassword(conStr, auth.password)}
`.trim()
);
throw new Error("Invalid database URL!");
}
return {
user: auth.username,
password: auth.password,
host: conParams.hostname,
port: conParams.port,
database: conParams.pathname.split("/")[1],
ssl: !!conParams.query.ssl,
min: conParams.query.min && +conParams.query.min,
max: conParams.query.max && +conParams.query.max,
idleTimeoutMillis:
conParams.query.idleTimeoutMillis && +conParams.query.idleTimeoutMillis,
};
};
// Parse a config object or a string to support old and new ways of configuring postache
const parseConfig = (urlOrPgConfig) => {
if (typeof urlOrPgConfig === "string") {
info(
"String database URL is deprecated, use an object instead! More info: https://github.com/omninews/node-postache#configuration"
);
return urlToObj(urlOrPgConfig);
}
if (typeof urlOrPgConfig === "object") {
return urlOrPgConfig;
}
throw new Error("Invalid database URL!");
};
module.exports = (queries, context, urlOrPgConfig, pgConfig = {}) => {
const pgConfigObj = {
...parseConfig(urlOrPgConfig),
...parseConfig(pgConfig),
};
const db = new pg.Pool(pgConfigObj);
db.on("error", (err) => {
error("idle client error: %s %j", err.message, err.stack);
});
const renderedQueries = R.mapObjIndexed(
(query) => mustache.render(query, context, queries),
queries
);
const queryWithObj = (objQuery) => (argsObj) => {
const args = [];
const pgQuery = objQuery.replace(dollarFollowedByAscii, (_, name) => {
args.push(R.path(name.split("."), argsObj));
return `$${args.length}`;
});
info("Running query: %s", pgQuery);
sensitive("Args: %j", args);
return db.query(pgQuery, args).catch((e) => {
error("Postache error: %j", e);
return Promise.reject(e);
});
};
return {
query: db.query.bind(db),
db,
...R.mapObjIndexed(queryWithObj, renderedQueries),
};
};
module.exports.loadDir = (dir, extOption) => {
let ext = extOption || ".sql";
if (ext[0] !== ".") {
ext = `.${ext}`;
}
const isSqlFile = new RegExp(`.*\\${ext}$`);
return readdir(dir)
.filter((file) => file.match(isSqlFile))
.reduce((files, filePath) => {
const name = filePath.replace(`${dir}/`, "").replace(ext, "");
return Object.assign(files, {
[name]: fs.readFileSync(filePath, { encoding: "utf8" }),
});
}, {});
};