2014-03-25 54 views
9

我正在尋找一種有效的方法來獲取原始sql文件,並使其同步執行postgres數據庫,類似於如果您通過psql運行它。在node.js中導入sql文件並針對PostgreSQL執行

我有一個sql文件,它創建所有數據庫,導入數據等我需要執行此使用node.js,但無法找到任何模塊,這會自動執行此操作。對於node.js應用程序本身,我們使用node-postgres('pg'),knex.js和bookshelf.js。我認爲,儘管這是最好的。

我能想到的另一種方法是讀取完整文件,用分號分隔它,用空格替換換行符,修剪任何重複的空格,然後以順序執行的方式將它們逐個饋送到pg中,不是異步的。如果這真的是最有效的方式,並且如果還沒有圖書館可以解決這個問題,我有點驚訝。我有點猶豫是否可以進入它,因爲SQL語法本身可能有點難度,我可能會意外地將它混淆起來。

提前一些澄清:

  • psql不能使用,因爲它不是在目標機器
  • 我選擇了開發和源代碼控制在SQL天然形式的SQL語句上安裝,因爲這是一個很大DBA更容易使用和操作它
+0

它比你首先想到的更難因爲您需要區分SQL中的關鍵字和關鍵字。作爲一個簡單的例子,_split by semicolons_不能與'插入表值(';');' –

回答

7

我已經寫了以下函數,它爲我的案件工作。這本來是更簡單的,如果不是因爲:

  • 使用batch管理併發
  • 具有棘手的PostgreSQL COPY的情況下考慮

代碼片段:

function processSQLFile(fileName) { 

    // Extract SQL queries from files. Assumes no ';' in the fileNames 
    var queries = fs.readFileSync(fileName).toString() 
    .replace(/(\r\n|\n|\r)/gm," ") // remove newlines 
    .replace(/\s+/g, ' ') // excess white space 
    .split(";") // split into all statements 
    .map(Function.prototype.call, String.prototype.trim) 
    .filter(function(el) {return el.length != 0}); // remove any empty ones 

    // Execute each SQL query sequentially 
    queries.forEach(function(query) { 
    batch.push(function(done) { 
     if (query.indexOf("COPY") === 0) { // COPY - needs special treatment 
     var regexp = /COPY\ (.*)\ FROM\ (.*)\ DELIMITERS/gmi; 
     var matches = regexp.exec(query); 
     var table = matches[1]; 
     var fileName = matches[2]; 
     var copyString = "COPY " + table + " FROM STDIN DELIMITERS ',' CSV HEADER"; 
     var stream = client.copyFrom(copyString); 
     stream.on('close', function() { 
      done(); 
     }); 
     var csvFile = __dirname + '/' + fileName; 
     var str = fs.readFileSync(csvFile); 
     stream.write(str); 
     stream.end(); 
     } else { // Other queries don't need special treatment 
     client.query(query, function(result) { 
      done(); 
     }); 
     } 
    }); 
    }); 
} 

請注意,如果您在除終止SQL語句之外的任何地方使用了分號,則會失敗。

+0

你可以添加什麼'批次'是什麼細節? –

+0

https://github.com/visionmedia/batch – rgareth

16

你傳遞給client.query

這一工程時,可以只用分號分隔隨之而來的疑問:

var pg = require('pg'); 

pg.connect('postgres://test:[email protected]/test', function(err, client, done){ 
     client.query('CREATE TABLE test (test VARCHAR(255)); INSERT INTO test VALUES(\'test\') '); 
     done(); 
}); 

啥都,這也工作:

var pg = require('pg'); 
var fs = require('fs'); 

var sql = fs.readFileSync('init_database.sql').toString(); 

pg.connect('postgres://test:[email protected]/test', function(err, client, done){ 
    if(err){ 
     console.log('error: ', err); 
     process.exit(1); 
    } 
    client.query(sql, function(err, result){ 
     done(); 
     if(err){ 
      console.log('error: ', err); 
      process.exit(1); 
     } 
     process.exit(0); 
    }); 
}); 
+0

我最初嘗試過,但發現問題: *傳統上在SQL文件中發現的換行符和標籤無法填充到client.query中,(可以通過一些額外的步驟解析) * Very每個查詢都很難處理(我承認這裏也沒有列出我的例子) – rgareth

+0

@rgareth我完全沒有任何問題,無論是SQL文件中的換行符還是選項卡。你可以在我的例子中添加一些'\ n's(甚至'\ r \ n's)和'\ t's,它仍然可以工作。 – OhJeez

+0

爲我工作的ibm_db lib。我也面臨同樣的問題,但是我想起了一個問題。怎麼樣SQL注入? – user2670818

相關問題