Geoserver WFS Cross Layer Filtering and String IDs - cql

I have a Geoserver WFS request with a cross layer filter based cql in it, that looks like this:
...&CQL_FILTER=INTERSECTS(the_geom, querySingle('myLayerName','the_geom','the_id = F338'))
This does not work. Geoserver is giving me this error message:
java.lang.NullPointerException: PropertyDescriptor is null - did you
request a property that does not exist?
if I change the filter to this:
&CQL_FILTER=INTERSECTS(the_geom, querySingle('myLayerName','the_geom','INCLUDE'))
it is working.
What could be going wrong in the first example? The id with the value F338 in fact does exist.
Could it be that Geoserver is expecting a integer as id? In CQL filters can be strings, but they have to be quoted. In my example, i obviously cannot really quote the value because the whole parameter to the querySingle function is a quote itself.

For string comparison, you need to put two single quotations, so i.e.
'the_id = ''F338'''. (one double quotation doesn't work)
This stupid undocumented little thing cost me 5 hours of try and error...

Related

flux query: filter out all records related to one matching the condition

I'm trying to filter an influx DB query (using the nodeJS influxdb-client library).
As far as I can tell, it only works with "flux" queries.
I would like to filter out all records that share a specific attribute with any record that matches a particular condition. I'm filtering using the filter-function, but I'm not sure how I can continue from there. Is this possible in a single query?
My filter looks something like this:
|> filter(fn:(r) => r["_value"] == 1 and r["button"] == "1" ) and I would like to leave out all the record that have the same r["session"] as any that match this filter.
Do I need two queries; one to get those r["session"]s and one to filter on those, or is it possible in one?
Update:
Trying the two-step process. Got the list of r["session"]s into an array, and attempting to use the contains() flux function now to filter values included in that array called sessionsExclude.
Flux query section:
|> filter(fn:(r) => contains(value: r["session"], set: ${sessionsExclude}))
Getting an error unexpected token for property key: INT ("102")'. Not sure why. Looks like flux tries to turn the values into Integers? The r["session"] is also a String (and the example in the docs also uses an array of Strings)...
Ended up doing it in two queries. Still confused about the Strings vs Integers, but casting the value as an Int and printing out the array of r["session"] within the query seems to work like this:
'|> filter(fn:(r) => not contains(value: int(v: r["session"]), set: [${sessionsExclude.join(",")}]))'
Added the "not" to exclude instead of retain the values matching the array...

Is there a way to pass a parameter to google bigquery to be used in their "IN" function

I'm currently writing an app that accesses google bigquery via their "#google-cloud/bigquery": "^2.0.6" library. In one of my queries I have a where clause where i need to pass a list of ids. If I use UNNEST like in their example and pass an array of strings, it works fine.
https://cloud.google.com/bigquery/docs/parameterized-queries
However, I have found that UNNEST can be really slow and just want to use IN on its own and pass in a string list of ids. No matter what format of string list I send, the query returns null results. I think this is because of the way they convert parameters in order to avoid sql injection. I have to use a parameter because I, myself want to avoid SQL injection attacks on my app. If i pass just one id it works fine, but if i pass a list it blows up so I figure it has something to do with formatting, but I know my format is correct in terms of what IN would normally expect i.e. IN ('', '')
Has anyone been able to just pass a param to IN and have it work? i.e. IN (#idParam)?
We declare params like this at the beginning of the script:
DECLARE var_country_ids ARRAY<INT64> DEFAULT [1,2,3];
and use like this:
WHERE if(var_country_ids is not null,p.country_id IN UNNEST(var_country_ids),true) AND ...
as you see we let NULL and array notation as well. We don't see issues with speed.

retrofit2 - duplicate url parameter names issue

I am coding a json/rest client in java/retrofit2. Works great, run into one snag. The service I am a client of (teamdesk.net) uses duplicate url parameters to express selecting specific columns. (Without any column parameters it will just select all) .. so like this:
?column=firstname&column=lastname&column=age ...
I know I could model this by using N number of #Query() decorators eg:
Call<List<User>> groupList(#Query("column") String col1, #Query("column") String col2);
Problem here is then I am limited to a fixed N number of columns. I could make multiple request methods to handle this (1 column, 2 columns, 3 columns.. etc) but that is unwieldy.
I can't use the #QueryMap() pattern as it will not allow - for obvious reasons - multiple "column" keys.
I tried this pattern and it works:
#GET("Patient/select.json{query}")
Call<List<Patient>> getPatients(#Path("query") String urlquery);
and then calling thus:
getPatients("?top=5&column=firstname&column=lastname&column=age")
But I fear that this is hacking and that some later version of retrofit will break this.
So I am looking for suggestions:
1) Is my #GET("Patient/select.json{query}") hack a good idea ?
2) is there some better way to allow me to gain edit access to the url parameters before calling ?
3) Is there some existing interceptor pattern that can help ?
4) Could I write my own interceptor pattern for this - i'm up for it..
thanks in advance.
From the retrofit documentation you can simply use varargs with the #Query annotation, so like this:
#GET("Patient/select.json")
Call<List<Patient>> getPatients(#Query("column") String... columns);
which you can call with any number of Strings
getPatients("column1", ..., "columnN");
and will result in the url:
yourBaseUrl/Patient/select.json?column=column1&...&column=columnN

Curly brackets in OrmLite select query throws error

It seems like OrmLite plain select extension method (Select<T>) tries to format the query string (like SelectFmt<T>), and so it throws an error if the query string contains curly brackets, which it assumes are missing arguments.
Example query:
db.Select<Company>("Website='http://www.test.com/?session={123}'");
Error thrown:
Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
Ideally, Select<T> should just execute the query verbatim, without any string formatting.
Is it a bug in OrmLite, or something else?!
Update: Seems like the issue is here in OrmLiteDialectProviderBase class. It should have a check for params length etc.
You can use SqlList<T> API's for executing Custom SQL that skips pre-processing by OrmLite, but you'll need to provide the full SQL Statement, e.g:
var results = db.SqlList<Company>(
"SELECT * FROM Company WHERE Website='http://www.test.com/?session={123}'");

Best practice to pass query conditions in ajax request

I'm writing a REST api in node js that will execute a sql query and send the results;
in the request I need to send the WHERE conditions; ex:
GET 127.0.0.1:5007/users //gets the list of users
GET 127.0.0.1:5007/users
id = 1 //gets the user with id 1
Right now the conditions are passed from the client to the rest api in the request's headers.
In the API I'm using sequelize, an ORM that needs to receive WHERE conditions in a particular form (an object); ex: having the condition:
(x=1 AND (y=2 OR z=3)) OR (x=3 AND y=1)
this needs to be formatted as a nested object:
-- x=1
-- AND -| -- y=2
| -- OR ----|
| -- z=3
-- OR -|
|
| -- x=3
-- AND -|
-- y=1
so the object would be:
Sequelize.or (
Sequelize.and (
{x=1},
Sequelize.or(
{y=2},
{z=3}
)
),
Sequelize.and (
{x=3},
{y=1}
)
)
Now I'm trying to pass a simple string (like "(x=1 AND (y=2 OR z=3)) OR (x=3 AND y=1)"), but then I will need a function on the server that can convert the string in the needed object (this method in my opinion has the advantage that the developer writing the client, can pass the where conditions in a simple way, like using sql, and this method is also indipendent from the used ORM, with no need to change the client if we need to change the server or use a different ORM);
The function to read and convert the conditions' string into an object is giving me headache (I'm trying to write one without success, so if you have some examples about how to do something like this...)
What I would like to get is a route capable of executing almost any kind of sql query and give the results:
now I have a different route for everything:
127.0.0.1:5007/users //to get all users
127.0.0.1:5007/users/1 //to get a single user
127.0.0.1:5007/lastusers //to get user registered in the last month
and so on for the other tables i need to query (one route for every kind of request I need in the client);
instead I would like to have only one route, something like:
127.0.0.1:5007/request
(when calling this route I will pass the table name and the conditions' string)
Do you think this solution would be a good solution or you generally use other ways to handle this kind of things?
Do you have any idea on how to write a function to convert the conditions' string into the desired object?
Any suggestion would be appreciated ;)
I would strongly advise you not to expose any part of your database model to your clients. Doing so means you can't change anything you expose without the risk of breaking the clients. One suggestion as far as what you've supplied is that you can and should use query parameters to cut down on the number of endpoints you've got.
GET /users //to get all users
GET /users?registeredInPastDays=30 //to get user registered in the last month
GET /users/1 //to get a single user
Obviously "registeredInPastDays" should be renamed to something less clumsy .. it's just an example.
As far as the conditions string, there ought to be plenty of parsers available online. The grammar looks very straightforward.
IMHO the main disadvantage of your solution is that you are creating just another API for quering data. Why create sthm from scratch if it is already created? You should use existing mature query API and focus on your business logic rather then inventing sthm new.
For example, you can take query syntax from Odata. Many people have been developing that standard for a long time. They have already considered different use cases and obstacles for query API.
Resources are located with a URI. You can use or mix three ways to address them:
Hierarchically with a sequence of path segments:
/users/john/posts/4711
Non hierarchically with query parameters:
/users/john/posts?minVotes=10&minViews=1000&tags=java
With matrix parameters which affect only one path segment:
/users;country=ukraine/posts
This is normally sufficient enough but it has limitations like the maximum length. In your case a problem is that you can't easily describe and and or conjunctions with query parameters. But you can use a custom or standard query syntax. For instance if you want to find all cars or vehicles from Ford except the Capri with a price between $10000 and $20000 Google uses the search parameter
q=cars+OR+vehicles+%22ford%22+-capri+%2410000..%2420000
(the %22 is a escaped ", the %24 a escaped $).
If this does not work for your case and you want to pass data outside of the URI the format is just a matter of your taste. Adding a custom header like X-Filter may be a valid approach. I would tend to use a POST. Although you just want to query data this is still RESTful if you treat your request as the creation of a search result resource:
POST /search HTTP/1.1
your query-data
Your server should return the newly created resource in the Location header:
HTTP/1.1 201 Created
Location: /search/3
The result can still be cached and you can bookmark it or send the link. The downside is that you need an additional POST.

Resources