Satisfy this JPQL requirement - jpa

Requirement: The content of one string is present in the other. This tests on whole words only, but multi-word queries are allowed. For example, a query with givenName:Jane will match users with givenName values of "Jane" and "Jane Ann", but not "Janet". A multi-word query for givenName:Mary Ann would match values of "Mary Ann Evans" and "Sarah Mary Ann" but not "Ann Mary".
This is what I have so far.
I have a SiteRepository that extends the JpaRepository interface and it consists of the following method.
#Query("SELECT s from Site s WHERE s.name LIKE :givenName")
public List<Site> findByName(#Param("givenName") String givenName);
Now, the user is suppose to pass in a String value to the method below (for example ":Jane" or ":Mary Ann").
public List<Site> findByName(String givenName) //Where Site is an entity with a name field.
In the above method, I essentially check the first character of the parameter giveName to see if it is ":" and if it is, I substring givenName to cut out the colon and concatenate the following characters.
return siteRepository.findByName("%" + givenName.substring(1, givenName.length()) + "%"
+ " AND NOT LIKE _" + givenName.substring(1, givenName.length()) + "_");
So if I called, findByName(":Jane")
I should get the following JPQL query: SELECT s from Site s WHERE s.name LIKE %Jane% AND NOT LIKE _Jane_
This however does not work. Any help will be appreciated and thanks in advance.

I am not an expert in jpql, so I will write here only my assumptions which are not necessarily correct, but I try to help the op anyways.
If my answer is wrong, then please, leave a comment at the answer to let me know about it.
I think this answer does not deserve to be down-voted, as I have made clear that my answer is not necessarily correct and I will remove it if it is incorrect.
This was my idea described as a comment to the question without knowing the technical details:
You should write a query which checks whether all the words are
present and the first index of a word is before the last index of the
next word.
LOCATE(searchString, candidateString [, startIndex])
searches for the position of searchString in candidateString starting from startIndex, indexes being started from 1. The idea is to write a query which checks whether the locate returns other than 0 having a value of startIndex dependent of the startIndex of the previous string. (Source) If all your strings match the criteria, then the record should be included into the results.

I found a solution. This seems to work for the cases I tested so far.
" SELECT s FROM Site s WHERE s.name NOT LIKE 'Jane_' AND s.name NOT LIKE '_Jane' AND s.name NOT LIKE 'Jane' AND s.name LIKE '%Jane%' "

Related

I need to change the output of a query so that instead of it coming back as the abbreviation 'em' it says 'employee'. Tsql

I have the correct result coming back. I just need to convert 6 abbreviations in that result to their correct names. There are 20k names assigned to 1 of 6 abbreviated names.
I tried aliasing but that seems to only work for table names.
I tried doing a case statement but that didn't work.
You need to provide more details (like some sample input and output), but if you have data like EM100, and you want to make it EMPLOYEE 100, then you could use an expression such as:
CASE WHEN ColumnName like 'EM%' THEN 'EMPLOYEE ' + SUBSTRING (ColumnName,3,100)
WHEN ColumnName like 'RN%' THEN 'REGNURSE' + SUBSTRING (ColumnName,3,100)
else ColumnName END
But providing more details will help provide a more specific answer.

Match part of a string with regex

I have two arrays of strings and I want to check if a string of array a matches a string from array b. Those strings are phone numbers that might come in different formats. For example:
Array a might have a phone number with prefix like so +44123123123 or 0044123123123
Array b have a standard format without prefixes like so 123123123
So I'm looking for a regex that can match a part of a string like +44123123123 with 123123123
Btw I'm using Swift but I don't think there's a native way to do it (at least a more straightforward solution)
EDIT
I decided to reactivate the question after experimenting with the library #Larme mentioned because of inconsistent results.
I'd prefer a simper solution as I've stated earlier.
SOLUTION
Thanks guys for the responses. I saw many comments saying that Regex is not the right solution for this problem. And this is partly true. It could be true (or false) depending on my current setup/architecture ( which thinking about it now I realise that I should've explained better).
So I ended up using the native solution (hasSuffix/contains) but to do that I had to do some refactoring on the way the entire flow was structured. In the end I think it was the least complicated solution and more performant of the two. I'll give the bounty to #Alexey Inkin for being the first to mention the native solution and the right answer to #Ωmega for providing a more complete solution.
I believe regex is not the right approach for this task.
Instead, you should do something like this:
var c : [String] = b.filter ({ (short : String) -> Bool in
var result = false
for full in a {
result = result || full.hasSuffix(short)
}
return result
})
Check this demo.
...or similar solution like this:
var c : [String] = b.filter ({ (short : String) -> Bool in
for full in a {
if full.hasSuffix(short) { return true }
}
return false
})
Check this demo.
As you do not mention requirements to prefixes, the simplest solution is to check if string in a ends with a string in b. For this, take a look at https://developer.apple.com/documentation/swift/string/1541149-hassuffix
Then, if you have to check if the prefix belongs to a country, you may replace ^00 with + and then run a whitelist check against known prefixes. And the prefix itself can be obtained as a substring by cutting b's length of characters. Not really a regex's job.
I agree with Alexey Inkin that this can also nicely be solved without regex. If you really want a regex, you can try something like the following:
(?:(\+|00)(93|355|213|1684|376))?(\d+)
^^^^^^^^^^^^^^^^^^^^^ Add here all your expected country prefixes (see below)
^^^ ^^ Match a country prefix if it exists but don't give it a group number
^^^^^^^ Match the "prefix-prefix" (+ or 00)
^^^^ Match the local phone number
Unfortunatly with this regex, you have to provide all the expected country prefixes. But you can surely get this list online, e.g. here: https://www.countrycode.org
With this regex above you will get the local phone number in matching group 3 (and the "prefix-prefix" in group 1 and the country code in group 2).

Refine Search on WIQL

WIQL SEARCH:
{
"query": "SELECT [System.Id] FROM WorkItems WHERE [System.Title] Contains Words 'midserver' AND [System.AreaPath] = 'XXXXX' AND [System.WorkItemType]='Issue' AND [System.State]<>'Done' ORDER BY [System.Id]"
},
can you pls help me with a query which refines the search i.e. the query should search the exact words and not CONTAINS ([System.Title] CONTAINS 'Search Text') –
something like IS ([System.Title], i have tried that but it doesn't recognize the query i think "IS" is not recognized
for e.g. story contains following names "rahul 1", and "rahul 2"..but if Iam searching with only "rahul" it should not display "rahul1" and "rahul2" instead it should say something like not found
Observation: its not working if there is space in the user story when i use Contains Words
so basically searching for the exact text if it is there or not but not search with contains
Since you want to search the exact words, why not just use a " = ". Change your WIQL like this:
SELECT
[System.Id]
FROM WorkItems
WHERE
[System.Title] = 'midserver'
AND [System.WorkItemType]='Issue'
AND [System.State]<>'Done'
ORDER BY [System.Id]
Actually the detail supported operators you are using such as =, Contains, Under is based on Field type.
Not all operators could used for each field type. For details, you could take a look at this screenshot:
If you are using System.Title which is a string field
Title
A short description that summarizes what the work item is and helps
team members distinguish it from other work items in a list. Reference
name=System.Title, Data type=String
So instead of Contains Words, you could directly use "=" in your case. For other kind of fields, you need to follow above operators.

Gremlin: Is there a way to find the character based on the index of a string?

I have vertex "office" and property "name" on OrientDB. I want to find the offices, by name, where the name does not have a "-" as the third character of the string. I imagine this would require some java code within the gremlin query.This is my best attempt, but it is resulting in office names that do in fact have a "-" as their third character.
g.V().hasLabel('office')
.where(values('name').map{it.get().charAt(2)}.is(neq('-')))
.project('Office Name')
.by(values('name'))
Since Gremlin doesn't support String operations (like split, charAt, etc.), your only chance is a lambda. Seems like you figured that out already, but your solution looks too overcomplicated to me. You can use something much simpler, like:
g.V().hasLabel('office').
has('name', filter {it.get()[2] != '-'}).
project('Office Name').
by('name')
However, note, that this filter will throw an exception if the office namer has less than 3 characters. Thus, you should better check that the String is long enough:
g.V().hasLabel('office').
has('name', filter {it.get().length() > 2 && it.get()[2] != '-'}).
project('Office Name').
by('name')
...or use RegEx pattern matching (which is pretty nice and easy in Groovy):
g.V().hasLabel('office').
has('name', filter {it.get() ==~ /.{2}-.*/}).
project('Office Name').
by('name')
The main reason why your traversal didn't work though, is that charAt returns a Character which is then compared to the String -, hence every office name will pass the neq filter.

Why is this Lucene query a "contains" instead of a "startsWith"?

string q = "m";
Query query = new QueryParser("company", new StandardAnalyzer()).Parse(q+"*");
will result in query being a prefixQuery :company:a*
Still I will get results like "Fleet Africa" where it is rather obvious that the A is not at the start and thus gives me undesired results.
Query query = new TermQuery(new Term("company", q+"*"));
will result in query being a termQuery :company:a* and not returning any results. Probably because it interprets the query as an exact match and none of my values are the "a*" literal.
Query query = new WildcardQuery(new Term("company", q+"*"));
will return the same results as the prefixquery;
What am I doing wrong?
StandardAnalyzer will tokenize "Fleet Africa" into "fleet" and "africa". Your a* search will match the later term.
If you want to consider "Fleet Africa" as one single term, use an analyzer that does not break up your string on whitespaces. KeywordAnalyzer is an example, but you may still want to lowercase your data so queries are case insensitive.
The short answer: all your queries do not constrain the search to the start of the field.
You need an EdgeNGramTokenFilter or something like it.
See this question for an implementation of autocomplete in Lucene.
Another solution could be to use StringField to store the data for ex: "Fleet Africa"
Then use a WildCardQuery.. Now f* or F* would give results but A* or a* won't.
StringField is indexed but not tokenized.