UNPKG

aquameta-sync

Version:

Import from and export to filesystem from Aquameta database

115 lines (105 loc) 3.13 kB
/* globals module require */ const fs = require('fs'); const {join} = require('path'); const {compose} = require('ramda'); const {promisify} = require('util'); const {client, database: db, query} = require('aquameta-datum'); const readdir = promisify(fs.readdir); const readFile = promisify(fs.readFile); module.exports = readTables; const executeQuery = query(client.connection()); const defaultConfig = { truncate: false, insertId: false, upsert: true, // false will only try to insert updateKey: 'id', }; async function upsert(rel, rows, config) { const pk = config.updateKey; const go = query(client.connection()); const dbRows = await go(db.select(db.include(pk, rel))); const pkValues = new Set(dbRows.map(({[pk]: val}) => val)); const updatePromises = []; const insertableRows = []; rows.forEach(row => { const pkValue = row[pk]; if (!config.insertId) { delete row.id; } if (pkValues.has(pkValue)) { // delete row[pk]; // update is broken so can't delete this field since it // may have a non-null constraint const filteredRel = db.where(pk, pkValue, rel); updatePromises.push(go(db.update(filteredRel, row))); } else { insertableRows.push(row); } }); if (insertableRows.length) { updatePromises.push(go(db.insert(rel, insertableRows))); } return Promise.all(updatePromises); } async function readTables(path) { const tables = (await readdir(path)).map(async table => { const tablePath = join(path, table); const configPath = join(tablePath, 'config.js'); let config = {...defaultConfig}; if (fs.existsSync(configPath)) { config = {...config, ...require(configPath)}; } const rel = db.relation(table); if (config.truncate) { await executeQuery(db.del(rel)); } const rows = await Promise.all(await readRows(tablePath)); if (!rows || !rows.length) { return {table, rows:[]}; } if (config.upsert) { await upsert(rel, rows, config); } else { await executeQuery( db.insert( rel, rows.map(row => { if (!config.insertId) { delete row.id; } return row; }), ), ); } return {table, rows}; }); return tables; } async function readRows(path) { const rows = (await readdir(path)) .filter(p => p !== 'config.js') .filter(p => !p.startsWith('.')) .map(async rowId => { const rowPath = join(path, rowId); const columns = await readColumns(rowPath); return {id: rowId, ...columns}; }); return Promise.all(rows); } async function readColumns(path) { const row = {}; const columns = (await readdir(path)) .filter(p => !p.startsWith('.')) .map(async name => { const fullPath = join(path, name); let content = await readFile(fullPath, 'utf-8'); if (content.charAt(content.length - 1) === '\n') { // Remove new line at end of file content = content.slice(0, -1); } row[name] = content; }); await Promise.all(columns); return row; }