I'm writing a command line utility to initialize a postgres database by dropping all tables, creating the postgis extension, then initialize my models.
The extension needs to be created because my models depend on it.
I'd like to know the "Sequelize way" to do this. For example, would I do this in a seeder then call sequelize db:seed ?
The SQL looks like this:
-- Drop all tables
drop schema public cascade;
create schema public;
-- Add PostGIS support
CREATE EXTENSION postgis;
// Edit: Rereading your question I see I missed the explicit request for the Sequelize way to do this - the below might be helpful but is probably not relevant.
I have wrestled with this problem in the apps I've built. The simplest solution (below) is a shell script with a JS script for the Sequelize calls. In other apps I use a number of Python classes along with a couple of JS scripts. This is crude, but flexible and it works.
run.sh:
#!/bin/bash
DB_NAME="sqpg"
DB_USER="sequelize"
DB_PW="sequelize"
DB_SCHEMA="s00"
export BLUEBIRD_DEBUG=1
sudo -u postgres psql -c "DROP SCHEMA IF EXISTS $DB_SCHEMA CASCADE" "$DB_NAME"
sudo -u postgres psql -c "CREATE SCHEMA $DB_SCHEMA AUTHORIZATION $DB_USER;" "$DB_NAME"
sudo -u postgres psql -c "CREATE EXTENSION \"uuid-ossp\" SCHEMA $DB_SCHEMA;" "$DB_NAME"
node populate-db.js
populate-db.js:
'use strict';
var Sequelize = require('sequelize');
sq_options = { /* ... */ };
var sq = new Sequelize('sqpg', 'sequelize', 'sequelize', sq_options);
var models = {
Foo: sq.define('Foo', {
/* ... * /
},
Bar: sq.define('Bar', {
/* ... */
}
};
models.Foo.belongsToMany(models.Bar, { through: 'foo_bar' });
models.Bar.belongsToMany(models.Foo, { through: 'foo_bar' });
sq.sync({ force: true })
.then(a_function_to_create_some_instances)
.then(a_function_to_create_some_more_instances)
.catch(function(err) {
console.warn('Rejected promise: ' + err);
console.warn(err.stack);
})
.finally(function() {
sq.close();
})
Related
I have following setup for my project, using the pg node-postgres package:
The simple table 'tmp' looks like this:
According to jsonORG and the postgres docs the object:
{"foo" : true}
is syntactically valid JSON, and when using the pgAdmin Query-tool with:
UPDATE tmp SET data = '{"foo": false}' WHERE id = '1'
works fine, but when i try updating my table through my express route using pg:
router.put('/updateTMP', (req, res) => {
// I use dummies in this case instead of req.body.someKey for testing purposes
let dummyJSON = {"foo":true};
let dummyID = 1;
pg.query(`UPDATE tmp SET data = '${dummyJSON}' WHERE id = '${dummyID}'`, (errUpdate, responseUpdate) => {
if (!errUpdate) { // NO ERROR
res.json({success: true, message: responseUpdate});
}
else { // ERROR
console.log(dummyJSON);
console.log(errUpdate);
res.json({success: false, message: errUpdate});
}
})
})
I get the following error from the database:
error: invalid input syntax for type json
I've tried the to_json function from postgresql and the to-json package from npm in the express route - all with the same negative result.
Am i missing some fundamental understanding or is it some formating/quoting-issue?
Thanks in advance for your ideas! ;)
ps: And yes - I've read through this, and that article..
I had the same problem. Try converting your JS object to string using JSON.stringify() before passing it into the query as pg won't always do that for you automatically.
See this issue on GitHub for more info.
I'm using Commander.js to write my own CLI. I managed to write commands that work individually but now I need to implement sub commands but the docs are a bit vague and confusing so I haven't been able to figure out.
What I want is the connect command to connect to a MongoDB instance and when it has done that proceed to execute the get command. How can I achieve this?
These are the commands and package.json:
./package.json:
{
...
"main": "./commands/my-cli.js",
"bin": "./commands/my-cli.js",
...
}
./commands/my-cli.js:
const commander = require('commander');
const program = new commander.Command();
const connect = require('./my-cli-connect');
const get = require('./my-cli-get');
// Initialize each command
connect(program);
get(program);
./commands/my-cli-connect.js:
function connect(program) {
program
.command('connect <db> <username> <password>', 'Connects to a database')
.action((db, username, password) => {
MongoClient.connect(<some-mongo-url>, {useNewUrlParser: true}, (err, connection) => {
assert.equal(null, err, 'Failed to connect to MongoDB instance');
// Continue here with the get command
});
});
program.parse(process.argv);
}
module.exports = connect;
./commands/my-cli-get.js:
function get(program) {
program
.command('get <collection>')
.option('-q,--query <query>', 'Search terms', jsonParser, {})
.description('Returns documents from a MongoDB collection')
.action(action);
program.parse(process.argv);
function action(collection, options) {
// This never runs
console.log('hello world');
}
}
module.exports = get;
Running my-cli --help shows these available commands:
...
Commands:
connect <db> <username> <password> Connects to a database
help [cmd] display help for [cmd]
Example command execution that should call both connect and then get when connect has finished connecting:
$ my-cli connect myDb myUser myPass get users -q '{"email": "foo#gmail.com"}'
Right now the get command's action function never runs.
I'm creating a CLI using Nodejs and commander and i need to implement an option/command like this.
--create user --f-name="Kevin"
I tried various options but could get it working
#!/usr/bin/env node
const program = require("commander");
function collect(val, memo) {
memo.push(val);
return memo;
}
program.version("0.0.1", "-v, --version")
.option(
"-c, --create <items>",
"Create user",
collect,
[]
).parse(process.argv);
console.log(' collect: %j', program.create );
This works only when i execute with like this --create user,a,d,v and it gives out an array collect: ["user,a,d,v"]. Any idea on how to implement this using Commander.js
Try this script:
program
.option('-c, --create', 'Create User')
.option('-un, --user-name <type>', 'Username');
program.parse(process.argv);
console.log(program.userName, `userName: ${program.userName}`)
And execute like this from the terminal:
node command.js --create user --user-name=NameUser
I have a test setup in which mongoimport and mongoexportcommands are used to populate an exiting mongoDB database, say testDB from folder testDump.
The problem occurs for the files which are empty in the folder from which testDB is initially populated and then restored.
Eg. a collection file called abcInstance.json is empty in the testDump.
$ cat abcInstance.json
[]
Now when I run some test, this collection gets populated in testDB but at the end when I restore all collections from the testDump folder using mongoimport command it fails for empty files.
So, I am trying to drop those collections using mongo and spawn command.
if (statSync(collectionFile).size === 4) {
const options = [
'testDB',
'--eval',
'"db.abcInstance.drop()"'
];
const dropDB = spawn('mongo', options, { stdio: 'inherit' });
if (dropDB.status !== 0) {
throw new Error('failed to drop collection ');
}}
But this is also failing and I cannot figure out the error.
I have tested that the same command runs successfully on command line:
$ mongo testDB --eval "db.abcInstance.drop()"
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017/alyneKickStartDB
MongoDB server version: 3.6.4
true
Any idea where I am going wrong?
So, I was able to solve the problem of executing the mongo command by a slightly different approach as stated here.
Basically, the problem I figured out was that my parent process was exiting without waiting for the child process to finish execution as both spawn and exec are asynchronous functions. So I modified my code as follows:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec)
async func test () {
const res = await exec('mongo testDB --eval "db.abcInstance.drop()" --quiet')
return { res }
}
Now, when I call this test() function, my collection is successfully dropped.
Does anybody know of any problem with this approach or a better way?
I am new to knex migrations and for the past 2 days I have been struggling to get it working but nothing happen. I am trying to run my migrations programmatically using the knex.migration object.
First using the cli, I create a migration file in the migrations directory. Here is its content:
exports.up = function(knex, Promise) {
return Promise.all([
knex.schema.createTable('users', function (table) {
table.increments('id').primary();
table.string('username');
table.string('password');
table.string('email');
table.string('name');
table.timestamp('date');
}),
]);
};
exports.down = function(knex, Promise) {
};
Then from my code I initialize the Knex object:
var knex = Knex({
client:'sqlite3',
connection:{
filename: './knex.sqlite'
}
});
Then I execute the migration:
knex.migrate.latest().then(()=>{
// console.log()
}).catch(err =>{
//
});
But absolutely nothing happens. My migration file is never executed and there is no error or warning message. So I don't know where to look at to start searching for the problem. When I look at my sqlite database, I can see that tables knex_migrations, knex_migrations_lock and sqlite_sequence have been created.
So what I am doing wrong here? Is there something I am missing?
Thanks for any suggestion
There's no requirement to use the CLI tools. Sometimes it's not possible to use it due to its limitations and in this case it's indeed possible to use the migration API directly, like so:
const knex = require('knex')({
// Here goes the Knex config
});
const migrationConfig = {
directory: __dirname + './migrations',
}
console.info('Running migrations in: ' + migrationConfig.directory);
knex.migrate.latest(migrationConfig).then(([batchNo, log]) => {
if (!log.length) {
console.info('Database is already up to date');
} else {
console.info('Ran migrations: ' + log.join(', '));
}
// Important to destroy the database, otherwise Node script won't exit
// because Knex keeps open handles.
knex.destroy();
});
There was two issues in the original question:
The migration directory was not specified - in this case Knex is not smart and will simply not do anything instead of throwing an error. Most likely the default used by Knex is not right so it's best to specify it.
knex.destroy() was missing. In this case, the script will never exit because Knex keeps open handles on the database, so it just looks like it's stuck doing nothing.
The above script also outputs more log info to see what's exactly happening.
Knex migrations are supposed to run by Knex CLI,FYI: https://knexjs.org/#Migrations
As your code described, I found a strange issue:
knex.migrate is actually undefined, it's not a property of knex.