Grails- how to get part of the values in set collection? - grails

I have a domain which call party and has many invitees.
party.invitees give me a the set collection of the invitees.
I want to get only some of the invitees so I try do do the followinf in my service.
partInvitees= event?.invitees?.findAll{[offset: 3,max: 8]}
It doesn't give the correct result. It gives me all the invitees instead only the specific I have asked.

The findAll method you are invoking in there is not from GORM, but from Groovy Collections. So even if you paginate it (which is not possible directly in Groovy, AFAIK), you'll be bringing the whole collection into memory. If you don't mind, just do:
event?.invitees[offset..(offset-1)+max]
If the collection is too big and you don't want to bring it to memory, you can also query the Invitee directly:
Invitee.findAllByEvent(event, [offset: 3,max: 8])
But be aware that the order won't be necessarily the same, since Gorms' findAllBy doesn't know about the collection index (I'm assuming invitees is a list). You can make the collection index-aware, but it's a bit tricky.

You could use the GORM list() method to get the entire collection for a domain class. If you want only a subset of the collection you could use list() with some parameters.
If your domain class is named Invite, you should use Invite.list(max: 8, offset: 3, sort: "id", order: "asc") to get the subset described in your question. Keep in mind that different sort/order params could give you different results.
See the list() or listOrderBy() documentation for more information.
If you want Invites only for a specific Event you should read the Deigote answer.

Related

How to Filter Odata Query that is expanded by multiple levels?

I am currently trying to make an Odata call where I filter by a "multi-level" expanded property, however, none of the documentation or information I can find on this covers exactly what I am trying to accomplish. Does anyone know if this can be done, and how?
This is for letting our users be able to filter their Tests by the name of the Room the test was taken in. We have been able to filter by a single level of expanding, letting users filter their Tests by the name of the location, but we just can't seem to get the syntax right with the second level.
For context, our Test table is linked to a location table that is linked to a room table.
We are able to see the expanded information without a filter by calling:
.../api/Tests$expand=Location($select=Id,LocationName;$expand=Room($select=Id,RoomName))
returns:
...{"Id":19955,"LocationId":102,"Location":{"Id":102,"LocationName":"TestLocation","Room":{"Id":8,"RoomName":"TestRoom"}},...
But when we try a filtered call such as:
.../api/Tests$expand=Location($select=Id,LocationName;$expand=Room($select=Id,RoomName))&$filter=contains(Location/Room/RoomName,%27a%27))
All we get is the standard:
{"error":{"code":"NotFound","message":"The type 'Edm.String' is not an entity type. Only entity types support $select and $expand.\r\nParameter name: context"}}
There is surely some way of being able to filter from a multi-levelled expand, but I am somewhat of a newbie to Using OData, so any help would be appreciated!
Also, I believe we are using OData - 7.01.
Just answering my own question here, as it turns out the way we were doing it was correct.
The system was breaking in other areas down the pipe.

Rails 3 design: "hiding" an entry with "attribute" true, but only on the api level

In a rails 3 app, I have a model with a boolean attribute called "archived". This attribute is accessible in the cms, where I can go in and edit individual objects, and a checkbox where I can check if an object is archived or not. However, if this object is archived, I don't want this object to be accessible on the api level. That includes the object itself, and its associated objects. At the same time I would like the object to be accessible in the cms, to edit other details and set the archived value back to false, so that I can access the object again in the api and change its behaviour back to default.
I would really appreciate suggestions on how to approach this from a design/high level perspective. Thank you for your help.
When you say "api" do you mean:
Public RESTful API
Access to those models in your own code. Like finder methods on your model?
For the first case, simply get only objects in required state (Model.where(archived: false)).
In the second case, taking into account that Ruby is very "open" language, it would be impossible to limit access to any of object property or method. However, to build a public API for other team members to use, you can add methods that correctly filter out your models (look into scope).
As a second alternative to Model.where(archived: false)
If you used a status enumerator instead of a boolean, you would be able to restrict the list using Model.archived, or Model.published... All you need is an integer field for the model's db table, and something like this in the model:
enum status: { dev:0, published: 1, archived: 2}
Then in your API, you define what status segment you want to restrict it to as shown above. The enumerator system in RoR is a little tricky to get the hang of at first, but very powerful once you get it.

Breeze: how to prevent merge to happen

Having an entity in cache, that entity has related entities in the form of a top 20.
Now a user action can update the top 20 on the server, and I thus would like to redownload the entire entity. Server sends the correct data with top 20, but in Breeze, I end up with a top 40... And I can't figure out how to avoid this behavior.
Thanks for the tip
Update: I do not use odata webapi and iqueryable, as it offers too much power to clients for my app. So I don't want to use EntityQuery.fromEntityKey, which seems to do what I want. I'd prefer to keep using a "normal" query, to which I add a parameter.
Update 2: To add more clarity as to why I want to prevent merge, when I recompute the top 20, I delete all related entries in the db and recreate them, so they have new Id's. So I am now considering an update, which might actually solve my issue BUT I would still like to know if merge can be prevented.
The Breeze EntityManager caches entities by primary key. So presumably your 2nd query is returning a completely new set of entities with each query. If this is the case, and you really only want the "latest" 20, the simplest fix would be to simply empty the EntityManager cache for this entity type before each query. Something like:
var entities = myEntityManager.getEntities(myEntityType);
entities.forEach(function(e) {
myEntityManager.detachEntity(e);
// or
// e.entityAspect.setDetached();
});
I am not sure what is exactly your qustion, but if you want to have different results on entity queries you may do it by creating 2 different controllers with different action names, or just with different parameters - overloaded methods. Then in your datacontext you can have 2 different queries.
You use .withParameters() propriety on the query to call the controller method with parameters.
Then in the controller method you can query and filter with LINQ, in any way you want. This way you can have different results based on the query/controller you chose to call.
Documentation: http://www.breezejs.com/documentation/querying-depth

Difference between findAll, getAll and list in Grails

With Grails there are several ways to do the same thing.
Finds all of domain class instances:
Book.findAll()
Book.getAll()
Book.list()
Retrieves an instance of the domain class for the specified id:
Book.findById(1)
Book.get(1)
When do you use each one? Are there significant differences in performance?
getAll is an enhanced version of get that takes multiple ids and returns a List of instances. The list size will be the same as the number of provided ids; any misses will result in a null at that slot. See http://grails.org/doc/latest/ref/Domain%20Classes/getAll.html
findAll lets you use HQL queries and supports pagination, but they're not limited to instances of the calling class so I use executeQuery instead. See http://grails.org/doc/latest/ref/Domain%20Classes/findAll.html
list finds all instances and supports pagination. See http://grails.org/doc/latest/ref/Domain%20Classes/list.html
get retrieves a single instance by id. It uses the instance cache, so multiple calls within the same Hibernate session will result in at most one database call (e.g. if the instance is in the 2nd-level cache and you've enabled it).
findById is a dynamic finder, like findByName, findByFoo, etc. As such it does not use the instance cache, but can be cached if you have query caching enabled (typically not a good idea). get should be preferred since its caching is a lot smarter; cached query results (even for a single instance like this) are pessimistically cleared more often than you would expect, but the instance cache doesn't need to be so pessimistic.
The one use case I would have for findById is as a security-related check, combined with another property. For example instead of retrieving a CreditCard instance using CreditCard.get(cardId), I'd find the currently logged-in user and use CreditCard.findByIdAndUser(cardId, user). This assumes that CreditCard has a User user property. That way both properties have to match, and this would block a hacker from accessing the card instance since the card id might match, but the user wouldn't.
Another difference between Domain.findByID(id) and Domain.get(id) is that if you're using a hibernate filter, you need to use Domain.findById(id). Domain.get(id) bypasses the filter.
AFAIK, these are all identical
Book.findAll()
Book.getAll()
Book.list()
These will return the same results
Book.findById(1)
Book.get(1)
but get(id) will use the cache (if enabled), so should be preferred to findById(1)

How can I modify the queryset in the change list view depending on a parameter I set in the URL

My problem is the following and it is related to the change list view of the admin interface.
I have a workorder model with several fields to caracterize the work order.
They are : type, nature, scheduling_type (and others).
When I see the list view, I would like to be able to change the filter (thus be able to create complex ones depending on the values of the different fields of the workorder model - the ones above and dates for example).
I have found post showing how to modify the default queryset (using managers for example) but I can't find a post that will use a value that is given in the url (ex. admin/workorder/planned_corrective). When the parameter planned_corrective is found, it must be used to select the appropriate queryset or manager and render the corresponding list.
As a add on, I want from that list to be able to use the standard admin options (like list filters, search ...) on that query.
Hope it is clear and thanks in advance for your help.
It sounds like you're after a RESTful interface.
You could accomplish much of this just by being clever with your urls.py - ie, defining admin/workoder/planned_corrective and every other possible parameter that could be encoded in the URL.
A lot of this can also be accomplished just by adding a get-absolute-url method to your models.
Or, you could the effort into using something like the django-rest-interface in your app.

Resources