How to deal with readonly arguments from DataLoader - (GraphQL + Apollo in NextJS) - graphql

I have a loader function in order to fetch chefs from a database. So that loader receive an array of ids and what's is strange is that the ids have a readonly type.
When I try to pass that read-only type to the database query, it gives an error.
How can I fix the type definition?
Source code: https://github.com/LauraBeatris/graphql-with-nextjs/blob/master/pages/api/loader.ts

I fixed that according to #DanielRearden comment.
The function that the DataLoader instance receives uses generic types, so we're able to pass a type to the ids argument and then use it inside of the whereIn knex method.
new DataLoader((ids: string[]) => (
databaseClient
.table("chefs")
.whereIn("id", ids)
.select("*")
.then(rows => ids.map(id => rows.find(row => row.id === id)))
))

Related

Simple write to Dexie without knowing the schema

Is it possible to write an entire object to Dexie without knowing the schema?
I just want to do this:
var db = new Dexie(gameDataLocalStorageName);
db.version(1).stores({
myData: "gameData"
});
db.myData.put(gameData);
console.log(db.myData.get('gameData'));
But I'm getting the following error:
Unhandled rejection: DataError: Failed to execute 'put' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.
DataError: Failed to execute 'put' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.
The error is because you've specified the schema to use inbound key "gameData", i.e. require each object to have the property "gameData" as its primary key.
If you don't need to have the primary key within the objects, you can declare the schema as {myData: ""} instead of {myData: "gameData"}. By doing so, you will need to provide the primary key separate from the object in calls to db.myData.put().
See docs for inbound vs non-inbound keys and detailed schema syntax
var db = new Dexie(gameDataLocalStorageName);
db.version(1).stores({
myData: ""
});
Promise.resolve().then(async () => {
await db.myData.put(gameData, 'gameData'); // 'gameData' is key.
console.log(await db.myData.get('gameData'));
}).catch(console.error);
Since we're changing the primary key here, you will need to delete the database in devtools before this would work.

hotchocolate throws error when using UseFiltering() on a field

I have a pretty simple setyp where I'm putting graphql over an entityframework datacontext (sql server).
I'm trying to get filtering to work. I've tried adding .UseFiltering() to a field descriptor like so...
descriptor.Field(t => t.AccountName).Type<NonNullType<StringType>>().UseFiltering();
But it causes this error on startup...
HotChocolate.SchemaException: 'Unable to infer or resolve a schema
type from the type reference Input: System.Char.'
I assume I'm doing something wrong somewhere...
"UseFiltering" is supposed to be used to filter data which represents a collection of items in some way (IQueryable, IEnumerable, etc).
For instance, if you have users collection and each user has AccountName property you could filter that collection by AccountName:
[ExtendObjectType(Name = "Query")]
public class UserQuery
{
[UseFiltering]
public async Task<IEnumerable<User>> GetUsers([Service]usersRepo)
{
IQueryable<User> users = usersRepo.GetUsersQueryable();
}
}
In that example the HotChocolate implementation of filtering will generate a number of filters by user fields which you can use in the following way:
users(where: {AND: [{accountName_starts_with: "Tech"}, {accountName_not_ends_with: "Test"}]})
According to your example: the system thinks that AccountName is a collection, so tries to build filtering across the chars the AccountName consists of.

Laravel different use of where clause

I want to ask about some feature in Laravel, I'm working with some old code written by someone else and I want to understand why it is written this way:
$users = Users::all();
$results = $users->where('age', '>','30')->get();
My question is how can 'where' clause be used with the '$users' variable? This works fine and no error is given and it returns the required results. But as far as i know, 'where' clause can be used like:
Classname::where()->get()
Does the User model implements some feature or use something to be able to call 'where' clause this way? When i try to do the same but with a new model i'm creating I get
"Type error: Too few arguments to function Illuminate\\Support\\Collection::get()
How can 'where' clause be used with the '$users' variable?
The where clause can be used because the all() method returns a Collection, and the where() and get() methods are available on the Collection class.
Does the User model implements some feature or use something to be able to call 'where' clause this way?
Each Eloquent model serves as a query builder which will make you able to add constraints and receive the results with the get() method afterwards.
// Collection::get() is diferent with QueryBuilder::get()
$builder = Users::query(); // you got QueryBuilder object
$builder->where('age', '>','30'); // you got QueryBuilder object
$list = $builder->get(); // you got Collection object
$list->where('age', '>','30'); // you got Collection object
// Collection object has 'get', but it require argument.
// QueryBuilder object has 'get' too, but do not require argument.

GraphQL Dataloader - Global variable with load() function

I'm using graphql with dataloader. I have this call inside a type. My problem is that when I call "categoryPhotoLoader" I want to pass user_id as a global param for every _id. Is this possible, or I have to create a concat (${_id}_${user_id}) and get inside the dataloader the first user_id of the keys? (split the string and get the user_id part of the first id)
async photoS3({_id, user_id}, _, {categoryPhotoLoader}) {
return categoryPhotoLoader.load(`${_id}_${user_id}`);
}
I would like something like that
async photoS3({_id, user_id}, _, {categoryPhotoLoader}) {
return categoryPhotoLoader.load(_id, {user_id: user_id});
}
Dataloader keys do not have to be Strings, they can be Arrays, Objects or other data types. So you can do:
categoryPhotoLoader.load({ _id, user_id })
and this Object will be passed to your batch function. If you do this, you'll want to provide a cacheKeyFn to your Loader's constructor so that dataloader can tell when two keys are equivalent. In this case, it would be simple enough to do something like:
new DataLoader(batchLoadFn, {
cacheKeyFn: ({ _id, user_id }) => ${_id}${user_id},
})
Be wary of using JSON.stringify since you want to ensure the correct order of properties in the string.

Convert collection to array of strings

I'm trying to export a query result in Laravel 5 to Excel, but I'm getting the error
Object of class stdClass could not be converted to string
when I use the code below:
$equipements=Equipement::all();
$equipements=collect($equipements)->toArray();
Excel::create('Inventaire',function($excel) use ($equipements){
$excel->sheet('Page 1',function ($sheet) use($equipements){
$sheet->fromArray($equipements);
});
})->export('xlsx');
But that's not the result I want, I want to specify columns from different tables. Is there any way to convert a collection to array of strings the method collection->torray return array of objects that's not what I want.
When sending $equipements to the fromArray() method, you're passing an array to that method. But you're sending the array of all equipements and each single equipement is an instance of the Equipement model.
To send each equipements to it's own row, use the following code:
Excel::create('Inventaire', function($excel) {
$excel->sheet('Page 1', function ($sheet) {
$equipements = Equipement::all();
foreach ($equipements as $equipement) {
$sheet->fromArray($equipement);
}
});
})->export('xlsx');
One thing to notice is that the all() method of a model already returns a Collection so no need to collect() that data again.

Resources