I have a String array (String[]) containing several String objects representing XPath queries. These queries are predetermined at design time. This array is passed to an object who executes the queries and then returns a Map<String, ArrayList<String>> with the results.
The map is made like this:
{Query that originated the result, Results vector}
Since I have to take these results and then perform some work with them, I need to know the individual queries. e.g.:
ArrayList<String> firstQueryResults = xpathResults.getObject(modelQueries[0]);
... logic pertaining only to the first query results ...
Retrieving the results by an integer (in the case of the first query, "0") doesn't seem nice to me, so I was wondering if there would be the possibility to identify them via enum-like constants, for better clarity:
... = xpathResults.getObject(QueryDictionary.MODEL_PACKAGE);
... = xpathResults.getObject(QueryDictionary.COMPONENT_PACKAGE);
OR
... = xpathResults.getObject(ModelQueries.PACKAGE);
... = xpathResults.getObject(ComponentQueries.PACKAGE);
I thought of using maps (i.e. Map<String, String> as in Map {ID, Query}) but I have still to reference the queries via an hardcoded string (e.g. "Package").
I also thought of using enums but i have several query sets (Model, Component, ...) and I also need to get all the query in a set in a String[] form in order to pass them to the object who performs the queries.
You can use a marker interface:
public interface QueryType {
}
Then your enums can implement this interface:
public enum ModelQueries implements QueryType {
...
}
public enum ComponentQueries implements QueryType {
...
}
and so on.
Then your getObject method can accept a parameter of type QueryType. Were you looking for something like this? Let me know if I haven't understood your question properly.
Related
So I have an abstract class that prepares my query up to after where clause. It looks something like this:
SelectConditionStep<Record2<Integer, String>> whereQuery = dslContext.select(FOO.DIGITS, FOO.WORD)
.from(FOO)
.where(/*some conditions*/);
It then returns whereQuery and that instance is used by concrete implementations to add stuff onto it.
Is it possible to make this call return SelectConditionStep<MyClass> so that I don't have to write all Record types in method signature (note that this is a simplified version, imagine having Record10). MyClass would, in this example, have two fields, Integer and String fields.
Or if not that, is there any other way to do it.
I am using Postgres as a db
Assuming you have an immutable POJO MyClass, e.g. a Java 16 record:
record MyClass(int digits, String word) {}
You could use a nested record to achieve something similar:
Select<Record1<MyClass>> whereQuery =
ctx.select(row(FOO.DIGITS, FOO.WORD).mapping(MyClass::new))
.from(FOO)
.where(...)
Suppose that I have a table with a column categories where values are separated by comma. I make a custom converter that accepts raw string from the database and returns Set<String>. Here is the entity
#Entity
public MyEntity {
#Convert(converter = StringToSetConverter.class)
private Set<String> categories;
}
Now I want to filter the entities by categories presence. Logic tells me that I cannot use in predicate, because the actual value in the database is a raw string.
Maybe this approach is acceptable
myEntityRepository.findAll((root, query, criteriaBuilder) ->
criteriaBuilder.like(
criteriaBuilder.lower(root.get("categories").as(String.class))
pattern.toLowerCase()
)
);
Perhaps there is a more elegant way to solve this problem?
The solution is fine. Depending on the database you are using, you could use array types on the database though and use array contains functions instead to implement these checks, but if what you have now works for you, there is no need to change that.
Long story short, I am using JDBI DAO to access data. It is hard to have a query with a dynamic order in it. So I am planning to use a Java 8 stream to perform this as a post processing step after the query results are fetched.
The problem is the way the comparator works by having to declare a method of the object statically.
shepherds = shepherds.stream()
.sorted(Comparator.comparing(Shepherd::getId).reversed())
.collect(Collectors.toList());
How can I do this dynamically with what will be variables like this
orderBy = id
orderDirection = ASC
So that I can paramaterize this method call?
e.g.
if(orderDirection.equals("ASC"))
shepherds.stream().sorted(Comparator.comparing(orderBy));
else
shepherds.stream().sorted(Comparator.comparing(orderBy).reversed());
The simplest way is to probably build a Map (unless you really can't do that on the DB side, which should be your main focus), where the Key would look like :
class Key {
String field;
Direction direction; // enum
// getters/setters/hashcode/equals
}
And simply create this Map upfront:
Map<Key, Comparator<Shepherd>> map = new HashMap<>();
map.put(new Key("id", Direction.ASC), Comparator.comparing(Shepard::getId))
map.put(new Key("id", Direction.DESC), Comparator.comparing(Shepard::getId).reversed())
The other way, I think it would be possible to create this really dynamically via LambdaMetafactory, but it is rather complicated.
I deal a lot with the pre-generics like Maps with Strings as the keys. They are mapping the keys to one of the following types of values:
Another Map
A List
Primitives wrappers
You can access the collection content using either XPath or queries like that:
myMap/FIRST_LIST[2]/SECOND_LIST[1]/MY_MAP/MY_PRIMITIVE
What I am looking for is a library that would allow me to apply a visitor function to the multiple elements of a collection. The basic functionality could look like that
MyMapBrowser browser = new MyMapBrowser(myMap);
browser.applyVisitor("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE",
new AbstractVisitor<String>() {
visit(String s) {
// do something with the strings
}
});
It would be also wonderful to have a possibility to first register multiple visitors for various levels of collection and then start the visiting iteration. It could look like this:
browser.registerVisitor(SECOND_LIST, new AbstractVisitor<MyList> { ... )
browser.doVisiting("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE");
In fact I've already started implementing a browser like that but I can't get rid of an impression that I'm reinventing the wheel.
Have you looked into JXPath? It lets you use XPath expressions to query and manipulate Java object graphs. The JXPathContext class lets you iterate over the values of selected nodes if you just want to extract the string values, or you can use the selectNodes method to get JDOM wrappers.
For instance, I think your example query would look something like:
// untested
JXPathContext context = JXPathContext.newContext(myMap);
Iterator iter = context.iterate("FIRST_LIST/SECOND_LIST/MY_MAP/MY_PRIMITIVE");
while (iter.hasNext()) {
String str = (String) iter.next();
// do something with strings
}
Unfortunately I haven't actually worked with JXPath (though I've also tried implementing an XPath-like traverser before too), but apparently you can also configure it to automatically create objects for a particular path. I didn't see any visitor functionality, but the iterate, getValue, and setValue should be able to accomplish the same thing. You could also rig up a simple wrapper class to run the query, iterate through the nodes, and pass the values to your own visitor interface. Something like:
public class JXPathVisitBrowser {
private JXPathContext context;
public JXPathVisitBrowser(Object object) {
context = JXPathContext.newContext(object);
}
public <T> void applyVisitor(String query, AbstractVisitor<T> visitor) {
Iterator iter = context.iterate(query);
while (iter.hasNext())
visitor.visit((T) iter.next());
}
}
There's a pretty detailed JXPath user guide too.
Take a look on LambdaJ. I think this is what you are looking for.
Since the play documentation on models is terrible I'll ask here. I have the basic code;
public static void Controller() {
List<Item> item = Item.find("SELECT itemname,id FROM Item WHERE itembool = true ORDER BY itemcreated ASC LIMIT 0,1").fetch();
if ( item == null ) {
notFound();
}
}
What I'm trying to do is get the value for 'itemname' returned for the first value returned from an SQL query (The real query is much more complicated and other things so it can't be replaced with methods). I can get the entire first object with item.get(0) but I can't figure out how to get the value of 'itemname' as a string and it doesn't seem to be documented anywhere.
Edit
Probably should have mentioned in the original question, I need to retrieve by field name, not index. I.E. I can't do items.get(0)[0]; I need to do items.get(0)['itemname'];
The documentation explains this if you read it, in here. Hibernate doesn't use SQL, but JPQL, which has a different syntax as it works with objects, not individual fields.
What you want to do can be achieved in two ways (both in the documentation):
List<Item> item = Item.find("SELECT i FROM Item i WHERE i.itembool = true ORDER BY i.itemcreated ASC").fetch(1);
List<Item> item = Item.find("itembool = true ORDER BY itemcreated ASC").fetch(1);
EDIT:
On the retrieval part, you will get a list of Item, so you can just access the field directly on the object:
item.get(0).getItemName();
Since Play uses Hibernate under the hood, you need to take a look at Hibernate's documentation.
In particular, SELECT itemname,id ... yields Object[] rather than Item, so that you can get itemname as follows:
List<Object[]> items = ...;
String itemname = items.get(0)[0];
well if you have to do a select itemname,id ..., you would not be able to do a items.get(0)["itemname"] because as axtavt and Pere have mentioned, you would get a Object[] back. You can instead create another (perhaps immutable) entity class that can be used in this query. Please refer to hibernate documentation for details. You can then model the entity based on your query requirements and use it to fetch information, thus letting hibernate handle all the magic number game for you. That ways, you would have a bean with filled up values that you can use to map back to your model class if you like.
HTH!