csv-to-pg 0.6.2 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/cli.d.ts +2 -0
- package/cli.js +60 -0
- package/esm/cli.js +58 -0
- package/esm/index.js +3 -0
- package/esm/parse.js +257 -0
- package/esm/parser.js +59 -0
- package/esm/utils.js +267 -0
- package/index.d.ts +2 -0
- package/index.js +19 -0
- package/package.json +25 -55
- package/parse.d.ts +3 -0
- package/parse.js +289 -0
- package/parser.d.ts +4 -0
- package/parser.js +63 -0
- package/utils.d.ts +135 -0
- package/utils.js +300 -0
- package/main/cli.js +0 -96
- package/main/index.js +0 -29
- package/main/parse.js +0 -352
- package/main/parser.js +0 -139
- package/main/utils.js +0 -413
- package/module/cli.js +0 -59
- package/module/index.js +0 -2
- package/module/parse.js +0 -308
- package/module/parser.js +0 -67
- package/module/utils.js +0 -334
package/module/parse.js
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
-
|
|
3
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
6
|
-
|
|
7
|
-
import csv from 'csv-parser';
|
|
8
|
-
import { createReadStream, readFileSync } from 'fs';
|
|
9
|
-
import { safeLoad as parseYAML } from 'js-yaml';
|
|
10
|
-
import * as ast from 'pg-ast';
|
|
11
|
-
import { makeBoundingBox, makeLocation, getRelatedField, wrapValue } from './utils';
|
|
12
|
-
|
|
13
|
-
function isNumeric(str) {
|
|
14
|
-
if (typeof str != 'string') return false; // we only process strings!
|
|
15
|
-
|
|
16
|
-
return !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
|
|
17
|
-
!isNaN(parseFloat(str)); // ...and ensure strings of whitespace fail
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const parseJson = value => {
|
|
21
|
-
if (typeof value === 'string') return value;
|
|
22
|
-
return value && JSON.stringify(value);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const psqlArray = value => {
|
|
26
|
-
if (value && value.length) {
|
|
27
|
-
return `{${value.map(v => v)}}`;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const parse = (path, opts) => new Promise((resolve, reject) => {
|
|
32
|
-
const results = [];
|
|
33
|
-
createReadStream(path).pipe(csv(opts)) // TODO check if 'data' is guaranteed to have a full row,
|
|
34
|
-
// if so, make a hook to use the stream properly
|
|
35
|
-
.on('data', data => results.push(data)).on('error', er => {
|
|
36
|
-
reject(er);
|
|
37
|
-
}).on('end', () => {
|
|
38
|
-
resolve(results);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
export const readConfig = config => {
|
|
42
|
-
let configValue;
|
|
43
|
-
|
|
44
|
-
if (config.endsWith('.js')) {
|
|
45
|
-
configValue = require(config);
|
|
46
|
-
} else if (config.endsWith('json')) {
|
|
47
|
-
configValue = JSON.parse(readFileSync(config, 'utf-8'));
|
|
48
|
-
} else if (config.endsWith('yaml') || config.endsWith('yml')) {
|
|
49
|
-
configValue = parseYAML(readFileSync(config, 'utf-8'));
|
|
50
|
-
} else {
|
|
51
|
-
throw new Error('unsupported config!');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return configValue;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const getFromValue = from => {
|
|
58
|
-
if (Array.isArray(from)) return from;
|
|
59
|
-
return [from];
|
|
60
|
-
}; // looks like the CSV library gives us empty strings?
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const cleanseEmptyStrings = str => {
|
|
64
|
-
if (typeof str === 'string') {
|
|
65
|
-
if (str.trim() === '') return null;
|
|
66
|
-
return str;
|
|
67
|
-
} else {
|
|
68
|
-
return str;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const parseBoolean = str => {
|
|
73
|
-
if (typeof str === 'boolean') {
|
|
74
|
-
return str;
|
|
75
|
-
} else if (typeof str === 'string') {
|
|
76
|
-
const s = str.toLowerCase();
|
|
77
|
-
|
|
78
|
-
if (s === 'true') {
|
|
79
|
-
return true;
|
|
80
|
-
} else if (s === 't') {
|
|
81
|
-
return true;
|
|
82
|
-
} else if (s === 'f') {
|
|
83
|
-
return false;
|
|
84
|
-
} else if (s === 'false') {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return null;
|
|
89
|
-
} else {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const getValuesFromKeys = (object, keys) => keys.map(key => object[key]);
|
|
95
|
-
|
|
96
|
-
const identity = a => a;
|
|
97
|
-
|
|
98
|
-
const isEmpty = value => value === null || typeof value === 'undefined'; // type (int, text, etc)
|
|
99
|
-
// from Array of keys that map to records found (e.g., ['lon', 'lat'])
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const getCoercionFunc = (type, from, opts) => {
|
|
103
|
-
const parse = opts.parse = opts.parse || identity;
|
|
104
|
-
|
|
105
|
-
switch (type) {
|
|
106
|
-
case 'int':
|
|
107
|
-
return record => {
|
|
108
|
-
const value = parse(record[from[0]]);
|
|
109
|
-
|
|
110
|
-
if (isEmpty(value)) {
|
|
111
|
-
return ast.Null({});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!isNumeric(value)) {
|
|
115
|
-
return ast.Null({});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const val = ast.A_Const({
|
|
119
|
-
val: ast.Integer({
|
|
120
|
-
ival: value
|
|
121
|
-
})
|
|
122
|
-
});
|
|
123
|
-
return wrapValue(val, opts);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
case 'float':
|
|
127
|
-
return record => {
|
|
128
|
-
const value = parse(record[from[0]]);
|
|
129
|
-
|
|
130
|
-
if (isEmpty(value)) {
|
|
131
|
-
return ast.Null({});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!isNumeric(value)) {
|
|
135
|
-
return ast.Null({});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const val = ast.A_Const({
|
|
139
|
-
val: ast.Float({
|
|
140
|
-
str: value
|
|
141
|
-
})
|
|
142
|
-
});
|
|
143
|
-
return wrapValue(val, opts);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
case 'boolean':
|
|
147
|
-
case 'bool':
|
|
148
|
-
return record => {
|
|
149
|
-
const value = parse(parseBoolean(record[from[0]]));
|
|
150
|
-
|
|
151
|
-
if (isEmpty(value)) {
|
|
152
|
-
return ast.Null({});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const val = ast.String({
|
|
156
|
-
str: value ? 'TRUE' : 'FALSE'
|
|
157
|
-
});
|
|
158
|
-
return wrapValue(val, opts);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
case 'bbox':
|
|
162
|
-
// do bbox magic with args from the fields
|
|
163
|
-
return record => {
|
|
164
|
-
const val = makeBoundingBox(parse(record[from[0]]));
|
|
165
|
-
return wrapValue(val, opts);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
case 'location':
|
|
169
|
-
return record => {
|
|
170
|
-
const [lon, lat] = getValuesFromKeys(record, from);
|
|
171
|
-
|
|
172
|
-
if (typeof lon === 'undefined') {
|
|
173
|
-
return ast.Null({});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (typeof lat === 'undefined') {
|
|
177
|
-
return ast.Null({});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (!isNumeric(lon) || !isNumeric(lat)) {
|
|
181
|
-
return ast.Null({});
|
|
182
|
-
} // NO parse here...
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const val = makeLocation(lon, lat);
|
|
186
|
-
return wrapValue(val, opts);
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
case 'related':
|
|
190
|
-
return record => {
|
|
191
|
-
return getRelatedField(_objectSpread(_objectSpread({}, opts), {}, {
|
|
192
|
-
record,
|
|
193
|
-
from
|
|
194
|
-
}));
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
case 'uuid':
|
|
198
|
-
return record => {
|
|
199
|
-
const value = parse(record[from[0]]);
|
|
200
|
-
|
|
201
|
-
if (isEmpty(value) || !/^([0-9a-fA-F]{8})-(([0-9a-fA-F]{4}-){3})([0-9a-fA-F]{12})$/i.test(value)) {
|
|
202
|
-
return ast.Null({});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const val = ast.A_Const({
|
|
206
|
-
val: ast.String({
|
|
207
|
-
str: value
|
|
208
|
-
})
|
|
209
|
-
});
|
|
210
|
-
return wrapValue(val, opts);
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
case 'text':
|
|
214
|
-
return record => {
|
|
215
|
-
const value = parse(cleanseEmptyStrings(record[from[0]]));
|
|
216
|
-
|
|
217
|
-
if (isEmpty(value)) {
|
|
218
|
-
return ast.Null({});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const val = ast.A_Const({
|
|
222
|
-
val: ast.String({
|
|
223
|
-
str: value
|
|
224
|
-
})
|
|
225
|
-
});
|
|
226
|
-
return wrapValue(val, opts);
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
case 'text[]':
|
|
230
|
-
return record => {
|
|
231
|
-
const value = parse(psqlArray(cleanseEmptyStrings(record[from[0]])));
|
|
232
|
-
|
|
233
|
-
if (isEmpty(value)) {
|
|
234
|
-
return ast.Null({});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const val = ast.A_Const({
|
|
238
|
-
val: ast.String({
|
|
239
|
-
str: value
|
|
240
|
-
})
|
|
241
|
-
});
|
|
242
|
-
return wrapValue(val, opts);
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
case 'image':
|
|
246
|
-
case 'attachment':
|
|
247
|
-
case 'json':
|
|
248
|
-
case 'jsonb':
|
|
249
|
-
return record => {
|
|
250
|
-
const value = parse(parseJson(cleanseEmptyStrings(record[from[0]])));
|
|
251
|
-
|
|
252
|
-
if (isEmpty(value)) {
|
|
253
|
-
return ast.Null({});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const val = ast.A_Const({
|
|
257
|
-
val: ast.String({
|
|
258
|
-
str: value
|
|
259
|
-
})
|
|
260
|
-
});
|
|
261
|
-
return wrapValue(val, opts);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
default:
|
|
265
|
-
return record => {
|
|
266
|
-
const value = parse(cleanseEmptyStrings(record[from[0]]));
|
|
267
|
-
|
|
268
|
-
if (isEmpty(value)) {
|
|
269
|
-
return ast.Null({});
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const val = ast.A_Const({
|
|
273
|
-
val: ast.String({
|
|
274
|
-
str: value
|
|
275
|
-
})
|
|
276
|
-
});
|
|
277
|
-
return wrapValue(val, opts);
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
export const parseTypes = config => {
|
|
283
|
-
return Object.entries(config.fields).reduce((m, v) => {
|
|
284
|
-
let [key, value] = v;
|
|
285
|
-
let type;
|
|
286
|
-
let from;
|
|
287
|
-
|
|
288
|
-
if (typeof value === 'string') {
|
|
289
|
-
type = value;
|
|
290
|
-
from = [key];
|
|
291
|
-
|
|
292
|
-
if (['related', 'location'].includes(type)) {
|
|
293
|
-
throw new Error('must use object for ' + type + ' type');
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
value = {
|
|
297
|
-
type,
|
|
298
|
-
from
|
|
299
|
-
};
|
|
300
|
-
} else {
|
|
301
|
-
type = value.type;
|
|
302
|
-
from = getFromValue(value.from || key);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
m[key] = getCoercionFunc(type, from, value);
|
|
306
|
-
return m;
|
|
307
|
-
}, {});
|
|
308
|
-
};
|
package/module/parser.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
-
import { parse, parseTypes } from './index';
|
|
3
|
-
import { deparse } from 'pgsql-deparser';
|
|
4
|
-
import { InsertOne, InsertMany } from './utils';
|
|
5
|
-
export class Parser {
|
|
6
|
-
constructor(config) {
|
|
7
|
-
this.config = config;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
async parse(data) {
|
|
11
|
-
const config = this.config;
|
|
12
|
-
const {
|
|
13
|
-
schema,
|
|
14
|
-
table,
|
|
15
|
-
singleStmts,
|
|
16
|
-
conflict,
|
|
17
|
-
headers,
|
|
18
|
-
delimeter
|
|
19
|
-
} = config;
|
|
20
|
-
const opts = {};
|
|
21
|
-
if (headers) opts.headers = headers;
|
|
22
|
-
if (delimeter) opts.separator = delimeter;
|
|
23
|
-
let records;
|
|
24
|
-
|
|
25
|
-
if (typeof data === 'undefined') {
|
|
26
|
-
if (config.json || config.input.endsWith('.json')) {
|
|
27
|
-
records = JSON.parse(readFileSync(config.input, 'utf-8'));
|
|
28
|
-
} else {
|
|
29
|
-
records = await parse(config.input, opts);
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
if (!Array.isArray(data)) {
|
|
33
|
-
throw new Error('data is not an array');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
records = data;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (config.debug) {
|
|
40
|
-
console.log(records);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const types = parseTypes(config);
|
|
45
|
-
|
|
46
|
-
if (singleStmts) {
|
|
47
|
-
const stmts = records.map(record => InsertOne({
|
|
48
|
-
schema,
|
|
49
|
-
table,
|
|
50
|
-
types,
|
|
51
|
-
record,
|
|
52
|
-
conflict
|
|
53
|
-
}));
|
|
54
|
-
return deparse(stmts);
|
|
55
|
-
} else {
|
|
56
|
-
const stmt = InsertMany({
|
|
57
|
-
schema,
|
|
58
|
-
table,
|
|
59
|
-
types,
|
|
60
|
-
records,
|
|
61
|
-
conflict
|
|
62
|
-
});
|
|
63
|
-
return deparse([stmt]);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
}
|
package/module/utils.js
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import * as ast from 'pg-ast';
|
|
2
|
-
import { join, resolve } from 'path';
|
|
3
|
-
export const normalizePath = (path, cwd) => path.startsWith('/') ? path : resolve(join(cwd ? cwd : process.cwd(), path));
|
|
4
|
-
|
|
5
|
-
const lstr = bbox => {
|
|
6
|
-
const [lng1, lat1, lng2, lat2] = bbox.split(',').map(a => a.trim());
|
|
7
|
-
return `LINESTRING(${lng1} ${lat1}, ${lng1} ${lat2}, ${lng2} ${lat2}, ${lng2} ${lat1}, ${lng1} ${lat1})`;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const funcCall = (name, args) => {
|
|
11
|
-
return ast.FuncCall({
|
|
12
|
-
funcname: [ast.String({
|
|
13
|
-
str: name
|
|
14
|
-
})],
|
|
15
|
-
args
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const aflt = num => ast.A_Const({
|
|
20
|
-
val: ast.Float({
|
|
21
|
-
str: num
|
|
22
|
-
})
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const aint = num => ast.A_Const({
|
|
26
|
-
val: ast.Integer({
|
|
27
|
-
ival: num
|
|
28
|
-
})
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export const makeLocation = (longitude, latitude) => {
|
|
32
|
-
if (!longitude || !latitude) {
|
|
33
|
-
return ast.Null();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return funcCall('st_setsrid', [funcCall('st_makepoint', [aflt(longitude), aflt(latitude)]), aint(4326)]);
|
|
37
|
-
}; // a string in the form of lon,lat,lon,lat
|
|
38
|
-
// -118.587533,34.024999,-118.495177,34.13165
|
|
39
|
-
|
|
40
|
-
export const makeBoundingBox = bbox => {
|
|
41
|
-
return funcCall('st_setsrid', [funcCall('st_makepolygon', [funcCall('st_geomfromtext', [ast.A_Const({
|
|
42
|
-
val: ast.String({
|
|
43
|
-
str: lstr(bbox)
|
|
44
|
-
})
|
|
45
|
-
})])]), aint(4326)]);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const ValuesLists = ({
|
|
49
|
-
types,
|
|
50
|
-
record
|
|
51
|
-
}) => Object.entries(types).map(([field, type]) => {
|
|
52
|
-
if (typeof type === 'function') {
|
|
53
|
-
return type(record);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
throw new Error('coercion function missing');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const makeCast = (arg, type) => ({
|
|
60
|
-
TypeCast: {
|
|
61
|
-
arg,
|
|
62
|
-
typeName: {
|
|
63
|
-
TypeName: {
|
|
64
|
-
names: [{
|
|
65
|
-
String: {
|
|
66
|
-
str: type
|
|
67
|
-
}
|
|
68
|
-
}],
|
|
69
|
-
typemod: -1
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const ref = name => ({
|
|
76
|
-
ResTarget: {
|
|
77
|
-
name,
|
|
78
|
-
val: {
|
|
79
|
-
ColumnRef: {
|
|
80
|
-
fields: [{
|
|
81
|
-
String: {
|
|
82
|
-
str: 'excluded'
|
|
83
|
-
}
|
|
84
|
-
}, {
|
|
85
|
-
String: {
|
|
86
|
-
str: name
|
|
87
|
-
}
|
|
88
|
-
}]
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const indexElem = name => ({
|
|
95
|
-
IndexElem: {
|
|
96
|
-
name,
|
|
97
|
-
ordering: 0,
|
|
98
|
-
nulls_ordering: 0
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const makeConflictClause = (conflictElems, fields) => {
|
|
103
|
-
if (!conflictElems || !conflictElems.length) return undefined;
|
|
104
|
-
const setElems = fields.filter(el => !conflictElems.includes(el));
|
|
105
|
-
|
|
106
|
-
if (setElems.length) {
|
|
107
|
-
return {
|
|
108
|
-
OnConflictClause: {
|
|
109
|
-
action: 2,
|
|
110
|
-
infer: {
|
|
111
|
-
InferClause: {
|
|
112
|
-
indexElems: conflictElems.map(a => indexElem(a))
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
targetList: setElems.map(a => ref(a))
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
} else {
|
|
119
|
-
return {
|
|
120
|
-
OnConflictClause: {
|
|
121
|
-
action: 1,
|
|
122
|
-
infer: {
|
|
123
|
-
InferClause: {
|
|
124
|
-
indexElems: conflictElems.map(a => indexElem(a))
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const InsertOne = ({
|
|
133
|
-
schema = 'public',
|
|
134
|
-
table,
|
|
135
|
-
types,
|
|
136
|
-
record,
|
|
137
|
-
conflict
|
|
138
|
-
}) => ({
|
|
139
|
-
RawStmt: {
|
|
140
|
-
stmt: {
|
|
141
|
-
InsertStmt: {
|
|
142
|
-
relation: {
|
|
143
|
-
RangeVar: {
|
|
144
|
-
schemaname: schema,
|
|
145
|
-
relname: table,
|
|
146
|
-
inh: true,
|
|
147
|
-
relpersistence: 'p'
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
cols: Object.keys(types).map(field => ast.ResTarget({
|
|
151
|
-
name: field
|
|
152
|
-
})),
|
|
153
|
-
selectStmt: {
|
|
154
|
-
SelectStmt: {
|
|
155
|
-
valuesLists: [ValuesLists({
|
|
156
|
-
types,
|
|
157
|
-
record
|
|
158
|
-
})],
|
|
159
|
-
op: 0
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
onConflictClause: makeConflictClause(conflict, Object.keys(types)),
|
|
163
|
-
override: 0
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
stmt_len: 1
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
export const InsertMany = ({
|
|
170
|
-
schema = 'public',
|
|
171
|
-
table,
|
|
172
|
-
types,
|
|
173
|
-
records,
|
|
174
|
-
conflict
|
|
175
|
-
}) => ({
|
|
176
|
-
RawStmt: {
|
|
177
|
-
stmt: {
|
|
178
|
-
InsertStmt: {
|
|
179
|
-
relation: {
|
|
180
|
-
RangeVar: {
|
|
181
|
-
schemaname: schema,
|
|
182
|
-
relname: table,
|
|
183
|
-
inh: true,
|
|
184
|
-
relpersistence: 'p'
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
cols: Object.keys(types).map(field => ast.ResTarget({
|
|
188
|
-
name: field
|
|
189
|
-
})),
|
|
190
|
-
selectStmt: {
|
|
191
|
-
SelectStmt: {
|
|
192
|
-
valuesLists: records.map(record => ValuesLists({
|
|
193
|
-
types,
|
|
194
|
-
record
|
|
195
|
-
})),
|
|
196
|
-
op: 0
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
onConflictClause: makeConflictClause(conflict, Object.keys(types)),
|
|
200
|
-
override: 0
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
stmt_len: 1
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
export const wrapValue = (val, {
|
|
207
|
-
wrap,
|
|
208
|
-
wrapAst,
|
|
209
|
-
cast
|
|
210
|
-
} = {}) => {
|
|
211
|
-
if (Array.isArray(wrap)) {
|
|
212
|
-
val = ast.FuncCall({
|
|
213
|
-
funcname: wrap.map(n => ast.String({
|
|
214
|
-
str: n
|
|
215
|
-
})),
|
|
216
|
-
args: [val]
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (wrapAst) return wrapAst(val);
|
|
221
|
-
if (cast) return makeCast(val, cast);
|
|
222
|
-
return val;
|
|
223
|
-
};
|
|
224
|
-
export const getRelatedField = ({
|
|
225
|
-
schema = 'public',
|
|
226
|
-
table,
|
|
227
|
-
refType,
|
|
228
|
-
refKey,
|
|
229
|
-
refField,
|
|
230
|
-
wrap,
|
|
231
|
-
wrapAst,
|
|
232
|
-
cast,
|
|
233
|
-
record,
|
|
234
|
-
parse,
|
|
235
|
-
from
|
|
236
|
-
}) => {
|
|
237
|
-
let val;
|
|
238
|
-
const value = parse(record[from[0]]);
|
|
239
|
-
|
|
240
|
-
if (typeof value === 'undefined') {
|
|
241
|
-
return ast.Null({});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
switch (refType) {
|
|
245
|
-
case 'int':
|
|
246
|
-
val = ast.A_Const({
|
|
247
|
-
val: ast.Integer({
|
|
248
|
-
ival: value
|
|
249
|
-
})
|
|
250
|
-
});
|
|
251
|
-
break;
|
|
252
|
-
|
|
253
|
-
case 'float':
|
|
254
|
-
val = ast.A_Const({
|
|
255
|
-
val: ast.Float({
|
|
256
|
-
str: value
|
|
257
|
-
})
|
|
258
|
-
});
|
|
259
|
-
break;
|
|
260
|
-
|
|
261
|
-
case 'boolean':
|
|
262
|
-
case 'bool':
|
|
263
|
-
val = ast.String({
|
|
264
|
-
str: value ? 'TRUE' : 'FALSE'
|
|
265
|
-
});
|
|
266
|
-
break;
|
|
267
|
-
|
|
268
|
-
case 'text':
|
|
269
|
-
default:
|
|
270
|
-
val = ast.A_Const({
|
|
271
|
-
val: ast.String({
|
|
272
|
-
str: value
|
|
273
|
-
})
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
val = wrapValue(val, {
|
|
278
|
-
wrap,
|
|
279
|
-
wrapAst
|
|
280
|
-
});
|
|
281
|
-
return wrapValue({
|
|
282
|
-
SubLink: {
|
|
283
|
-
subLinkType: 4,
|
|
284
|
-
subselect: {
|
|
285
|
-
SelectStmt: {
|
|
286
|
-
targetList: [{
|
|
287
|
-
ResTarget: {
|
|
288
|
-
val: {
|
|
289
|
-
ColumnRef: {
|
|
290
|
-
fields: [{
|
|
291
|
-
String: {
|
|
292
|
-
str: refKey
|
|
293
|
-
}
|
|
294
|
-
}]
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}],
|
|
299
|
-
fromClause: [{
|
|
300
|
-
RangeVar: {
|
|
301
|
-
schemaname: schema,
|
|
302
|
-
relname: table,
|
|
303
|
-
inh: true,
|
|
304
|
-
relpersistence: 'p'
|
|
305
|
-
}
|
|
306
|
-
}],
|
|
307
|
-
whereClause: {
|
|
308
|
-
A_Expr: {
|
|
309
|
-
kind: 0,
|
|
310
|
-
name: [{
|
|
311
|
-
String: {
|
|
312
|
-
str: '='
|
|
313
|
-
}
|
|
314
|
-
}],
|
|
315
|
-
lexpr: {
|
|
316
|
-
ColumnRef: {
|
|
317
|
-
fields: [{
|
|
318
|
-
String: {
|
|
319
|
-
str: refField
|
|
320
|
-
}
|
|
321
|
-
}]
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
rexpr: val
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
op: 0
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}, {
|
|
332
|
-
cast
|
|
333
|
-
});
|
|
334
|
-
};
|