Why doesn't the parameter index work? - spring-data-neo4j

In the documentation, https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/
it uses {0} to reference the parameter 'movieTitle'.
#Query("MATCH (movie:Movie {title={0}}) RETURN movie")
Movie getMovieFromTitle(String movieTitle);
However, in my own code, if I use "{title={0}", my IntelliJ always reports a syntax error. I can resolve the issue by changing it to
{title:{movieTitle}
Here I have to use the actual argument name and the colon plus {}.
Is there any trick for this? I don't think the documentation is wrong.
Question 2:
If I want the node label "Movie" to be a parameter, it also shows an error message:
#Query("MATCH (movie:{label} {title={0}}) RETURN movie")
Movie getMovieFromTitle(String movieTitle, String label);

I do not know what version of IntelliJ you are using but the first query is right. There is also a test case for this in the spring-data-neo4j project.
It is not possible to use the second query syntax because there is no support for this on the database level where the query gets executed. If it would be supported in SDN before making the call to the DB the query has to be parsed (and the pattern replaced) every time when the query get executed and SDN will loose the possibility to parse the query once and then just add the parameter values in subsequent calls. This will lower the performance of executing annotated query functions.

Related

Drupal 8: Altering Search API queries

I'm working on a project which includes the following activated modules:
Drupal core 8.2.3
Database Search 8.x-1.0-beta4
Search API 8.x-1.0-beta4
Search API Term Handlers 8.x-1.0-beta4
Views 8.2.3
I have a list of nids which need to be excluded from the search result of the site-wide search. The search uses Search API and has been setup using Views.
The table in the database is: "search_api_db_default_index"
The field I wish to target is: "nid"
I wasn't able to get HOOK__search_api_query_alter or HOOK_search_api_results_alter to fire, so I am attempting to manipulate the query through HOOK_views_query_alter.
I have attempted to use both the "addWhere" and "addCondition" methods with the following syntax:
When using the addCondition method, I attempted
$query->addCondition('search_api_db_default_index.nid', $oneBadNid, '<>');
and
$query->addCondition('search_api_db_default_index.nid', $manyBadNids, 'NOT IN');
and when using the addWhere method, I attempted
$query->addWhere('AND', 'search_api_index_default_index.nid', $oneBadNid, '<>');
and
$query->addWhere('AND', 'search_api_index_default_index.nid', $manyBadNids, 'NOT IN');
Regardless of whether or not I prefix the field with the table name, searching always results in triggering the following notice:
Unknown field in filter clause: 'search_api_db_default_index.nid' .
It seems that the field name is always wrapped in an html encoded string representing a single quotation, but this occurs both when using double quotations or single quotations around the supplied table.field parameter.
I am not even sure that this is what is keeping me from altering my query, but it is the only thing close to an error which I have discovered in this process. It's also possible that I'm simply not supposed to be targeting the table in the manner written, but I did not find any documentation directing me to the proper methodology.
I would appreciate any insight into this issue! Thanks!
Generally you can use
$fields = $query->getIndex()->getFields();
on the query to get an array of fields you can use within the search_api query.
Piggy-backing off of Nebel54's comment, and attempting this on my own, you don't need to include the 'table' name when setting the addCondition. However, I did need to use hook_search_api_query_alter over a views-specific one.
function mymodule_search_api_query_alter(\Drupal\search_api\Query\QueryInterface &$query) {
// Ensure field_myfield is being indexed
$fields = $query->getIndex()->getFields();
if (isset($fields['field_myfield'])) {
$query->addCondition('field_myfield', 'myvalue', '<>');
}
}

Equivalence of Django queryset filteration

I've been using the following two interchangeably in a Django project:
Comments.objects.filter(writer=self.request.user).latest('id')
and
Comments.objects.get(writer=self.request.user)
Are they equivalent in practice? The docs don't seem to explicitly address this.
They are not equivalent at all, but this greatly depends on the particular model. We do not know the particulars of your model Comments, but if we assume that field writer is not unique:
For the first statement:
Comments.objects.filter(writer=self.request.user).latest('id')
Returns in essence the object with the largest id amongst a queryset of all comments with the particular writer. If one takes a look at the django.db.connections['default'].queries, will see that the resulting query is a SELECT .. ORDER_BY .. LIMIT .. statement.
For the second statement:
Comments.objects.get(writer=self.request.user)
Returns the particular record fot that writer. In case there are more than one, you get a MultipleObjectsReturned exception. If no object is found, you get a DoesNotExist exception. In the event that this would be a unique field or there would be a single object by chance, the resulting query would be a SELECT .. WHERE statement which is faster.
Regarding the documentation, if you take a look at the Options.get_latest_by reference, there is more information regarding the purpose of the latest function. Think of it more of a convenience provided by Django. It is nonetheless very important to understand how Django evaluates queries and the resulting SQL, and there are always many ways to achieve the same query so it is a matter of logic.
I don't know why you would think these are equivalent, or why the docs should address this specifically.
In the case where you only have one matching Comment, yes this will give the same result. But the first version will do it via a more complex query, with an added sort on id.
If you have more than one Comment for that writer - as seems likely - the second version will always give a MultipleObjectsReturned error.
filter gives all lines corresponding your filter.
latest gives the most recent line (highest id value)
For example:
Comments.objects.filter(writer=self.request.user).latest('id') gets in first place all Comments written by self.request.user and then latest get the newest from them.
get is made to get a unique line, so :
Comments.objects.get(writer=self.request.user) will give the comment written by self.request.user. There should be only one. If a user can write many comments then you have to use filter or maybe all. It depends on what you want exactly.
More info here

Spring Data Neo4j find nodes by label

I am currently using SDN 4 and trys to do the following query:
#Query("MATCH (n:TNode:{0}) RETURN n")
Collection<TNode> getNodes(String type);
where each node has a common label "TNode" and an individual label type. However, it always returns syntax error. I'm sure the query is correct because it returns nodes using Neo4j web client.
Does the error occurs because SDN can not find nodes by label?
This is a limitation of Cypher, not SDN. Labels (or relationship types) as parameters are not supported. See this and related feature requests.
You can work around this using where clause and labels(n) function:
MATCH (n:TNode)
WHERE {0} in labels(n)
RETURN n
This comes with a caveat - it will go through all nodes matched by the MATCH clause. In your situation having a :TNode label might solve the issue, but generally having simple MATCH (n) would go through all nodes in the database, which will be very slow.
Other option would be to build the query manually and use org.springframework.data.neo4j.template.Neo4jOperations#queryForObjects to run the query:
String query = "MATCH (n:TNode:" + type + ") RETURN n"; // ugly, but works, beware of query injections etc..
Collection<TNode> nodes = neo4jOperations.queryForObjects(TNode.class, query, params);

Does ##parentid attribute work in Sitecore query?

Sitecore reference talk about some attributes you can use in Query, including ##templatename, ##id and ##parentid etc.
parentid doesn't seem to work - /sitecore/content//*[##parentid!=''] never returns any result. While /sitecore/content//*[##templatename!=''] works fine. Sitecore version is 6.5 and 6.6.
Has anyone been able to query with ##parentid? ( Perhaps it uses Ancestor/Descendant table and I'm missing data?? - just a guess )
It is attempting to parse the value as a GUID and failing. Instead, try an empty GUID like so:
/sitecore/content//*[##parentid!='{00000000-0000-0000-0000-000000000000}']
##parentid only works in fast query.
In fast query you can only use ancestor not ancestor-or-self (which doesn't give an error it just does a fallback too ancestor).
Also you can't use the pipe | in fast query to concatenate results of 2 or more queries.
I can't for the life of me figure out how to do a "give me the ancestor-or-self of the current node whose parent has id={110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}.

How to get constraint errors from OCIErrorGet?

Our C++ program is using Oracle and OCI to do its database work. Occasionally, the user will trigger a constraint violation, which we detect and then show an error message from OCIErrorGet. OCIErrorGet returns strings like this:
ORA-02292: integrity constraint (MYSCHEMA.CC_MYCONSTRAINT) violated - child record found
ORA-06512: at line 5
I am looking for the cleanest way to extract "MYSCHEMA.CC_MYCONSTRAINT" from the Oracle error. Knowing the name of the constraint, I could show a better error message (our code could look up a very meaningful error message if it had access to the constraint name).
I could use a regex or something and assume that the Oracle message will never change, but this seems a little fragile to me. Or I could look for specific ORA codes and then grab whatever text falls between the parentheses. But I was hoping OCI had a cleaner/more robust way, if a constraint fails, to figure out the actual name of the failed constraint without resorting to hardcoded string manipulation.
Any ideas?
According to the Oracle Docs, a string search is exactly what you need to do:
Recognizing Variable Text in Messages
To help you find and fix errors, Oracle embeds object names, numbers,
and character strings in some messages. These embedded variables are
represented by string, number, or character, as appropriate. For
example:
ORA-00020: maximum number of processes (number) exceeded
The preceding message might actually appear as follows:
ORA-00020: maximum number of processes (50) exceeded
Oracle makes a big point in their docs of saying the strings will be kept up to date in their section on "Message Accuracy." It's a pretty strong suggestion that they intend you to do a string search.
Also, according to this website, the Oracle Error structure also pretty strongly implies that they intend you to do a string search, because the data structure lacks anything else for you to get:
array(4) {
["code"]=>int(942)
["message"]=>string(40) "ORA-00942: table or view does not exist"
["offset"]=>int(14)
["sqltext"]=>string(32) "select * from non_existing_table"
}
This output reveals the following information:
The variable $erris an array with four elements.
The first element is accessible by the key ‘code’ and its value is number 942.
The second value is accessible by the key ‘message’ and the value is string “ORA-00942: table or view does not exist”.
The third value is accessible by the key ‘offset’, and its value is the number 14. This is the character before the name of the
non-existing table.
The fourth member is the problematic SQL message causing the error in the first place.
I agree with you; it would be great if there were a better way to get the constraint name you're violating, but string-matching seems to be the intended way.