TypeORM dynamic query builder - typeorm

I am migrating to use typeorm from raw queries. One of the issues that I am having with this is when it comes to dynamic queries. Previously, I had a query builder function that would dynamically create the sql query. So for example you could imagine an input that looks something like
{
id: 123,
exclude: [505, 273]
}
then the query builder would create and return a query something like
SELECT * FROM table WHERE id = 123 AND pid NOT LIKE '505%' AND pid NOT LIKE '273%';
how can I do something like this with TypeORM because the exclude array is dynamic?

Related

Use dynamic finders with list of Object IDs

With the given class structure
class MyObject {
Status status;
}
class Status {
Integer id;
}
I want to use dynamic finders to query based on a list of Status ID values. What I want to be able to do is something like this
MyObject.findAllByStatusInList([1,2,3]);
This does not work though because my list needs to be Status objects. I know I can build a criteria to do this, but I just want to know if there is a way to accomplish this with Dynamic Finders?
You can still accomplish this using the dynamic finder.
def statuses = [1, 2, 3].collect { Status.load(it) }
MyObject.findAllByStatusInList(statuses)
load() will create a proxy for you that won't require retrieving the instance from the database as long as you don't access any properties other than id.
You can use the where clause:
MyObject.where {status.id in [1,2,3]}.find()
UPD
Dynamic finders don't support aliasing so Criteria (or DetachedCriteria) is the solution to be used.
In case if Status class is a domain entity you could retrieve a list of them (or load their proxies) from the database and then query MyObjects by the status list.
So I see no other appropriate solution but using Criteria in your case.
You can use this.
List<Integer > statuses = [1, 2, 3]
MyObject.findAllByStatusInList(statuses)

Grails: query or criteria against a string/value pairs map property

Grails gives the possibility of creating simple string/value map properties section "Maps of Objects", first paragraph.
I was wondering, is there a way to later query the domain class (using Gorm dynamic finders, criterias or HQL) using the map property as part of the query (i.e adding a condition for the key X to have the value Y)?
After playing with it a bit and almost give up, I discovered the map syntax to (surprisingly) work in HQL. Assuming the class looks like:
class SomeClass {
Map pairKeyProperty
}
You can build queries that look like the following:
select * from SomeClass sc where sc.pairKeyProperty['someKey'] = 'someValue' and sc.pairKeyProperty['someOtherKey'] = 'someOtherValue'
Pretty neat! I still would prefer to use criterias as they are much cleaner to compose, but they seem to not support the same syntax (or I couldn't find it).
I created a sample app in GitHub:
https://github.com/deigote/grails-simple-map-of-string-value-pairs
It can be visisted at:
http://grails-map-of-string-pairs.herokuapp.com/
The form above uses a cross join. To enforce an inner join use
join sc.pairKeyProperty pk1 on index(pk1) = 'someKey'
where 'someValue' in elements(pk1)

Grails : how to customize order with a sql function?

I want to retrieve the 10 nearest geolocalized objects using Gorm.
To do so, I would like to customize the order() parameter in order to use a get_distance(longitude, latitude, :longitude, :latitude) sql function.
I've been struggling with this all day, does anybody have a hint ?
Thanks !
EDIT
I finally managed to do what I wanted but with a very ugly solution :
I added a sqlProjection in which I put my get_distance() function and was able to order by it.
Adding a projection removes the retrieval of the object properties so I had to explicitly ask for it by adding property projections and I managed to do it with introspection.
Then I had to define the result transformer of the criteria for it to give me domain instances.
If register your function with the hibernate SQL dialect, then you can use it in HQL queries. For example, put this in your bootstrap code:
import org.hibernate.dialect.function.SQLFunctionTemplate
import org.hibernate.Hibernate
def dialect = applicationContext.sessionFactory.dialect
def getDistance = new SQLFunctionTemplate(Hibernate.INTEGER, "get_distance(?1,?2)")
dialect.registerFunction('get_distance', getDistance)
Then you can use it in HQL:
Location.executeQuery(
"""
select id, get_distance(latitude, longitude) as distance
from Location
order by distance
""",
[], [max: 10])
What we did is the following:
Create the query with whatever DB specific operators, but as a view
Create a new domain class object solely to map to the view, thereby allowing you to do GORM criteria queries and the like

Jena UpdateFactory

I was wondering if it was possible to create a SPARQL UpdateRequest in Jena by using ARQ Op objects. I would be interested to create programmatically updates like this:
DELETE {?s :predicate <http://example.org#old> }
INSERT {?s :predicate <http://example.org#toAdd>}
WHERE {?s :predicate <http://example.org#old> }
by creating the patterns in the DELETE, INSERT, and WHERE clauses from the ARQ API.
So far the only ways I have found to create SPARQL Update requests require to parse a SPARQL string or to create a com.hp.hpl.jena.update.Update object (which uses QuadAcc objects for which I couldn't find examples of use.
My fear is that the management of SPARQL UPDATE requests and the one of SPARQL SELECT queries are separated and that ARQ cannot be used to 'assemble' queries on the fly.
Thanks in advance
This question also burned me. I wanted to compose an UpdateRequest from ElementGroup objects and ElementTriplesBlock objects. This are the two main classes used to construct a Query. For example:
ElementGroup queryPattern = ...
ElementTriplesBlock constructTriples = ...
Query query = new Query();
query.setQueryConstructType();
// set CONSTRUCT clause
query.setConstructTemplate(new Template(constructTriples.getPattern()));
// set WHERE clause
query.setQueryPattern(queryPattern);
I tried the Jena mailing-list and received this answer:
The Update API is designed to deal with streaming arbitrarily large
unbounded INSERT and DELETE data hence the use of QuadAcc rather than
an Element for the INSERT/DELETE portion of the update.
Eventually I implemented this using a ParametrizedSparqlString:
ElementGroup queryPattern = ...
ElementTriplesBlock deleteTriples = ...
ElementTriplesBlock insertTriples = ...
ParameterizedSparqlString qstring = new ParameterizedSparqlString();
// Set DELETE clause
qstring.append("DELETE {");
qstring.append(deleteTriples.toString());
qstring.append("}");
// Set INSERT clause
qstring.append("INSERT {");
qstring.append(insertTriples.toString());
qstring.append("}");
// Set WHERE clause
qstring.append("WHERE {");
qstring.append(queryPattern.toString());
qstring.append("}");
// Construct an update query
UpdateRequest request = qstring.asUpdate();
I haven't tried this myself, but it looks like creating Update objects and assembling them into an UpdateRequest is indeed the way to go.
After a short look, QuadAcc doesn't seem particularly difficult, just use addTriple() with triples that contain variables.
The UpdateModify subclass of Update looks particularly interesting, it corresponds to the DELETE … INSERT … WHERE pattern in your example. Unfortunately the WHERE clause is initialised with an Element (syntactic representation of a query part) rather than an Op (algebraic representation).

Can Doctrine_RawSql be used with sfDoctrinePager?

I have a complex query that needs to be performed on given relationships (INNER JOINS) that are not defined in the Symfony schema. The query itself already takes quite some time, so I've opted to exclude it from the Doctrine schema and elected to use raw queries isntead. However, I would still like to to use the Doctrine pagination within the Symfony framework. Is this possible?
Yes it is.
After you create the query with Doctrine_RawSql you just have to add it to the pager. For example:
$query = new Doctrine_RawSql();
$query->addComponent('a', 'Class')->where('a.id = ?', 1);
$pager = new sfDoctrinePager('Class', 25);
$pager->setQuery($query);
$pager->init();

Resources