Loopback get model from datasource with discoverSchemas - node.js

I've been testing loopback for couple hours now and everyhing is working fine when i'm creating models manually and modify the model.json created to match my oracleDb columns name.
But i'm getting stuck when i want to get a model from my oracle db to avoid to write the 50 columns manually..
I made a test with a table called "atest" and contains a column "name" and "id".
It's create the atest.json , and add this in model-config.json:
"Atest": {
"dataSource": "oracledb",
"public": true
}
But in my atest.json there is just a "undefined"..
My discover-models.js file :
'use strict';
const loopback = require('loopback');
const promisify = require('util').promisify;
const fs = require('fs');
const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);
const mkdirp = promisify(require('mkdirp'));
const DATASOURCE_NAME = 'oracledb';
const dataSourceConfig = require('./server/datasources.json');
const db = new loopback.DataSource(dataSourceConfig[DATASOURCE_NAME]);
discover().then(
success => process.exit(),
error => { console.error('UNHANDLED ERROR:\n', error); process.exit(1); },
);
async function discover() {
// It's important to pass the same "options" object to all calls
// of dataSource.discoverSchemas(), it allows the method to cache
// discovered related models
const options = { relations: false };
// Discover models and relations
const atestSchemas = await db.discoverSchemas('ATEST', options);
// Create model definition files
await mkdirp('common/models');
var response = await writeFile(
'common/models/atest.json',
JSON.stringify(atestSchemas['ATEST'], null, 2)
);
console.log(response);
// Expose models via REST API
const configJson = await readFile('server/model-config.json', 'utf-8');
console.log('MODEL CONFIG', configJson);
const config = JSON.parse(configJson);
config.Atest = { dataSource: DATASOURCE_NAME, public: true };
await writeFile(
'server/model-config.json',
JSON.stringify(config, null, 2)
);
}
My oracle connection is working fine, i don't get it, any idea?

Add a console.log after you invoke discoverSchemas:
// Discover models and relations
const atestSchemas = await db.discoverSchemas('ATEST', options);
console.log(atestSchemas);
You should see that the key is not just 'ATEST', as referenced later with atestSchemas['ATEST']. The key is 'SCHEMA_NAME.ATEST' (SCHEMA_NAME will vary as per your environment).
If you target the appropriate key, you should get what you're looking for.

Related

API Request passing ID fetched from mongodb

I´m a Java Dev so I need help from NodeJS guys!
Task: create a script that retrieves '_id', 'document', and 'corporateName' from MongoDB, then take the retrieved '_id', and pass it as a parameter to an API request. The last part should be taking 'document', 'corporateName' + 'client_id', 'client_secret' and export it into a single csv file.
It might be a very simple script! Therefore I´ve done this till now:
const {MongoClient} = require('mongodb');
const uri = "mongodb+srv://<privateInfo>/";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("merchant-profile");
const ecs = database.collection("merchant_wallet");
const api = `https://<prodAPI>/v1/merchant/wallet/${id}/oauth2`;
const ecOpt = {_id: 1, document: 1, corporateName: 1};
const credOpt = {client_id: 1, client_secret: 1};
const ec = ecs.find({}).project(ecOpt);
let id = ec.forEach(id => cred._id);
const cred = api.find({}).project(credOpt);
await cred.forEach(console.dir);
} finally {
await client.close();
}
}
run().catch(console.dir);
I´m trying to understand how can I take '_id' fetched in 'ec' and pass it as a param to the 'cred' call.
This would already be awesome!
If you could help me out with the CSV issue as well it would be perfect.
So I don´t want just the answer, but understand how to do this.
Thank you all in advance!
This is the way I found to do it:
const { default: axios } = require("axios");
const { MongoClient } = require("mongodb");
const uri = "mongodb+srv://admin:sLKJdsdRp4LrsVtLsnkR#pp-core-prd.fy3aq.mongodb.net/";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("merchant-profile");
const ecs = database.collection("merchant_wallet");
const data = [];
await ecs.find({}).forEach(async function teste(response) {
const id = response._id;
const api = `https://api.pedepronto.com.br/v1/merchant/wallet/${id}/oauth2`;
try{
const res = await axios.get(api);
data.push({client_secret: res.data[0].client_secret, client_id: res.data[0].client_id})
}catch(e){
console.log(e);
}
})
} finally {
await client.close();
}
}
run().catch(console.dir);
It iterates over the find method and appends the fetched id to the uri.

How to use cls-hooked unmanaged transactions?

I'm writing tests with jest and sequelize and I need to keep my database clean for every test, so I want to set a transaction for every test and then rollback at the end.
This is what I've got, but it wont pass the transaction to my tests:
beforeEach(async () => {
this.transaction = await db.sequelize.transaction();
});
test('Database should be clean', async () => {
const role = await db.role.create({
name: 'someName',
});
expect(role.id).toBe(1);
});
afterEach(async () => {
await this.transaction.rollback();
});
Sequelize is already setted to use cls
const Sequelize = require('sequelize');
const config = require('../../config/config.js');
const cls = require('cls-hooked');
const namespace = cls.createNamespace('testing-namespace');
Sequelize.useCLS(namespace);
const sequelize = new Sequelize(config);
...
It would be really helpful if somenone could explain me how to use unmanaged transactions with cls-hooked.
I managed to keep my database clean by using umzug to run seeds programatically, this is my code:
const { db } = require('../models');
const Umzug = require('umzug');
const path = require('path');
const umzug = new Umzug({
migrations: {
path: path.join(__dirname, './../../seeders'),
params: [db.sequelize.getQueryInterface()],
},
logging: false,
});
beforeEach(async () => {
const reverted = await umzug.down({ to: 0 });
const executed = await umzug.up();
});
I tried to use umzug v3 (beta), but it didn't work, so I used the stable version 2. This approach isn't as performant as I'd like, but gets the job done.

ObjectionJS - Group models in a data layer file

I have a NodeJS app running fastify with fastify-objectionjs.
For tidiness, I'd like to group all models in a single file called _main.js, where I export an array of the models inside the models folder.
Since the fastify-objectionjs registration requires an array of models, I thought I could just import the array from my _main.js and feed it as it is to the registration function.
But ObjectionJS is telling me that The supplied models are invalid.
/app.js (node entry point)
const fastify = require('fastify')({
logger: true
})
const knexConfig = require('./knexfile')
const dataLayer = require('./models/_main')
fastify.register(require('fastify-objectionjs'), {
knexConfig: knexConfig,
models: dataLayer
})
// Also tried:
// fastify.register(require('fastify-objectionjs'), {
// knexConfig: knexConfig,
// models: [dataLayer]
// })
/models/_main.js
const User = require('./user.model')
var dataLayer = [User]
module.exports = dataLayer
// Also tried without var:
// module.exports = {
// dataLayer: [
// User
// ]
// }
/models/user.model.js
const Knex = require('knex')
const connection = require('../knexfile')
const { Model } = require('objection')
const knexConnection = Knex(connection)
Model.knex(knexConnection)
class User extends Model {
static get tableName () {
return 'users'
}
}
module.exports = { User }
I can't seem to find a problem in the file flow, but if I create the models array on the fly, the app starts smoothly:
/app.js (node entry point)
const fastify = require('fastify')({
logger: true
})
const knexConfig = require('./knexfile')
const User = require('./models/user.model') // changed
fastify.register(require('fastify-objectionjs'), {
knexConfig: knexConfig,
models: [User] // changed
})
Any idea why this isn't working?
Thanks in advance for your time.
Found the gotcha, I just needed to use destructuring in the require of User, like this:
/models/_main.js
// BAD
// const User = require('./user.model')
// GOOD
const { User } = require('./user.model')
module.exports = [User]
Works like a charm.
Useful question that explains the difference:
Curly brackets (braces) in node require statement

Parse Server edit Relations on Object very slow

I've got the following function which works as expected on Parse Server cloud code, however it's painfully slow.
The nested for loops which are internally calling queries and save functions are undoubtedly the root cause.
How can I refactor this code so that there is some async processing or even better what methods are there to remove / edit the relations on an object, the documentation around this is very poor.
ClientLabels.applyClientLabels = async (req, res) => {
const { clients, labels } = req.params;
const user = req.user;
const objectIds = clients.map((client) => client.objectId);
const clientSaveList = [];
const clientClass = Parse.Object.extend('Clients');
const query = new Parse.Query(clientClass);
query.containedIn("objectId", objectIds);
const queryResult = await query.find({ sessionToken: user.getSessionToken() })
try {
for (const client of queryResult) {
const labelRelation = client.relation('labels');
const relatedLabels = await labelRelation.query().find({ sessionToken: user.getSessionToken() });
labelRelation.remove(relatedLabels);
for (const label of labels) {
label.className = "ClientLabels";
const labelRelationObj = Parse.Object.fromJSON(label)
labelRelation.add(labelRelationObj);
};
clientSaveList.push(client);
};
const saved = await Parse.Object.saveAll(clientSaveList, { sessionToken: user.getSessionToken() })
res.success(saved);
} catch (e) {
res.error(e);
};
}
Explanation of some weirdness:
I am having to call Parse.Object.fromJSON in order to make the client side label object a ParseObjectSubClass and allow operations on it such as adding relations.
You cannot use include on a relation query as you would with a Pointer, so there needs to be a query for relations all on it's own. An array of pointers was ruled out as there is going to be an unknown amount of labels applied.
There are a few things that can be done: (1) The creation of labels in the inner loop is invariant relative to the outer loop, so that can be done one time, at the start. (2) There's no need to query the relation if you're just going to remove the related objects. Use unset() and add to replace the relations. (3) This won't save much computation, but clientSaveList is superfluous, we can just save the query result...
ClientLabels.applyClientLabels = async (req, res) => {
const { clients, labels } = req.params;
const objectIds = clients.map((client) => client.objectId);
let labelObjects = labels.map(label => {
label.className = "ClientLabels";
return Parse.Object.fromJSON(label)
});
const query = new Parse.Query('Clients');
query.containedIn("objectId", objectIds);
const sessionToken = req.user.getSessionToken;
const queryResult = await query.find({ sessionToken: sessionToken })
try {
for (const client of queryResult) {
client.unset('labels');
client.relation('labels').add(labelObjects);
};
const saved = await Parse.Object.saveAll(queryResult, { sessionToken: sessionToken })
res.success(saved);
} catch (e) {
res.error(e);
};
}

Custom service in feathersjs

I try to write a custom service, but it doesn't work at all. I try to post a request and make two update queries in the collections, but i will not work at all
this is my code
// Initializes the `bedrijven` service on path `/bedrijven`
const createService = require('feathers-mongoose');
const createModel = require('../../models/bedrijven.model');
const hooks = require('./bedrijven.hooks');
const filters = require('./bedrijven.filters');
module.exports = function() {
const app = this;
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'bedrijven',
Model,
paginate
};
// Initialize our service with any options it requires
app.post('/bedrijven/setfavo', function(req, res) {
Promise.all([
app.service('bedrijven').update({
owner: req.body.userid
}, {
favo: false
}),
app.service('bedrijven').update(req.body._id, {
favo: true
})
]);
});
app.use('/bedrijven', createService(options));
// Get our initialized service so that we can register hooks and filters
const service = app.service('bedrijven');
service.hooks(hooks);
if (service.filter) {
service.filter(filters);
}
};
Make sure this file is included in your main app.js file.
Something like:
const bedrijven = require('./bedrijven/bedrijven.service.js');
app.configure(bedrijven);
Is there a reason you don't want to use feathers generate service? It would take care of these questions for you.

Resources