I recently started to use javascript and electron. I want to use sqlite as a database technology. My problem is when I call:
OpenDB(dbPath);
CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL");
Program actually calls CreateTable function without waiting database to open. If I call these two functions with delay program works as intended. I wrote function definitions below:
export function OpenDB(dbPath) {
projectDB = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error(err.message)
this.result = false;
return;
}
console.log('SQlite project database created.');
});
}
export function CreateTable(tableName, tableColumns) {
configDB.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')' , (err) => {
if(err) {
console.error(err);
console.log("Table couldn't created.")
return;
}
console.log("Table created.")
})
}
So my question is how can I make CreateTable function wait until the database actually opened?
From what I understand from my readings I need to create callback function but I couldn't manage to do it successfully. And more I read more I confused. Thanks in advance.
let db;
export function OpenDB(dbPath, cb) {
db = new sqlite3.Database(dbPath, cb);
}
export function CreateTable(tableName, tableColumns, cb) {
db.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')', cb);
}
And welcome to callback hell
OpenDb(dpPath, function (err) {
if (err)
return console.error(err.message);
CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL", function (err) {
if (err)
return console.error(err);
});
})
If this way is inappropriate then use promisification
let db;
export function OpenDB(dbPath) {
return new Promise(function (resolve, reject) {
db = new sqlite3.Database(dbPath, err => err ? resolve() : reject(err));
});
}
export function CreateTable(tableName, tableColumns) {
return new Promise(function (resolve, reject) {
db.run('CREATE TABLE IF NOT EXISTS ' + tableName + ' (' + tableColumns + ')',
err => err ? resolve() : reject(err));
});
}
And usage
OpenDb(dbPath)
.then(() => CreateTable("sampleTable", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL"))
.then(() => CreateTable("sampleTable2", "Column1 TEXT NOT NULL, Column2 TEXT NOT NULL"))
.then(() => console.log('Complete'))
.catch(err => console.error(err));
#Aikon Mogwai's answer is good. My suggestion using async/await:
async function createTables() {
let db = new sqlite3.Database(tbpath);
await create_table(db, 'CREATE TABLE IF NOT EXISTS sampleTable(Column1 TEXT NOT NULL, Column2 TEXT NOT NULL)')
await create_table(db, 'CREATE TABLE IF NOT EXISTS sampleTable2(Column1 TEXT NOT NULL, Column2 TEXT NOT NULL)')
db.close();
logger.info("Created database.")
}
async function create_table(db: any, query: any) {
return new Promise(function (resolve, reject) {
db.run(query, function (err: any, rows: any) {
if (err) {
console.log("promise rejected")
return reject(err);
}
resolve(rows);
});
});
}
The new sqlite3.Database(tbpath) doesn't have to be awaited. At least I don't have problems with that.
Related
I'm trying to translate my old mysql app to Postgresql, it was very difficult to connect to the server, but when i think it worked, this message appears on insomnia.
The message
I tried using different methods that i found on Google but they didn't work for me.
I think that the problem is how i'm connecting to the server.
I'm new using postgresql.
const { Pool, Client } = require("pg")
const config = require("../config")
const connection = new Pool({
host: config.postgresql.host,
user: config.postgresql.user,
password: config.postgresql.password,
database: config.postgresql.database,
port: "5432",
ssl: true
})
function list(table) {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM ${table}`, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
function get(table, id) {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM ${table} WHERE id=${id}`, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
function insert(table, data) {
return new Promise((resolve, reject) => {
connection.query(`INSERT INTO ${table} SET ${data}`, (err, result) => {
if (err) return reject(err)
resolve(result)
})
})
}
function update(table, data) {
return new Promise((resolve, reject) => {
connection.query(
`UPDATE ${table} SET ${data} WHERE id=${data.id}`,
(err, result) => {
if (err) return reject(err)
resolve(result)
}
)
})
}
const upsert = async (table, payload) =>
new Promise((resolve, reject) => {
connection.query(
`INSERT INTO ${table} SET ${payload} ON DUPLICATE KEY UPDATE ${payload}`,
(error, data) => {
console.log("UPDATE DATA: ", data)
if (error) {
return reject(error)
}
resolve(data)
}
)
})
function query(table, query, join) {
let joinQuery = ""
if (join) {
const key = Object.keys(join)[0]
const val = join[key]
joinQuery = `JOIN ${key} ON ${table}.${val} = ${key}.id`
}
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM ${table} ${joinQuery} WHERE ${table}.${query}`,
(err, res) => {
if (err) return reject(err)
resolve(res[0] || null)
}
)
})
}
module.exports = {
list,
get,
upsert,
query
}
The insert query is wrong, Please change it to the below syntax. You cannot use SET in insert. SET should be used in update.
Wrong:
connection.query(`INSERT INTO ${table} SET ${data}`, (err, result)
Insert query syntax:
INSERT INTO TABLE_NAME (column1, column2, column3,...columnN)
VALUES (value1, value2, value3,...valueN);
I have an Airtable base that I can retrieve records from (see code below), but I'd like to get the value for other fields besides just "Location". Using "console.log('Retrieved: ', record.get('Location'));", how do I modify this line to include in the output the field values for a field called "Size" in addition to the "Location" field? I tried "console.log('Retrieved: ', record.get('Location', 'Size'));", but that didn't work.
Here's an excerpt from my code:
// Lists 3 records in Bins
base('Bins').select({
// Selecting the first 3 records in Grid view:
maxRecords: 3,
view: "Grid view"
}).eachPage(function page(records, fetchNextPage) {
// This function (`page`) will get called for each page of records.
records.forEach(function(record) {
console.log('Retrieved: ', record.get('Location'));
});
// To fetch the next page of records, call `fetchNextPage`.
// If there are more records, `page` will get called again.
// If there are no more records, `done` will get called.
fetchNextPage();
}, function done(err) {
if (err) { console.error(err); return; }
});
OUTPUT
Retrieved 170000118
Retrieved 170000119
Retrieved 170000120
I found this repo to help in when I tried to product situations like this.
A wrapper for common functions for accessing data on an airtable.com database. All queries return promises.
Here is how it works if you want to avoid using an npm package. But ultimatly the jist of it is to either use request or some short of promise fulfillment menthod to retrive the Records.
import Airtable from 'airtable'
import _ from 'lodash'
const ENDPOINT_URL = 'https://api.airtable.com'
let API_KEY // Can only set the API key once per program
export default class AirTable {
constructor({apiKey, databaseRef}) {
if(!API_KEY) {
API_KEY = apiKey
Airtable.configure({
endpointUrl: ENDPOINT_URL,
apiKey: API_KEY
});
}
this.base = Airtable.base(databaseRef)
this.get = {
single: this.getSingleRecordFrom.bind(this),
all: this.getAllRecordsFrom.bind(this),
match: this.getAllMatchedRecordsFrom.bind(this),
select: this.getRecordsSelect.bind(this)
}
this.insert = this.createRecord.bind(this)
this.add = this.insert
this.create = this.insert
this.update = this.updateRecord.bind(this)
this.set = this.update
this.remove = this.deleteRecord.bind(this)
this.delete = this.remove
this.destroy = this.remove
this.rem = this.remove
}
async createRecord({tableName, data}) {
return new Promise((resolve, reject) => {
this.base(tableName).create(data, (err, record) => {
if (err) {
console.error(err)
reject()
return
}
console.log("Created " + record.getId())
resolve(record)
})
})
}
async updateRecord({tableName, id, data}) {
return new Promise((resolve, reject) => {
this.base(tableName).update(id, data, (err, record) => {
if (err) {
console.error(err)
reject()
return
}
console.log("Updated " + record.getId())
resolve(record)
})
})
}
async deleteRecord({tableName, id, data}) {
return new Promise((resolve, reject) => {
this.base(tableName).destroy(id, (err, record) => {
if (err) {
console.error(err)
reject()
return
}
console.log("Deleted " + record.getId())
resolve(record)
})
})
}
async getSingleRecordFrom({tableName, id}) {
console.log(tableName, id)
return new Promise((resolve, reject) => {
this.base(tableName).find(id, function(err, record) {
if (err) {
console.error(err)
reject(err)
}
resolve(record)
})
// console.log(record);
})
}
async getAllRecordsFrom(tableName) {
return this.getRecordsSelect({tableName, select: {} })
}
async getAllMatchedRecordsFrom({tableName, column, value}) {
return this.getRecordsSelect({tableName, select: {filterByFormula:`${column} = ${value}`} }) // TODO: validate input
}
async getRecordsSelect({tableName, select}) {
return new Promise((resolve, reject) => {
let out = []
this.base(tableName).select(select).eachPage((records, fetchNextPage) => {
// Flatten single entry arrays, need to remove this hacky shit.
_.map(records, r => {
_.forOwn(r.fields, (value, key) => { // If array is single
if(_.isArray(value) && value.length == 1 && key != 'rooms') {
r.fields[key] = value[0]
}
});
})
out = _.concat(out, records)
fetchNextPage();
}, (err) => {
if (err) {
console.error(err)
reject(err)
} else {
// console.log(JSON.stringify(out, null, 4))
// console.log("HI")
resolve(out)
}
})
})
}
}
Hope this Makes sense, Also trying to make an API-Proxy fetching a whole table or even use Express to fetch record id's as arrays can work as well
You can use this code line.
records.forEach(function(record) {
console.log('Retrieved: ', record.get('Location') + ' ' + record.get('Size'));
});
I am new to NodeJS and JavaScript. I am badly stuck in a problem:
I want to generate QR image of 'some text' and after generating it, I want to query my MySQL database and insert the image to database.
Problem is that QRCode.toDataURL of SOLDAIR module goes in running state and query is called before the QR image is returned from the .toDataUrl function.
Hence it results in error.
I tried everything, promises, nested promises, counters, if statements etc., but I am unable to find a solution.
My code:
router.post('/generateTicket', (req,res) => {
const query1 = `SELECT * FROM booking ORDER BY bookingID DESC LIMIT 1`;
const query2 = `INSERT INTO ticket (ticket_image,BookingID) SET ?`;
let bookingID;
let count;
let ticket_data = {};
Promise.using(mysql.getSqlConn(), conn => {
conn.query(query1).then(resultOfQuery1 => {
bookingID = resultOfQuery1[0].BookingID;
count = resultOfQuery1[0].PeopleCount;
console.log("ID = " + bookingID + " people count = "+count);
promiseToCreateQRcode().then(function (URLfromResolve) {
console.log("the url is " + URLfromResolve );
}).catch(function (fromReject) {
console.log("Rejected "+ fromReject);
}); // catch of promise to create QR
}).catch(err => {
res.json({ status: 500, message: 'Error Occured in query 1 ' + err });
}); // catch of query 1
});
});
var opts = {
errorCorrectionLevel: 'H',
type: 'image/png',
rendererOpts: {
quality: 0.3
}
};
let promiseToCreateQRcode = function () {
let QRImage;
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) throw err
console.log("\n"+url+"\n");
QRImage = url;
});
if (QRImage)
resolve(QRImage);
else
reject("error occured in url");
});
};
As u can see, the program jumps to if statement and the QR image is not generated yet, hence it goes in "reject":
Try this,
let promiseToCreateQRcode = function () {
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err){
reject(err); // or some message
} else {
resolve(url);
}
});
});
};
This way promise will be resolved only when toDataURL returns QR image.
Have a look at How do I convert an existing callback API to promises?. You need to call resolve or reject in the asynchronous callback!
function promiseToCreateQRcode() {
return new Promise(function(resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) {
reject(err);
} else {
console.log("\n"+url+"\n");
resolve(url);
}
});
});
}
Using this extra QRImage variable like you did cannot work.
I am not sure how to pass data to a promise function like below.
I need to parss it a JSON object that is then used in my MSSQL query, but if i remove the function around the promise, it says that data is undefined.
The code below is functional, I am just looking for a cleaner way to do this.
routes.post('/save', function(req, res){
var insert = function(data) {
sql.connect(config)
.then(pool => {
return pool.request()
.input('first_name', sql.VarChar(100), data.firstName)
.input('last_name', sql.VarChar(100), data.lastName)
.query('INSERT INTO Uncomplete_registration (first_name, last_name) VALUES (#first_name, #last_name)')
}).then(result => {
console.dir(result)
}).catch(err => {
console.dir(err)
})
sql.on('error', err => {
console.dir("other error: " + err);
})
}
insert(req.body.data);
});
I am sure there is a better way to do this but I am not sure how...
Try this
routes.post('/save', function(req, res){
var data = req.body.data;
sql.connect(config)
.then(pool => {
return pool.request()
.input('first_name', sql.VarChar(100), data.firstName)
.input('last_name', sql.VarChar(100), data.lastName)
.query('INSERT INTO Uncomplete_registration (first_name, last_name) VALUES (#first_name, #last_name)')
}).then(result => {
console.dir(result)
}).catch(err => {
console.dir(err)
})
sql.on('error', err => {
console.dir("other error: " + err);
})
});
This makes data into a local variable, which is essentially what your function is doing. The promise .then/.catch can then access it as a closure variable.
routes.post("/save", function (req, res) {
var data = req.body.data;
sql.connect(config)
.then(pool => {
return pool.request()
.input("first_name", sql.VarChar(100), data.firstName)
.input("last_name", sql.VarChar(100), data.lastName)
.query("INSERT INTO Uncomplete_registration (first_name, last_name) VALUES (#first_name, #last_name)");
}).then(result => {
console.dir(result);
}).catch(err => {
console.dir(err);
});
sql.on("error", err => {
console.dir("other error: " + err);
});
});
Switched from Atom code editor to PHP Storm, and a lot of my code is being highlighted when I use promises with the following message: Expression statement is not assignment or call
Here is an example of some highlighted code:
getTickers.bitfinex = function() {
var counter = 0,
promises = []
//highlighted code begins here
new Promise(function(resolve, reject) {
request.get({
url: 'https://api.bitfinex.com/v1/symbols'
},
function(err, res, body) {
if (err) {
console.log(err, 'bitfinex api error')
reject(err, 'bitfinex api error')
}
if (!err) {
body = JSON.parse(body)
var symbols = []
body.forEach(function(symbol) {
symbol = 't' + symbol.toUpperCase()
symbols.push(symbol)
})
resolve(symbols)
}
})
})
.then((symbols) => {
var symbolsStr = symbols.join()
request.get({
url: 'https://api.bitfinex.com/v2/tickers?symbols=' + symbolsStr
},
function(err, res, body) {
body = JSON.parse(body)
if (err) {
console.log(err, 'bitfinex api error')
}
if (body[0] == 'error') {
console.log(body, 'bitfinex api error')
}
if (body[0] !== 'error') {
body.forEach(function(ticker) {
var promise = new Promise(function(resolve, reject) {
var currencyPair = ticker[0].replace("t", ""),
splitCurrencies = currencyPair.match(/[A-Z]{3}/g),
baseCurrency = splitCurrencies[0],
quoteCurrency = splitCurrencies[1]
Ticker.create({
currency_pair: baseCurrency + '-' + quoteCurrency,
base_currency: baseCurrency,
quote_currency: quoteCurrency,
last: ticker[7],
volume: ticker[8],
native_currency_pair: ticker[0],
exchange: 'bitfinex',
time: new Date().getTime()
}, function(err, document) {
if (err) {
reject(err)
}
if (document) {
counter++
resolve()
}
})
})
promises.push(promise)
})
Promise.all(promises)
.then(() => console.log(counter + ' bitfinex tickers updated'))
.catch((err) => console.log(err, 'bitfinex update error'))
}
})
})
.catch((err) => console.log(err))
//highlight ends here
}
What can I add or change in the code to make this correct so the warning goes away?
In order to disable this WebStorm-specific code inspection go to
WebStorm -> Preferences -> Editor -> Inspections
and uncheck the box under JavaScript -> JavaScript validity issues
that has the label, "expression statement which is not assignment or call".
If you would like to actually change your code to fix these errors, see this answer.