Restrict search to specific domains - grails

I'm using the elasticsearch plugin and I'm running searches using elasticSearchService.search(myKeywords) which searches for keywords over all the domain classes marked as searchable.
Now I want to restrict the search to two specif domain classes. I can see there are options named indices and types that can be passed to the search method, but if I simply use my domain class names on them I get errors telling the index or type doesn't exist. What exactly should I do to achieve what I want?
(I'm new to lucene and elasticsearch and I'm not sure I understood the index and type concepts. Reading the docs I could only find examples to restrict searches to an specific field, not a hole domain class or whatever it is mapped to, in lucene/elasticsearch concepts).

The way to go is:
elasticSearchService.search(myKeywords, [types:["myPackage.MyClass","myPackage.MyOtherClass"]])
The results are as expected, but I'm still worried about having one index (and one type) per domain. Not what I expected but I can't see how to map all domain classes to a single index for the hole database as stated by the docs

Related

OGM Custom Query using Custom Label

I have a Neo4j/OGM Entity Person which I mapped to the Label User using
#NodeEntity(label="User).
I now want to write a custom Query MATCH (p:Person) where....
As far as I see, there is no way to use my Application-Side Type Person instead of the Graph-Side Label User like in Hibernate, right?
If there is a way, please explain how to do this, or tell my a key-word to google for.
Same question goes for entity properties.
Thank you.
Update:
Lets say I have a User class like so:
#NodeEntity(label="Person")
class User {
#Property(name="username")
private String name;
...
}
I've used the Mapping to obtain loose coupling so I can eg. rename the Person and won't affect the Neo4j.
And in the Neo4j there are for example Houses with Relationships to Users.
Now I want to load all Houses, referencing a User with the name "Sven", so the Statement would be MATCH (h:House)-[:HOLDS]->(p:Person {username:'Sven'}).
Given, that I might have a huge poject with all the entities in some submodule somewhere else, I might not know, that User is mapped to Person and the user.name is mapped to username, so in a Hibernate environment, I would query as MATCH (h:House)-[:HOLDS]->(u:User {name:'Sven'}). However in OGM this doesn't seem to work.
There might be a way to solve this architectually but in some projects you don't have this choise.
So the question in the End is: Is there some way to get this to work, or do I really need to know the mapping of every entity i use?
You can do this in several ways :
Make your User extend a Person class
if you need more dynamic labels, the class can contain an #Labelsannotated list of labels to apply. See the documentation for more details
About properties, I don't see how this would be useful. Interested to hear about the use case.

rename domain class, groovy and grails reverse engineering

How do a rename a domain class while reverse engineering or after reverse engineering.
i generated class using reverse engineering in Groovy and Grails.
the domain class name was AgentTable. I want to rename it as Agent. When i renamed the domain class using IntelliJ (right click - refactor - rename), it renamed the AgentTable to Agent whereever it was used. but when i start the server (run the app), giving error
"nested exception is org.hibernate.HibernateException: Missing table: agent"
I have to do this for few domain class. is it anyway i can give an alternative name while reverse engineering the domain classes.
or after domain class was created how do i rename it without this error.
Look into your database the name of the table it created for the agent. Once you know the name of the table add the following in your new domain
static mapping = {
table "table-name-here"
}
While it works I would not recommend #elixir 's approach.
In my opinion the mapping is not supposed to be used for renames. This is also how I understand the official documentation.
In the example they use it to map Person onto the 'people' table, not because of a rename but because of a semantic reason. Tables are typically named after the plural form. Here is a nice answer on another question regarding this. In the project I am working on the domain object 'User' is mapped to the table 'users'. You can not use the table name 'user' as it is an SQL statement.
Assumptions and clarifications:
In my experience Grails maps the domain name to the table name after these rules (example domain name 'MyExampleDomain':
separate the domain name by capital letters (My Example Domain)
lower case all (my example domain)
replace spaces with underlines (my_example_domain)
Following this your Domain Class 'AgentTable' has a table 'agent_table' in your respective database. After your rename Grails even tells you what it wants:
nested exception is org.hibernate.HibernateException: Missing table: agent
It wants to look up values in a table called 'agent' but it can not find it. The refactor function of IntelliJ does not rename the functions, so it will miss out on the database.
Luckily we know exactly what values it wants - the values previously found in 'agent_table'.
So why create this confusion with remapping domains and table names when we could just rename the table and be done with it?
The solution:
Execute an SQL script like this on your database:
ALTER TABLE <old_domain_name> RENAME TO <new_domain_name>;
The names are of course in their "table-form".
This simply renames your table to match the expected format in Grails. When restarting everything should be fine.
However you do not need to use rename. You could also create a whole new table, build it the way the domain objects wants it to be and then migrate the data. See section 'Problems with this approach' for information on when to use what.
Problems with this approach:
As always, tinkering with information a program depends on (and even generated itself) will often have some dire consequences if you aren't careful.
For example we have to pay attention to keys. If your domain object has a relation to other objects it will hold them in the table via foreign keys. Depending on how you chose to migrate the information in the table you might have deleted these foreign keys connections. You will have to add them via a separate SQL statement. When you choose to recreate the table this will happen for sure. Renaming it should keep the keys.
Another one are column names. If you choose to rename attributes you will also have to rename the columns via SQL. You will also have to remember the foreign keys other tables might have on the table you are renaming. RENAME did this automatically for me, but you should double check.
Why you should still stick with this approach:
Remapping domain objects to the tables with old names is bound to create code smell and confusion. Do you really want to remember these mappings in your head? And more importantly: do you really expect other people to have to work with this?
The best case is if people can't even tell if this object has ever had a different name and changing the database is the best way I know to achieve this.

REST URL naming convention /items/{id} vs /items?id={id}

I understand that in MVC pattern and in REST services it is common to use URIs like /items/{id} but what is bad thing about using query parameters in the URI?
GET /items/{id} vs GET /items?id={id}
Further, lets say an entity has 'referenceId' field that points to some related (say parent) entity, and I need to create REST service to get all items for parent entity, which way is better:
GET(POST) /items/parent/{parentId}
or
GET(POST) /items?parent={parentId}
Will be grateful for insights that would help to resolve my subjective issues on constructing URLs for REST services.
I would use the following schemes.
/items/id
This uniquely addresses a resource of items with id id. We are not using parameters as a parameter to uniquely address this resource (as is the case with the other option). Just as
miguelcobain suggests.
/parent/id/items
Here id is an id to uniquely address a resource of parent and from those we collect/retrieve the items it references. From what you have said in the question it seems that parent references multiple items, like a container or collection.
The convention I use for this is to narrow down the scope going from left to right. Therefore in case items could be active or inactive. Thusly items have a property or attribute to be active or inactive. Narrowing down on this I get the following scheme:
/items/active
/parent/id/active
For your first question:
/items/{id} should retrieve a single resource with the specified id or 404 if it doesn't exist.
/items/?id={id} should retrieve an array (even if only one in the array) because you are querying the collection.
For your second question:
I agree with #miguelcobain's assessment - if the item is a specific resource/entity, just use the proper resource path to retrieve it.
To make this easier on the consumer, create a link header with rel="parent" and/or include the uri in the child resource. For an example of link headers, see GitHub's pagination api.
Of course, REST principles don't care about aesthetic details on URLs. It just imposes that every resource should be uniquely addressable.
Furthermore, using the query parameters to uniquely address something "kind of" violates the semantics of a "parameter", doesn't it? A parameter should be something optional, something additional and parameterized. Something like a detailed search on a collection of items, for example.
What you wrote may make sense in some cases. It depends.
In your example, is the item really a resource? If not, you could just do GET(POST) /parents/{parentId}.
If parent is, say, a boolean, and you want to search the items that have parent equals to true, then using the parameters makes sense. But since you're explicitly saying that you want a parent with a specific id, I assume that parent is a resource itself and I would uniquely address that resource using your option 1.
I hope I made myself clear.
It seems to me there are no rules to follow.
items/{id} - this convention is suitable for GET item by given id. If user doesn't provide id then it returns 404 status code.
items/id={id}&name={name} - this type of convention is suitable for search multiple items by given criteria. If no items are found, it is not a 404 situation, you simply say "I successfully found nothing matching your search criteria"

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.

How to create OData based off RFC with multiple tables in the output?

I am working on a large project at work that requires me to create OData's for a large variety of Remote Function Calls. I was able to work out how to model and create OData's for simple RFCs; however, I am struggling with more complex RFCs that use multiple tables as well as simple exporting and importing parameters.
I want to output these tables as well as the importing and exporting parameters via GetEntity and GetEntitySet with just one call. I have done extensive searching online to find solutions but the best solution seems to be redefining the RFC's or calling the OData multiple times which is not ideal.
Is there any way to combine multiple tables with several entries in the output? When I say output, I am referring to the resulting XML from GetEntity/GetEntitySet.
For example, take the below fake RFC definition that takes a PERNR, and outputs a list of direct reports and a structure of employee details.
IMPORTING
PERNR
EXPORTING
S_EMPLOYEE_DETAILS
TABLES
T_DIRECT_REPORTS
Is there a way to combine the table, structure, and importing parameters into one output?
The first thing to understand is that the OData protocol is not intended to solely work like classical function calls. It is based however on entity/relationship kind of model.
So in your case id sugest to create an entity type named 'Employee' with the appropiate properties of your structure S_EMPLOYEE_DETAILS. With this you can e.g. implement the method GET_EMPLOYEE_ENTITY to retrieve a single instance of an employee via PERNR.
The next thing to do would be to get the direct reports of this employee. Since this is a relation 1:N from Employee to Employee in your case you can create a navigation property called 'DirectReports' with appropiate cardinality. Then in your GET_EMPLOYEE_ENTITYSET you can return the instances of table T_DIRECT_REPORTS (note that navigation property is not empty and you have to read the keys of the parent!).
Once you got this working you can move on to the 'best-practise' and implement the method GET_EXPANDED_ENTITY with filling the expand clauses, which is in my opinion the preferred way as you dont need to implement two seperate methods and is consiered faster as well (if many expands happen).
Both methods of implementation can be called via
GET EmployeeSet('12345678')?$expand=DirectReports

Resources