Can you build a query in prisma without executing it? - javascript

I have a find method in my api that takes these parameters
-limit (optional)
-select (optional)
-sort (optional)
-skip (optional)
In MongoDB you can build a query like this :
let query = model.find(query);
if(limit) {
query.limit(limit)
}
if(skip) {
query.skip(skip)
}
// ....
let result = await query.exec();
Is there a similar option in Prisma ?

I am not Prisma user, but seems like you can build config parameters beforehand like
let query = {
skip: skip,
take: limit
};
prisma.model.findMany(query)

Related

Sequelize select from select

I want join and filter raw query
const projects = await sequelize.query('SELECT * FROM projects + SQL MAGIC', {
model: Projects,
mapToModel: true,
type: QueryTypes.SELECT,
});
In this query replace projects table with select+magic:
const dinamic_where = {id: 1}
const projects = await Projects.findAll(
where: { ..dinamic_where },
include: [{ model: Organization }],
)
So generated query shall become
SELECT fields,... FROM (SELECT * FROM projects + SQL MAGIC) JOIN organization WHERE organization.id = 1;
bind not suitable because of dinamic_where can contan different number of fields.
If you need to modify FROM part, I think you need to use a little more low level access to Sequelize.
There is a function queryGenerator.selectQuery however this takes string as FROM table name meaning if I do
selectQuery('(...SQL MAGIC)', options, Projects)
This will generate a query string as
SELECT ... FROM '(...SQL MAGIC)' ...
FROM query is taken as a string value which is not a valid SQL.
So, a little hacky workaround.
const customQuery = selectQuery('FROM_TO_BE_REPLACED', options, Projects)
// Use JS string replace to add dynamic SQL for FROM.
// If it is Postgres, double quotes are added by queryGenerator.
// If MySQL, it would be ``
customQuery.replace('"FROM_TO_BE_REPLACED"', '(...SQL MAGIC)')
All in action.
const Model = require("sequelize/lib/model");
const parentOptions = {
where: {
id: 1,
key: 'value'
},
include: [Organization]
};
// This is required when the inline query has `include` options, this 1 line make sure to serialize the query correctly.
Model._validateIncludedElements.bind(Projects)(parentOptions);
const customQuery = sequelize.getQueryInterface()
.queryGenerator
.selectQuery('FROM_TO_BE_REPLACED', parentOptions, Projects);
const fromQuery = '(SELECT * FROM SQL MAGIC)';
const projects = await sequelize.query(customQuery.replace('"FROM_TO_BE_REPLACED"', fromQuery),
{
type: QueryTypes.SELECT
}
);

Handling Optional Query Params in NodeJS API [duplicate]

I want to send in response some data according to searching by query parameters (using .find function of mongoose) from the client side. What do I need to do is a search according to the parameters received?
What I mean is :
I may receive
localhost:5000/admin/customers?customer_id=1&customer_email=abc#gmail.com
I could have used this code to send results according to this query :
Customer.find({
customer_id = req.query.customer_id,
customer_email = req.query.customer_email,
}, (err,docs)=> {
res.json(docs);
})
or
just
localhost:5000/admin/customers?customer_id=1
I could have used this code to send results according to this query :
Customer.find({
customer_id = req.query.customer_id
}, (err,docs)=> {
res.json(docs);
})
or
may be
localhost:5000/admin/customers?no_of_items_purchased=15
I could have used this code to send results according to this query :
Customer.find({
no_of_items_purchased = req.query.no_of_items_purchased
}, (err,docs)=> {
res.json(docs);
})
But what I want is to use .find function on anything received from query params. Like a general code to achieve this.
PS: Also please help with : "How to filter req.query so it only contains fields that are defined in your schema ?"
You can create a query variable to keep the field that you want to filter.
Suppose that your Customer model structure is:
{
customer_id: ...,
customer_name: ...,
customer_email: ...,
no_of_items_purchased: ...
}
Then your code will be:
let {customer_id, customer_name, customer_email, no_of_items_purchased} = req.query;
let query = {};
if (customer_id != null) query.customer_id = customer_id;
if (customer_name != null) query.customer_name = customer_name;
if (customer_email != null) query.customer_email = customer_email;
if (no_of_items_purchased != null) query.no_of_items_purchased = no_of_items_purchased;
let result = await Customer.find(query);
Just pass request.query as a parameter directly on find method:
Customer.find(request.query)

Prisma - Optimistic Update using LastUpdated field, is it possible to express with Prisma's safe query builder syntax?

I am working with a PostgreSQL database using Prisma. I have a bulk update command which I want to fail if any of the records have changed since my last read.
My schema:
model OrderItem {
id String #id #default(uuid()) #db.Uuid
quantity Int
lastUpdated DateTime #updatedAt #map("last_updated")
##map("order_item")
}
I have written a query which works, but I built the query manually rather than using Prisma's safe query builder tools.
My query:
type OrderItemType = {
id: string;
quantity: number;
lastUpdated: Date;
}
type OrderItemUpdateDataType = {
quantity: number;
}
const updateByIds = async (
orderItemIdLastUpdatedTuples: ([OrderItemType['id'], OrderItemType['lastUpdated']])[],
orderItemUpdateData: OrderItemUpdateDataType,
) => {
// Optimistic concurrency - try updating based on last known "last updated" state. If mismatch, fail.
await prisma.$transaction(async (prisma) => {
// TODO: Prefer prisma.$queryRaw. Prisma.join() works on id[], but not on [id, lastUpdated][]
const idLastUpdatedPairs = orderItemIdLastUpdatedTuples
.map(([id, lastUpdated]) => `(uuid('${id}'), '${lastUpdated.toISOString()}')`)
.join(', ');
const query = `SELECT * FROM order_item WHERE (id, last_updated) in ( ${idLastUpdatedPairs} )`;
const items = await prisma.$queryRawUnsafe<OrderItem[]>(query);
// If query doesn't match expected update count then another query has outraced and updated since last read.
const itemIds = orderItemIdLastUpdatedTuples.map(([id]) => id);
if (items.length !== orderItemIdLastUpdatedTuples.length) {
throw new ConcurrentUpdateError(`Order Items ${itemIds.join(', ')} were stale. Failed to update.`);
}
await prisma.orderItem.updateMany({
where: { id: { in: itemIds } },
data: orderItemUpdateData,
});
});
};
This function wants to update a set of items. It accepts a list of tuples - id/lastUpdated pairs. It starts an explicit transaction, then performs an unsafe SELECT query to confirm the items to affect haven't been updated, then updates. This is following the guidance of Prisma's docs here - https://www.prisma.io/docs/concepts/components/prisma-client/transactions#interactive-transactions-in-preview
I was hoping to achieve the same results using prisma.$queryRaw rather than prisma.$queryRawUnsafe or even using implicit transactions rather than an explicit transaction wrapper. I wasn't able to find a syntax for expressing "where in tuple" using either of these approaches, though.
I am able to express what I want using implicit transactions when updating a single record. An example here would look like:
const { count } = await prisma.orderItem.updateMany({
where: { id, lastUpdated },
data: orderItemUpdateData,
});
and when using an explicit, safe query I stumbled on joining the array of tuples properly.
From the Prisma documentation, https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access#tagged-template-helpers, there exists a Prisma.join command (which happens implicitly when using their tagged template helper syntax) but I wasn't able to generate a valid output when feeding it an array of tuples.
Did I miss anything? Does Prisma support joining a tuple using their safe query template syntax?

Modify default find service in Strapi

I have 2 collection types in my Strapi setup: product and review where a product has many reviews.
I want to add 2 new fields to the response of /products and /products/:id:
averageRaing: number
totalReviews: number
I want to override the default find service to implement this, but I am unable to find the source code for strapi.query("product").find(params, populate) to override it.
If possible, I need this done in a single query rather than making multiple queries.
So far I have:
find(params, populate) {
return strapi.query("product").model.query(db => {
// I want the same query as when I run `strapi.query("product").find(params, populate)`
});
},
But I am unsure of how to handle the params and populate in the exact same way that .find(params, populate) does.
After digging into the source code, I found a solution:
const { convertRestQueryParams, buildQuery } = require("strapi-utils");
function find(params, populate) {
const model = strapi.query("product").model;
const filters = convertRestQueryParams(params);
const query = buildQuery({ model, filters });
return model
.query((qb) => {
const totalReviewsQuery = strapi.connections
.default("reviews")
.count("*")
.where("product", strapi.connections.default.ref("products.id"))
.as("total_reviews");
const averageRatingQuery = strapi.connections
.default("reviews")
.avg("rating")
.where("product", strapi.connections.default.ref("products.id"))
.as("average_rating");
query(qb);
qb.column("*", totalReviewsQuery, averageRatingQuery);
})
.fetchAll({
withRelated: populate,
publicationState: filters.publicationState,
})
.then((results) => results.toJSON());
}

Knex JS - update & select in the same query (simultaneously)

Using Knex JS - Is it possible to get all elements from the row being updated, I would like update and select to be done in a single query. (currently update only returns the id of the row being updated).
let query = await knex('items').select('id', 'customerId', 'itemId').where('id', id).update({ inactive: true })
Thanks!
If using postgres, then use .returning()
const query: any = await knex('items')
.returning('id', 'customerId', 'itemId')
.where('id', id)
.update({ inactive: true });
here is the knex documentation
https://knexjs.org/#Builder-returning

Categories

Resources