executing direct query in controller in loopback - node.js

I have started working in loopback 4.I have created a default CRUD controller with basic CRUD operations which can get 'the table data', 'the table record for particular id' etc.. what I need now is I want to execute my own query for this table. How to write a query in controller and execute it?
/* below is the default function to get table data*/
#get('/customers', {
responses: {
'200': {
description: 'Array of customers model instances',
content: {
'application/json': {
schema: {type: 'array', items: {'x-ts-type': Customers}},
},
},
},
},
})
async find(
#param.query.object('filter', getFilterSchemaFor(Customers)) filter?: Filter,
: Promise<Customers[]> {
if (limit > 100) limit = 100; // your logic
return await this.CustomersRepository.find(filter);
}
the type of code I want is,
Execute(dataset, sqlstatement); //is that available?

Support for executing raw database queries was added recently by the pull request #2681, this functionality is provided by Repository method execute.
Please note that they query format is connector-specific. For example, if you are using MySQL database, then you can write the following query:
await this.CustomersRepository.execute(
// the query template, use "?" for variables to AVOID SQL INJECTIONS ATTACKS!
'SELECT TOP ? * FROM CUSTOMERS',
// the values to use for variables
[limit]);

Related

Perform check on record before performing update with Prisma

I'm creating the backend for a simple app which allows users to create, update, and delete products. Using Express as my framework, with Postgres as my DB and Prisma, which I'm new to, as my ORM. Users and products have a one-to-many relationship. Prisma's documentation states that when updating a record, you should use the update method - so to update the name of a product with a given ID, your code would look something like this:
export const updateProduct = async (req, res) => {
const [productID, newProductName, userID] = [req.params.id, req.body.name, res.locals.user.id];
const product = await prisma.product.update({
where: {
id: productID,
},
data: {
name: newProductName
}
});
res.status(200);
res.json(product);
};
However, there's a problem here - I'm not checking to see that the product with the provided ID belongs to the user that has sent the request to update it. I have the ID of the user who has sent the request in the variable userID, and each product in the DB has a field belongsToID which is set to the ID of the user that the product belongs to. I should theoretically therefore be able to modify my query to get the product with the specified ID and a matching belongsToID like so:
export const updateProduct = async (req, res) => {
const [productID, newProductName, userID] = [req.params.id, req.body.name, res.locals.user.id];
const product = await prisma.product.update({
where: {
id: productID,
belongsToID: userID
},
data: {
name: newProductName
}
});
res.status(200);
res.json(product);
};
That, however, does not work - I get the following error: Type '{ id: any; belongsToID: any; }' is not assignable to type 'ProductWhereUniqueInput'. Object literal may only specify known properties, and 'belongsToId' does not exist in type 'ProductWhereUniqueInput'.ts(2322).
It appears that when trying to do a 'findUnique', Prisma doesn't allow non-unique fields to be used in the query (even if the combination of both fields is unique, as is the case here). I do get that logically, my query doesn't make much sense - the ID alone is already enough to find a unique entry without the second field, so in that sense, the second field is totally redundant. Yet how else am I meant to check that the belongsToID is what it should be before updating the record? Is there somewhere else within the object passed to .update where I can provide a check to be performed on the retrieved record before performing the update?
I believe that creating an index would allow me to query for both fields at once - but why should I have to create an index when the ID (which is already indexed) alone is all I need to retrieve the record I need? What I really need is a way to perform a check on a retrieved record before performing the update when using Prisma.table_name.update(), not a way to query for something with a unique combination of fields.

Best way to programmatically add tables to node and express app with Sequelize

I have been doing some research on this for a bit but can't seem to find the right answer. I am building a personal bugetting application with node, Express and Sequelize. In order to give users as much flexibility as possible, I want the app to dynamically generate tables for user budgets. Users can create as many budgets as they want, and add up to 10 or 12 columns. I was thinking of using a Sequelize raw query, but dynamically generating the query is messy and I'm not sure it's very good practice. Should I use a migration and the umzug library? The thing is I'm still pretty new to server side development and databases so I just need a bit of guidance on this. Here is my current raw query. I haven't tested it yet as I have been building out other core components of the app.
/* Handle dynamic budget table creation and queries */
const Db = require('./lib/Db.js');
module.exports = class Budget extends Db
{
/**
* Create a new budget table
* #param {String} name - budget name
* #param {Object} columns - object of column names and their values
* #param {String} user - user name
* #param {Number} userId - user id
*/
async createNewBudget(name, columns, user, userId)
{
let query = `CREATE TABLE ${name}_budget (`;
for (let key in columns) {
query += `${key} NUMERIC, `;
}
query += ")";
await this.db.sequelize.query(query);
let insert = `INSERT INTO ${name}_budget(`;
for (let key in columns) {
insert += `${key}, `;
}
insert += ") VALUES (";
for (let key in columns) {
insert += `${columns[key]}, `;
}
insert += ")";
await this.db.sequelize.query(insert);
}
}
The Db class is a simple class that makes available the sequelize instance:
/* Base class for all classes interacting with the database via raw queries */
module.exports = class Db
{
constructor()
{
this.db = require('../models/index.js');
}
}
I have these files in my lib directory. I just have a feeling that the way I'm going about this isn't that good. Any helpful suggestions would be greatly appreciated.
I'm a little curious as to why you want a user to be able to create new tables... I think you should be using migration to setup your original database, and think it through to the point where users have id's, then you have a user_budget table that is a many to many connection to budget an array of options after that, database design does take some planning but it is not rocket science and if/when you don't get it right, it's not too hard to change... postgres, mySQL etc are great at handling scads of rows efficiently and many relationships, but i think you might be creating a bunch of technical debt and non-scalable solution to create new tables for new budgets, that is unnecessary with an RDBMS. You are creating a new table for something that could just be a couple rows in a well designed DB
We can define the model in one file, say models/budget.js:
module.exports = function (sequelize, DataTypes) {
const Budget = sequelize.define('budget', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
category: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
name: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
...,
version: {
type: DataTypes.INTEGER,
defaultValue: 0,
allowNull: false,
},
}, {
version: true,
paranoid: true
});
return Budget;
};
Then create a "migrations" file which loads the model into the DB:
'use strict';
const models = require('../models');
module.exports = {
up: function (queryInterface) {
return queryInterface.createTable(models.Budget.tableName, models.Budget.rawAttributes);
},
down: function (queryInterface) {
return queryInterface.dropTable(models.Budget.tableName);
},
};

Can make graphql query to be strongly types with typescript?

I'm using typescript and graphql and every time I want to send request to my graphql I need to write a query.
My question is there is anyway to use type/interface to create the query?
for example take a look at this interface:
interface Document {
id: string;
name: string;
author: {
name: string;
}
}
The graphql query for this is
query document {
id
name
author {
name
}
}
and I use axois to get the data:
const data = await axios.get("/graphql", { query });
Is there easy way to get the data using strongly typed? something like:
const data = await axois.get('/graphql', { fields: ['id', 'name', 'author.name'] })
And typescript will throw an error if some string from fields doesn't include in the interface.
axios.get can take a generic which will provide the types on the return type. An example should make it clear. Using your code above
// vvvvvvvv==> your expected return data
const result = await axios.get<Document>("/graphql", { query });
// data will be strongly typed (but NOT checked)
result.data.id; // => string
result.data.author.name; // => string
For more info check axios' index.d.ts file.

Update only one row in sequelize

I am using Sequelize as ORM along with express.js Below is my minimalistic table structure.
Id status phone
1 0 09620701828
2 0 09620701828
Now when an api request is to make on an end-point then I have to update status for last id belonging to a particular phone that I am getting from request. Raw MySql query for which will be UPDATE table SET status=1 where phone='09620701828' ORDER BY id DESC LIMIT 1;
How I can achieve the same using Sequelize update method. Below is what I have tried
models.customerLeadFeedback.update(
{status: 1},
{
where: {phone : '09620701828'},
order: [['id', 'DESC']],
limit : 1
}).then(function () {
res.sendStatus(200);
})`
But order by clause is not working for above and updating status for id 1. Can anyone help me with this without using raw query in sequelize.
It would appear that Sequelize'sModel#update function doesn't support ordering - see the docs at http://sequelize.readthedocs.io/en/v3/api/model/#updatevalues-options-promisearrayaffectedcount-affectedrows
If you really want to target the row by ordering, you could fetch the row first, then update it:
models.customerLeadFeedback.findOne(
{status: 1},
{
where: {phone : '09620701828'},
order: [['id', 'DESC']]
}).then(function (record) {
return record.update({status: 1});
}).then(function (record) {
res.sendStatus(200);
});
It's less efficient, using two queries instead of one, but currently looks like your only option if you don't want to use raw queries.

Query Parse.com migrated database pointer relationship with Mongoose

Context
So we have migrated from Parse.com to an hosted MongoDB database. Now I have to write a script that queries our database directly (not using Parse).
I'm using nodejs / mongoose and am able to retrieve these documents.
Problem
Here is my schema so far:
var StorySchema = new mongoose.Schema({
_id: String,
genre: String
});
var ActivitySchema = new mongoose.Schema({
_id: String,
action: String,
_p_story: String /* Also tried: { type: mongoose.Schema.Types.ObjectId, ref: 'Story' } and { type: String, ref: 'Story' }*/,
});
I would like to write a query that fetches theses documents with the related Story (stored as a pointer).
Activity
.find({
action: 'read',
})
.exec(function(error, activities) {
activities.forEach(function(activity) {
// I would like to use activity._p_story or whatever the mean to access the story here
});
});
Question
Is there a way to have the fetched activities populated with their story, given that the _p_story field contains Story$ before the object id?
Thanks!
One option I have been looking at is the ability to create a custom data type for each pointer. The unfortunate side is Parse treats these as 'belongsTo' relationships and but does not store the 'hasMany' relationship that Mongoose wants for populate(). But once this is in place you can easily do loops to get the relational data. Not ideal but works and is what populate is really doing under the hood anyways.
PointerTypeClass.js -> This would work for populating the opposite direction.
var Pointer = function(mongoose) {
function PointerId(key, options) {
mongoose.SchemaType.call(this, key, options, 'PointerId');
}
PointerId.prototype = Object.create(mongoose.SchemaType.prototype);
PointerId.prototype.cast = function(val) {
return 'Pointer$' + val;
}
return PointerId;
}
module.exports = Pointer;
Also be sure mongoose knows about the new type by doing mongoose.Schema.Types.PointerId = require('./types/PointerTypeClass')(mongoose);
Lastly. If you are willing to write some cloudcode you could create the array of ids for your populate to know about the objects. Basically in your Object.beforeSave you would update the array of the id for the relationship. Hope this helps.

Resources