libpiggy
Version:
Use a PostgreSQL database like a JSON document store.
122 lines (88 loc) • 3.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _assert = require('assert');
var _assert2 = _interopRequireDefault(_assert);
var _isNumber = require('lodash/isNumber');
var _isNumber2 = _interopRequireDefault(_isNumber);
var _map = require('lodash/fp/map');
var _map2 = _interopRequireDefault(_map);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const getFieldParts = function (fieldName) {
// E.g., foo.bar.baz[0] -> ['foo', 'bar', 'baz', 0]
return fieldName.split(/[.|[]/).map(v => v.search(']') > -1 ? Number(v.replace(']', '')) : v);
};
const getIndexPath = function (field) {
const fieldParts = getFieldParts(field);
return fieldParts.join('_');
};
const getJsonPath = function (field, type, columnNames) {
// Quote the strings
const fieldPartsRaw = getFieldParts(field);
const fieldParts = fieldPartsRaw.map(p => (0, _isNumber2.default)(p) ? p : `'${p}'`);
let jsonPath;
if (type === 'object') {
jsonPath = `("${columnNames.val}" -> ${fieldParts.join(' -> ')})`;
}
if (type === 'text' || type === 'integer') {
const fieldLast = fieldParts.pop();
if (fieldParts.length) {
jsonPath = `("${columnNames.val}" -> ${fieldParts.join(' -> ')} ->> ${fieldLast})`;
} else {
jsonPath = `("${columnNames.val}" ->> ${fieldLast})`;
}
}
if (type === 'integer') {
jsonPath = `(${jsonPath}::integer)`;
}
return jsonPath;
};
const getIndexesQueryText = function ({ table, columnNames, indexes }) {
const text = (0, _map2.default)(index => {
const { field, type, unique, lower } = index;
if (field === 'key' || field === 'val') {
_assert2.default.fail(false, `'key' and 'val' are not valid indexes`);
}
const indexPath = getIndexPath(field);
let jsonPath = getJsonPath(field, type, columnNames);
if (lower) {
jsonPath = `lower(${jsonPath})`;
}
const indexName = `${table}_${columnNames.val}_${indexPath}_idx`;
return `
CREATE ${unique ? 'UNIQUE' : ''} INDEX IF NOT EXISTS "${indexName}"
ON "${table}" (${jsonPath});
`;
}, indexes);
return text.join('');
};
const createIndexes = (() => {
var _ref = (0, _asyncToGenerator3.default)(function* (options = {}) {
const { client, table, indexes, columnNames } = options;
try {
// The primary gin index with jsonb_path_ops
let text = `
CREATE INDEX IF NOT EXISTS "${table}_${columnNames.val}_idx"
ON "${table}" USING gin ("${columnNames.val}" jsonb_path_ops);
`;
// Secondary indexes
if (indexes && indexes.length) {
text += getIndexesQueryText({ table, columnNames, indexes });
}
const results = yield client.query({ text });
return {
client,
results
};
} catch (error) {
throw error;
}
});
return function createIndexes() {
return _ref.apply(this, arguments);
};
})();
exports.default = createIndexes;