Typeorm: Check if a property is either value 1, 2, 3 or n - repository

I want to get all tasks that have a certain role. I have an array of strings for which I want to get the tasks.
Query:
return this.createQueryBuilder('task')
.select(this.baseSelect)
.where('task.role = :role', { role }) // What here?
.getMany();
This code of course only gets the tasks for which the role is that one value.
How can I check multiple values?

For searching in multiple roles you can use the IN operator:
OLD VERSION of TypeORM
return this.createQueryBuilder('task')
.select(this.baseSelect)
.where('task.role IN(:roles)', {roles: [role1, role2, role3]});
.getMany();
NEW VERSION of TypeORM
As mentioned by user Christophe Geers, In the new version, you will have to use the spread syntax.
return this.createQueryBuilder('task')
.select(this.baseSelect)
.where('task.role IN(:...roles)', {roles: [role1, role2, role3]});
.getMany();

Related

How to delete multiple items with GraphQL?

I am new in GraphQL.
How can I write a delete mutation to delete multiple items (more than one ID) in GraphQL?
I use scaphold.io.
You can batch multiple mutations in the same request to the GraphQL server using GraphQL aliases.
Let's say this is how you delete one Item:
mutation deleteOne {
deleteItem(id: "id1") {
id
}
}
Then this is how you can delete multiple items in one request:
mutation deleteMultiple {
id1: deleteItem(id: "id1") {
id
}
id2: deleteItem(id: "id2") {
id
}
# ... and so on
id100: deleteItem(id: "id100") {
id
}
}
It's helpful to know that multiple mutations in one request run sequentially in the stated order (from top to bottom). You can also run multiple queries in one request the same way, and multiple queries in one request run in parellel.
If you want to run say 1000 mutations, it might be better to batch them in 10 groups of 100.
More information and another example can be found in this FAQ article as well as the official GraphQL docs.
I think that good solution would be to create a method (mutation) that accepts array of e.g. IDs, that are further used to batch delete multiple records from the database.
mutation deleteUsers($userIds: [Int!]!) {
deleteUsers(userIds: $userIds) {
...
}
}
Then, in the resolver you could use the userIds parameter to perform an SQL query like DELETE FROM users WHERE id IN userIds, where userIds of course should be correctly replaced (escaped), depending on how you interact with the database.

How to insert an item into a sequence using Sequelize, or How to manage an ordering attribute

I have an entity with a sequence attribute, which is an integer from 1-N for N members of the list. They are polyline points.
I want to be able to insert into the list at a given sequence point, and increment all the items at that point or beyond in the sequence to make room for the new item, and likewise if I delete then decrement everything above so we still have nice sequence ordering with no missing numbers.
There is a REST interface in this of course, but I dont want to hack about with that, I just want sequelize to magically manage this sequence number.
I am assuming I need to get hold of some "before insert" and "after delete" hooks in sequelize and issue some SQL to make this happen. Is that assumption correct or is there some cooler way of doing it.
I havent tested this, but this appears to be the solution, which is barely worth comment.
I know the modelName, and name==the attribute name,
options.hooks={
beforeInsert: function(record, options) {
return self.models[modelName].incrementAfter(name,record[name]);
},
afterDelete: function(record, options) {
return self.models[modelName].decrementAfter(name,record[name]);
}
}
and then added to my extended model prototype I have
incrementAfter:function(field,position){
return this.sequelize.query("UPDATE "+this.tableName+" SET "+field+" = "+field+"+1 WHERE "+field +" >= "+position);
},
decrementAfter:function(field,position){
return this.sequelize.query("UPDATE "+this.tableName+" SET "+field+" = "+field+"-1 WHERE "+field +" >= "+position);
},

Dapper - Bulk insert of new items and get back new IDs

I am using dapper to add multiple new students in one db hit using this method:
db.ExecuteAsync(#"INSERT Student(Name,Age) values (#Name,#Age)",
students.Select(s => new { Name = s.Name, Age = s.Age })
);
But the problem I don't have the new ids.
Can I make one db hit and still some how get the new ids ?
And if not, what is the most efficient way of performing such bulk insert ?
That is not a bulk insert; it is basically just shorthand that unrolls the loop; although interestingly (perhaps) it is possible to ask it to pipeline that sequence if "MARS" is enabled on your connection. Without the pipeline, it is basically shorthand for:
foreach(var obj in students.Select(s => new { Name = s.Name, Age = s.Age }))
{
await db.ExecuteAsync(#"INSERT Student(Name,Age) values (#Name,#Age)", obj);
}
in which case, you might as well use Query or ExecuteScalar to fetch the SCOPE_IDENTITY().
With the pipeline, it is more subtle; it does the same thing, but with multiple outstanding commands at a time (it only awaits when the backlog is full, or when all of the commands have been issued).
Bulk insert does not return ids. You could consider using a table valued parameter and using INSERT with the OUTPUT clause to insert an entire DataTable of data at a time (getting the identities in the process), but on the negative side: it does involve using DataTable ;p
Disclaimer: I'm the owner of the project Dapper Plus
As Marc answered, there is no BulkInsert in Dapper.
However, it's possible to achieve it with Dapper Plus (The library is commercial)
You need to specify in the mapping which column is an identity (so the id get populated on the entity automatically)
// MAP once
DapperPlusManager.Entity<Invoice>().Identity(x => x.InvoiceID);
connection.BulkInsert(invoices, x => x.InvoiceMeta, x => x.InvoiceItems);
It even possible to propagate automatically the identity by specifying the identity propagation to true
// MAP once
DapperPlusManager.Entity<Invoice>().Identity(x => x.InvoiceID, true);
connection.BulkInsert(invoices, x => x.InvoiceMeta, x => x.InvoiceItems);
In this case, InvoiceItem will automatically have the InvoiceID also populated.
You can learn more about identity propagation here: https://dapper-plus.net/getting-started-identity-propagation

Eloquent: Get pages based on user role

I have a User, Role & Page setup, all with many-to-many relationships and the pivot tables setup in the usual fashion (role_user, page_role), along with the eloquent methods to attach a model to the pivot tables.
My idea is to allow a user to have many roles, and a page can be accessed by many roles.
However now I'd like to return a collection where I have my users details and then the pages they're allowed to access.
The closest I have got is:
return User::find( Auth::user()->id )->with('roles.pages')->first()->roles;
Now this returns each role the user has, and each page that the role can access. Which is correct, however I have duplication on the pages part.
How would I go about getting only a list of pages the user is able to access with no duplication?
Cheers
Read that answer to get you on the track: HasManyThrough with one-to-many relationship
Only for your setup you need to adjust the query - join 2 pivot tables (and make sure they represent real data, ie no rows referencing non-existing models):
// User model
// accessor so you can access it like any relation: $user->pages;
public function getPagesAttribute()
{
if ( ! array_key_exists('pages', $this->relations)) $this->loadPages();
return $this->getRelation('pages');
}
// here you load the pages and set the collection as a relation
protected function loadPages()
{
$pages = Page::join('page_role as pr', 'pr.page_id', '=', 'pages.id')
->join('role_user as ru', 'ru.role_id', '=', 'pr.role_id')
->where('ru.user_id', $this->id)
->distinct()
->get(['pages.*', 'user_id']);
$hasMany = new Illuminate\Database\Eloquent\Relations\HasMany(Page::query(), $this, 'user_id', 'id');
$hasMany->matchMany(array($this), $pages, 'pages');
return $this;
}
One more thing: I hardcoded tables and columns names for sake of simplicity, but in real life I suggest you rely on the relationships and their getters, like: $relation->getTable(), $relation->getForeignKey() etc.
Now suggestion about your code:
return User::find( // 2. query to get the same user
Auth::user()->id // 1. query to get the user and his id
)->with('roles.pages')
->first() // 3. query to get ANOTHER user (or the same, luckily..)
->roles;
Use Auth::id() instead of Auth::user()->id (for Laravel ver 4.1.25+) to avoid redundant query
find() and first() are methods that execute the query, so you just returned the user with id = Auth::user()->id and moment later you fetch another one, who comes first() from the users table..
You don't need to use User::whatever for authenticated user, use Auth::user() instead.
So the code with suggested solution would look like this:
Auth::user()->pages; // collection of Page models with unique entries

Yii. Get Users based on role

I am using native CDbAuthManager to implement RBAC in my webapp. How can I get all the users who has permission to do a role? Suppose I have role named updateprofile. I want to get all the users assigned to that role. I searched the documentation and couldnt find a function.
(I know i can iterate through all user models and do a checkAccess() in a foreach loop, but I prefer a nicer solution )
The easiest way I've found to do this is to create an AuthAssignment model that maps to your auth_assignment table. Then, you can setup relationships, scopes, etc for it and query using it to retrieve all user models. There isn't anything particularly special about the auth_assignment table (as it is mainly just roles in there).
code like
class AuthAssginment extends CActiveRecord{.....
public function getUsersBaseOnRole($role) {
return Yii::app()->db->createCommand()
->select('userid')
->from($this->tableName())
->where('itemname=:role', array(
':role' => $role,))
->queryAll() ;
}....
I think the other replies do not give you the perfect result because roles can be hierarchical and so, you cannot use direct queries or relations. My solution which works well is:
// list all users with 'userManagement' role
if($users = Users::model()->findAll()) {
foreach($users as $id => $user) {
if(!$user->checkAccess('userManagement')) {
unset($users[$id]);
}
}
$users = array_values($users); // to reset indices (optional)
}