how to perform like and ilike quey against enum datatype column in prisma - enums

How to perform like and ilike queries against the ENUM datatype column in Prisma?
Is this possible in Prisma, If anyone knows please let me know?
I have tried several ways how to implement this in Prisma. But it doesn't work for me
const {role} = req.query
await this.prisma.user.findMany({
where:{
role: { contains: role, mode: 'insensitive']=}
}
}
In my user table, the column role is enum datatype. if the query string is not matched with one of the role enums, Prisma throws the error.
enum Role {
Admin
Engineer
Sales_User #map("Sales User")
Customer
}
In my scenario, the query string role may and may not be matched with the enum Role. if the query string role will not be matched with one of the Role enums, Prisma throws the errors.

Related

How to force a filter on server side to a graphql query?

Imagine the condition that I have a query called "users" that returns all the users and these users can be associated with one or more companies, so I have a type UserCompanies (I need it because it saves some more information beyond the relation). I'm using Prisma and I need to force a filter that returns only users that are of the same company as the requester.
I get the information of the company from JWT and need to inject this to the query before sending it to Prisma.
So, query should be like that:
query allUsers {
users {
name
id
status
email
userCompanies{
id
role
}
}
}
and on server side, I should transform it to: (user where is ok, just changing args)
query allUsers {
users(where: {
userCompanies_some: {
companyId: "companyId-from-jwt"
}
}) {
name
id
status
email
userCompanies(where: {
companyId: "companyId-from-jwt"
}){
id
role
}
}
}
I'm seeing a few resolutions to this, but I don't know if it is the best way:
1 - Using addFragmentToInfo, does the job to put conditions on the query, but if the query has a usercompanies already set, it gives me a conflict. Otherwise, it works fine.
2 - I can use an alias for the query, but after DB result I will need to edit all the results in array to overwrite the result.
3 - don't use info on Prisma and filter in js.
4 - Edit info(4th parameter) of type GraphqlResolveInfo

combining resolvers for interface and concrete types

For some reason I'm having a hard time figuring out how to combine resolvers for a GraphQL interface and a type that implements said interface.
Say I have the following schema:
interface IPerson {
id: ID!
firstName: String!
lastName: String!
}
type ClubMember implements IPerson {
...IPerson fields
memberType: String!
memberSince: DateTime!
}
type StaffMember implements IPerson {
...IPerson fields
hireDate: DateTime!
reportsTo: StaffMember
}
extend type Query {
people(ids: [Int!]): [IPerson]
}
A full ClubMember query with all fields, such as:
query {
people(ids: [123456,234567,345678]) {
id
firstName
lastName
... on ClubMember {
memberType
memberSince
}
}
}
would produce a response like the following:
[
{
"id": 123456,
"firstName": "Member",
"lastName": "McMemberface",
"memberType": "VIP",
"memberSince": "2019-05-28T16:05:55+00:00"
},
...etc.
]
I've used makeExecutableSchema() from apollo-server with inheritResolversFromInterfaces: true, and I want to be able to make use of default resolvers for each interface/type by having the model classes backing IPerson, ClubMember, etc. return objects with only the fields relevant to each type, i.e., the model class for IPerson fetches only the fields required by IPerson, etc. That is, the response above would execute 2 SQL statements:
SELECT id, firstName, lastName FROM Contacts WHERE id IN(?);
and
SELECT contactId, memberType, memberSince FROM Members WHERE contactId IN(?);
Of course, I could get all the data in one SQL statement by doing a JOIN at the database level, but I really want to have one (and only one) way of resolving the fields required by IPerson, and let the other types augment that data with their own resolvers.
My question is, do I need to "join" the resulting objects together myself in the resolver for the people query type? E.g.
const resolvers = {
Query: {
people: function( parent, args, context, info ) {
let persons = context.models.Person.getByIds( args.ids );
let members = context.models.Member.getByIds( args.ids );
/*
return an array of {...person, ...member} where person.id === member.id
*/
}
}
}
Or is there some way that Apollo handles this for us? Do I want something like apollo-resolvers? The docs on unions and interfaces isn't super helpful; I have __resolveType on IPerson, but the docs don't specify how the fields for each concrete type are resolved. Is there a better way to achieve this with Dataloader, or a different approach?
I think this question is related to my issue, in that I don't want to fetch data for a concrete type if the query doesn't request any of that type's fields via a fragment. There's also this issue on Github.
Many thanks!
Edit:
__resolveType looks as follows:
{
IPerson: {
__resolveType: function ( parent, context, info ) {
if ( parent.memberType ) {
return 'ClubMember';
}
...etc.
}
}
}
This problem really isn't specific to Apollo Server or even GraphQL -- querying multiple tables and getting a single set of results, especially when you're dealing with multiple data models, is going to get tricky.
You can, of course, query each table separately and combine the results, but it's not particularly efficient. I think by far the easiest way to handle this kind of scenario is to create a view in your database, something like:
CREATE VIEW people AS
SELECT club_members.id AS id,
club_members.first_name AS first_name,
club_members.last_name AS last_name,
club_members.member_type AS member_type,
club_members.member_since AS member_since,
null AS hire_date,
null AS reports_to,
'ClubMember' AS __typename
FROM club_members
UNION
SELECT staff_members.id AS id,
staff_members.first_name AS first_name,
staff_members.last_name AS last_name,
null AS member_type,
null AS member_since,
staff_members.hire_date AS hire_date,
staff_members.reports_to AS reports_to
'StaffMember' AS __typename
FROM staff_members;
You can also just use a single table instead, but a view allows you to keep your data in separate tables and query them together. Now you can add a data model for your view and use that to query all "people".
Note: I've added a __typename column here for convenience -- by returning a __typename, you can omit specifying your own __resolveType function -- GraphQL will assign the appropriate type at runtime for you.

In GraphQL, how to control DB query by client query?

I learn to use GraphQL these days. In my opinion, To build a query, I need to build three parts:
Schema
type User{
id String
name String
cars [Car!]!
}
type Car{
id String
}
type Query{
user(id: String): User
}
DB Query function
{
user: async function ({id}) {
const user = await DB.user.findOne({id});
const userCars = await DB.car.find({userId: id});
user.cars = userCars;
return cars;
}
}
Client query
{
user (id: "1") {
name
cars {
id
}
}
}
That query returns a user's name and his cars. The DB query function always query for cars.
But sometimes I just need user's info:
{
user (id: "1") {
name
}
}
I don't want to query for cars, so I hope to make my DB query function can auto choose to query for cars or not.
How can I do this?
GraphQL.js will support either object properties or methods for resolver functions; this is discussed in its page on Object Types.
One way to deal with this is just to insert an anonymous function directly into the returned object:
{
user: async function ({id}) {
const user = await DB.user.findOne({id});
user.cars = () => DB.car.find({userId: id});
return cars;
}
}
Another is to create a wrapper object with a class that provides the id property and (asynchronous, lazy) cars method; some examples of this are in the GraphQL.js documentation. This approach tends to work in most GraphQL implementations in most languages.
I think you looking into auto-creating/mapping from GraphQL query into db query.
Every queries are db/project specific, so you should create this mapping. You can easily do that with graphql-fields package.
There is copy pasted WHY section from the package:
An underlying REST api may only return fields based on query params.
{
user {
profile {
firstName
},
id
}
}
should request /api/user?fields=profile,id
while
{
user {
email
}
}
should request /api/user?fields=email
Implement your resolve method like so:
resolve(root, args, context, info) {
const topLevelFields = Object.keys(graphqlFields(info));
return fetch(`/api/user?fields=${topLevelFields.join(',')}`);
}
It's best to avoid squeezing it all into one resolver function. Instead, create a separate ObjectType for Cars which has its own fields and its own resolver function. This way, the car query is only called if that field is requested.
In case you are using a RDS, join monster and data louder can help optimize performance of your queries.
Join Monster which relies on generating one big join query and also solve the problem of only requesting exactly the fields you need from the DB
Cached and Batched SQL Data Source which uses facebook's dataloader under the hood - it wont solve the problem of which fields to query (although the example uses knex, which will make that a lot easier), but instead it can cache and batch your queries

Apollo / GraphQL Same Query with Different Parameters

How would I go about having an Apollo query with different parameters. Let's say my app has the concept of users and I want my API to be able to find a user either by ID or username.
It doesn't seem I can do this
type Query {
user(id: ID!): User
user(username: String!): User
}
do I have to resort to something like this
type Query {
userById(id: ID!): User
userByUsername(username: String!): User
}
Create a new input type with ID and username as fields and specify it as parameter.
type Query {
getUser(filters:UserFilter): User
}
input UserFilter{
ID : Int,
Username : String
}
Query should look like this ...
Query{
getUser(filters:{ID:123123})
}
OR for username filter
Query{
getUser(filters:{Username:"Tom"})
}
I believe your second option is the best however you could do something like this.
type Query {
user(id: ID, username: String): User
}
If the parameters are not required then your resolver could use some logic to determine if it should get the user based on the id or the username.
if (args.id) {
return getUserById(args.id)
} else {
return getUserByUsername(args.username)
}
However for reasons gone over in this talk https://youtu.be/pJamhW2xPYw?t=750 (maybe see at about 12:30), I believe your second option is a better design choice. Hope that helps!

How to search string values in GraphQL

How do you query using GraphQL in a manor similar to SQL's like operator?
Example: What users have a first name starting with jason?
select * from users where first_name like "jason%"
The short answer is: you don't.
The longer answer is that you have to write that code yourself. GraphQL isn't a database query language like SQL, it's an application query language. What that means is that GraphQL won't let you write arbitrary queries out of the box. It will only support the types of queries defined in your GraphQL schema.
If you want to be able to write a query that contains like, you have to
a) declare that in the schema, and
b) write a resolve function that fetches the data
For example, you could have this schema:
type Query {
users(firstName: String!): [User]
}
type User {
firstName: String
lastName: String
}
You would have to define the following resolve function for the users field:
{
Query: {
users(root, args){
return sql.raw('SELECT * FROM `users` WHERE `firstName` LIKE ?', args.firstName);
}
}
}
And finally write this query to get a list of firstName and lastName of all the users that match your search criteria:
{
users(firstName: 'jason%'){
firstName
lastName
}
}
Here's a post I wrote a while ago that clarifies some of the concepts around GraphQL: https://medium.com/apollo-stack/how-do-i-graphql-2fcabfc94a01
And here's a post that explains the interplay between GraphQL schemas and resolve functions: https://medium.com/apollo-stack/graphql-explained-5844742f195e
Not sure if this is relevant to you because you want it to start with "jason" (ie would return "jason bourne" but not "bourne jason") but I recently came across a way to query GraphQL in a "%Like%" manner. For your use case it would look something like this:
export const allUsersQuery = `
query allUsers($UserName: String!){
allUsers(
filter: {first_name_contains: $UserName}
) {
id
first_name
...INSERT_OTHER_FIELDS_HERE...
}
}
`;
FWIW: I did this using a GraphCool BAAS. I don't think you were using GraphCool because GraphCool doesn't allow "_" in variable names.
Hope this helps someone down the line :)

Resources