Git Product home page Git Product logo

jinq's Introduction

Jinq provides developers an easy and natural way to write database queries in Java. You can treat database data like normal Java objects stored in collections. You can iterate over them and filter them using normal Java commands, and all your code will be automatically translated into optimized database queries. Finally, LINQ-style queries are available for Java!

Jinq can also be used within Scala to provide database queries similar to Typesafe's Slick but using JPA ORMs like Hibernate.

Documentation about how to get started with Jinq and other information can be found on the Jinq project page

jinq's People

Contributors

dependabot[bot] avatar emilio-eam avatar my2iu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jinq's Issues

Unknown method java/math/BigDecimal:negate()Ljava/math/BigDecimal; encountered

I tried the following

List<Pair<String, BigDecimal>> result2
= streams
.streamAll(em, ParastatikaEntity.class)
.where(c -> c.getDate_created().after(from))
.where(c -> c.getDate_created().before(to))
.where(c -> c.getEidos().getTameio_affect() == 2)//pistotika
.where(c -> c.getSynallassomenos().getSynaltype() == 1)//gia pelates
.group(c -> c.getSynallassomenos().getName(), (name, stream) -> stream.sumBigDecimal(c -> c.getTotal_no_vat()).negate())
.toList();

Getting the following error with negate()

Caused by: org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: Unknown method java/math/BigDecimal:negate()Ljava/math/BigDecimal; encountered
at ch.epfl.labos.iu.orm.queryll2.symbolic.BasicSymbolicInterpreter.naryOperation(BasicSymbolicInterpreter.java:367)
at org.jinq.rebased.org.objectweb.asm.tree.analysis.Frame.execute(Unknown Source)
at ch.epfl.labos.iu.orm.queryll2.path.CodePath.calculateReturnValueAndConditions(CodePath.java:148)
at ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer.analyzeMethod(TransformationClassAnalyzer.java:440)

Scala sample could be improved

def customers(): JinqIterator[Customer] = { return streams.streamAll(em, classOf[Customer]); }

could be replaced by:

def customer = streams.streamAll(em, classOf[Customer]) etc. and remove the () in the uses:
customers.foreach( c => println(c.getName() + " " + c.getCountry() + " " + c.getSalary()));

(or use s"")

JPQL date methods

In JPQL we can use date functions (see this doc).

In Jinq, we can't use this because new Date() is not recognized, and in the JPQL class there is not functions to handle this case.

What are the steps required to implement something like this? Or this is not in the scope of Jinq?

Thanks for the wonderful library.

bug on sortedBy().sortedBy()

code

...streamAll(Content.class)
.where(content->content.getEntityType().equals(EntityType.Book)
&& content.getEntityId() == entityId
&& content.getType().equals(NodeType.Item)).sortedBy(content->content.getParentId()).sortedBy(content->content.getWeight())
.select((content)->new ContentModel(
content.getId(),
content.getParentId(),
content.getType(),
content.getTitle(),
content.getContent(),
content.getEntityId(),
content.getEntityType(),
content.getWeight(),
content.getIndex()
)
);

is translated to:

SELECT A FROM Content A WHERE A.entityType = com.jingfangpai.common.statics.EntityType.Book AND A.entityId = :param0 AND A.type = com.jingfangpai.common.statics.NodeType.Item ORDER BY A.weight ASC, A.parentId ASC

the sorting field are not in order.

AnalyzerException: Unknown method org/jinq/orm/stream/scala/JinqIterator:sumBigDecimal(Lscala/Function1;)Ljava/math/BigDecimal;

Running this code, based on the sample:

  lineorders.where(_.getSale.getCustomer.getDebt > 0)
    .group(_.getSale.getCustomer, (c: Customer, s)=> s.sumBigDecimal(_.getTotal) )
    .sortedBy(_._2)

similar to the Java code (which works):

  lineorders().where(l->l.getSale().getCustomer().getDebt() > 0)
          .group(l2 -> l2.getSale().getCustomer(), (customer, stream) -> stream.sumBigDecimal(l -> l.getTotal()))
          .sortedBy(p -> p.getTwo())

gives the following exception:

Exception in thread "main" java.lang.IllegalArgumentException: Could not analyze lambda code
at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeClassAsLambda(LambdaAnalysis.java:123)
at org.jinq.jpa.transform.ScalaLambdaInfo.fullyAnalyze(ScalaLambdaInfo.java:25)
at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambdas(JPAQueryComposer.java:320)
at org.jinq.jpa.JinqJPAScalaIterator.groupToTuple(JinqJPAScalaIterator.scala:221)
at org.jinq.jpa.JinqJPAScalaIterator.group(JinqJPAScalaIterator.scala:226)
at SampleMain.runSampleQueries(SampleMain.scala:74)
at SampleMain$.main(SampleMain.scala:26)
at SampleMain.main(SampleMain.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Unknown method org/jinq/orm/stream/scala/JinqIterator:sumBigDecimal(Lscala/Function1;)Ljava/math/BigDecimal; encountered
at ch.epfl.labos.iu.orm.queryll2.symbolic.BasicSymbolicInterpreter.naryOperation(BasicSymbolicInterpreter.java:367)
at org.objectweb.asm.tree.analysis.Frame.execute(Unknown Source)
at ch.epfl.labos.iu.orm.queryll2.path.CodePath.calculateReturnValueAndConditions(CodePath.java:148)
at ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer.analyzeMethod(TransformationClassAnalyzer.java:365)
at ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer.analyzeLambdaMethod(TransformationClassAnalyzer.java:331)
at org.jinq.jpa.transform.LambdaAnalysis.analyzeLambdaClass(LambdaAnalysis.java:238)
at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeClassAsLambda(LambdaAnalysis.java:113)
... 12 more

OR ing together expressions that involve NULL doesn't work properly

Bien Ly Ngoc noted that:

stream.where(n -> n.getAccount().getId() == accoutId || n.getAccount() == null) ...

is being translated as the HQL

WHERE A.account.id = :param0 OR A.account.id <> :param1 AND A.account IS NULL

which gives the resulting SQL:

WHERE ACCOUNT_ID = 1 OR ACCOUNT_ID <> 1 AND ACCOUNT_ID IS NULL;

Which is not correct since when ACCOUNT_ID is NULL, ACCOUNT_ID <> 1 evaluates to UNKNOWN (ie FALSE)

Support returning Iterable, as Spring JPA

It probably would be nice if, in addition to the ".iterator()", it would be supported a ".iterable()" that return a Iterable as result, as is possible with JPA with Spring.

Add support for translating instanceof

Hey

I have a super class which is extended by sub class, the super class has a Discriminator Column and each sub class has its own Discriminator value, Lets say that Animal is the super class , Cat is the sub class

now if I try this

 where(animal -> animal instanceof Cat) 

it throws an Exception

Exception in thread "main" java.lang.IllegalArgumentException: Could not analyze lambda code
org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: 
Unhandled bytecode instruction

Note that, we dont have an attribute that maps to the discriminator column, but even if we could add it and then JinQ was able pick it up and use it instead of instance of, it will still be a work around and not a perfect solution

is there any possible way to detect inheritance ?

I think since JPA 2.0, there is a TYPE command, and I think also it can detect the discriminator column.
http://stackoverflow.com/questions/7807608/how-to-create-an-instance-of-like-query-in-jpa-2-0

SpringData Page support

Hi!

There is any way to get the Query object (before the run but after the fillQueryParameters) ? I want to call with Spring Data Pageable object to get paged result. Or JINQ have another way to create spring boot Page object? (It need the total number of result, not just the "page")

Create and use Pojos in queries

Currently one has to use Pair or Tuple2,3,... to compine multiple values. Would it be possible to support creating and using (immutable) POJOs?

This would be extremely helpful for One-To-One mapped joins, as no Collector is needed to be written. It would also simplify reading huge queries, as foo.bar().baz().qux is easier to read and keep in mind than pair.getOne().getOne().qux.

Joining entites even if not needed

Lets say I have 3 EntitiesE1, E2 and E3 now If I create a stream that joinsE1, E2 and then left outer join E3 but only select a pair of E1, E2, the translated query still joins E3.

So basically IMO it should be something like that

  • if E3 is (selected/used by a selected element) then perform the join
  • If E3 was not selected but joined with other entities then
    • if the joins where outer and are not included in the selection, do not join them all
    • if the joins where outer and are included also in the selection, join them all
    • if the joins where inner then do the joins
  • if E3 is neither selected nor joined, do not perform the join

Is there a way to avoid that ?

The general idea is, to try to create a query that is a bit general, which I might us as is, or use a more specific version of it by selecting tuned entities on API levels, other than creating several custom queries for each API call

Example Code:
The entities join may or may not make sense but the idea is there.

   @Test
   public void Test(){
      JinqStream<Tuple3<Customer,Sale,Lineorder>> customers = streams.streamAll(em, Customer.class)
           .join((val, source) -> source.stream(Sale.class))
           .where(pair -> pair.getOne().getSales().contains(pair.getTwo()))
           .select(pair -> new Pair<Customer,Sale>(pair.getOne(),pair.getTwo()))
           .leftOuterJoin(t -> JinqStream.from(t.getTwo().getLineorders()))
           .select(tuple3 -> new Tuple3<Customer, Sale, Lineorder>(tuple3.getOne().getOne(),tuple3.getOne().getTwo(),tuple3.getTwo()))
           ;


      // Now if I do a modification on this stream, and ask only for Customers and Sales
         JinqStream<Pair<Customer,Sale>> customersWithoutLineOrders =
                 customers.select(pair -> new Pair<Customer, Sale>(pair.getOne(),pair.getTwo()));

         String query = customersWithoutLineOrders.getDebugQueryString();

      // Now the resulting query should not include the join for Lineorders because its neither selected nor used in any further joins
      assertNotEquals("SELECT A, B FROM Customer A, Sale B LEFT OUTER JOIN B.lineorders C WHERE B IN (SELECT D FROM A.sales D)", query);

      // The resulting query should only include Customers and Sales join
      assertEquals("SELECT A, B FROM Customer A, Sale B WHERE B IN (SELECT C FROM A.sales C)", query);

   }

Another Example is a useless join

 JinqStream<Pair<Customer,Sale>> customers = streams.streamAll(em, Customer.class)
           .join((val, source) -> source.stream(Sale.class))
           .where(pair -> pair.getOne().getSales().contains(pair.getTwo()))
           .select(pair -> new Pair<Customer,Sale>(pair.getOne(),pair.getTwo()))
           .leftOuterJoin(t -> JinqStream.from(t.getTwo().getLineorders()))
           .select(pair -> new Pair<Customer,Sale>(pair.getOne().getOne(), pair.getOne().getTwo()))
              ;

Fix need for registerAssociationAttribute

From the sample:

  // Hibernate seems to generate incorrect metamodel data for some types of
  // associations, so we have to manually supply the correct information here.
  streams.registerAssociationAttribute(Lineorder.class.getMethod("getSale"), "sale", false);

Why is this, and is it solvable? With this requirement for all relations it seems, it is not practical to use Jinq with JPA. Maybe it is possible to get it from the @OneToMany etc. annotations?

leftOuterJoin JoinWithSource support

Hi!
Possible to create leftOuterJoin with JoinWithSource implementation?
I have 3 table.
I18NMaster <-> I18N <-> Language

I want to select all I18NMaster field in all Language, and where exists, I want the I18N localized text...

b0c1

IgnoreCase problem

deal.getInstrument().getName().toLowerCase().equals(instrumentNameLowerCase)
is working greatly
Unfortunately
deal.getInstrument().getName().equalsIgnoreCase(instrumentName) is not working as expected.

Is it possible to map that equaslsIgnoreCase match SQL UPPER (string1) UPPER(string2) or same thing for lower?

How to use Jinq with xtend

My code is below:
streams.streamAll(em, typeof(Customer))
.where[o|o.name=="Bob"].toList()
.forEach[println(it.name)]

xtend translate the code to below:
JPAJinqStream _streamAll = SampleMain.streams.streamAll(this.em, Customer.class);
final JinqStream.Where<Customer, Exception> _function = (Customer o) -> {
String _name = o.getName();
return Objects.equal(_name, "Bob");
};
JPAJinqStream _where = _streamAll.where(_function);
List _list = _where.toList();
final Consumer _function_1 = (Customer it) -> {
String _name = it.getName();
InputOutput.println(_name);
};
_list.forEach(_function_1);

 but  it generate erros:
            Exception in thread "main" java.lang.IllegalArgumentException: Could not analyze lambda code
at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeLambda(LambdaAnalysis.java:197)
at org.jinq.jpa.transform.LambdaInfo.fullyAnalyze(LambdaInfo.java:116)
at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:293)
at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:379)
at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:1)
at org.jinq.orm.stream.QueryJinqStream.where(QueryJinqStream.java:45)
at org.jinq.jpa.QueryJPAJinqStream.where(QueryJPAJinqStream.java:87)
at SampleMain.runSampleQueries(SampleMain.java:79)
at SampleMain.main(SampleMain.java:52)

Caused by: org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: Unknown static method com/google/common/base/Objects:equal(Ljava/lang/Object;Ljava/lang/Object;)Z encountered
at ch.epfl.labos.iu.orm.queryll2.symbolic.BasicSymbolicInterpreter.naryOperation(BasicSymbolicInterpreter.java:385)
at org.jinq.rebased.org.objectweb.asm.tree.analysis.Frame.execute(Unknown Source)
at ch.epfl.labos.iu.orm.queryll2.path.CodePath.calculateReturnValueAndConditions(CodePath.java:148)
at ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer.analyzeMethod(TransformationClassAnalyzer.java:440)
at ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer.analyzeLambdaMethod(TransformationClassAnalyzer.java:406)
at org.jinq.jpa.transform.LambdaAnalysis.analyzeLambda(LambdaAnalysis.java:318)
at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeLambda(LambdaAnalysis.java:187)
... 8 more

sortedBy doesn't seem to work on runtime composition

`JinqJPAStreamProvider streams = new JinqJPAStreamProvider(MainApp.getEmf());

    EntityManager em = MainApp.getEmf().createEntityManager();

    JinqStream<SynallassomenoiEntity> stream = streams.streamAll(em, SynallassomenoiEntity.class);

    String eponimia = eponTextField.getText();

    if (eponimia.length() > 0) {

        if (eponimiaCombo.getSelectionModel().getSelectedIndex() == 0) {

            stream = stream.where(p -> p.getName().equals(eponimia));

        }

        if (eponimiaCombo.getSelectionModel().getSelectedIndex() == 1) {

            stream = stream.where(p -> JPQL.like(p.getName(), eponimia + "%"));

        }

        if (eponimiaCombo.getSelectionModel().getSelectedIndex() == 2) {

            stream = stream.where(p -> p.getName().contains(eponimia));

        }

        if (eponimiaCombo.getSelectionModel().getSelectedIndex() == 3) {

            stream = stream.where(p -> JPQL.like(p.getName(), "%" + eponimia));

        }

    }
    stream.sortedBy(p -> p.getName());
    showndata = stream.toList();

`
it returns the list unsupported...

Add automatic support for boolean getters named isField() instead of getField()

Jinq currently expects boolean getters to be of the form getField() because that seemed to be the default of JPA providers. Supporting isField() requires programmers to manually register the methods with Jinq which can be annoying.

I'll have to find an example of isField() in a JPA entity first to get a feel for how different JPA providers handle them.

Make the project available in Maven Central

It is pre-requisite for any modern project. The best would be to just restructure it for Maven. There is also EntityGenerator that will need a Maven plugin so the consumers can integrate it into their projects easily.

I can help with all that but the transition will require moving a lot of files and could not be done in parallel with a significant amount of other work... But anyway it is best for the project to do it early.

Also there is a question about the package names, the project now is under jinq.org umbrella but there are a lot of stuff in ch.* packages. It there is no good reason to keep them there it would be good to also change packaging so it is associated with the project, i.e. org.jing.*

SQL "LIKE" statement

Hi again Ming,

I'm trying to query a table with a "LIKE" expressión removing diacritical marks. Something like:

private String clean(String name) {
    String result = Normalizer.normalize(name, Normalizer.Form.NFD);
    return result.replaceAll("[\\p{InCombiningDiacriticalMarks}]", "");
}

...

JinqJPAStreamProvider streams = new JinqJPAStreamProvider(entityManager.getMetamodel());
JPAJinqStream<Master> reportsStream = streams.streamAll(entityManager, Master.class);

List<Master> records = reportsStream
        .where(master -> clean(master.getName()).indexOf("values") > 0)
        .toList();

But i get an error:

java.lang.IllegalArgumentException: Could not extract code from lambda. This error sometimes occurs because your lambda references objects that aren't Serializable.
    at org.jinq.jpa.transform.LambdaInfo.analyze(LambdaInfo.java:33)    

Do you know it there's any way to perform this operation?

BTW i had to use "indexOf" becuase "contains" was not working :(

Thanks a lot for your help and best regards,
Ricardo

Allow a where() after a sortedBy()

That's probably safe. Also, possibly allow a select() after a sortedBy(). And when something isn't allowed, create a better error message (possibly with a URL to the chart showing what's allowed).

Support for native Database functions

Can you please add support for calling database functions with Jinq?

In JPA 2.1 Support for calling database functions was added. It can be reviewed in the JPA 2.1 Specification on Page 193:

4.6.17.3 Invocation of Predefined and User-defined Database Functions
The invocation of functions other than the built-in functions of the Java Persistence query language is supported by means of the function_invocation syntax. This includes the invocation of predefined database functions and user-defined database functions.

In eclipselink it is implemented since version 2.4, i don't know about hibernate though.

I would have the following suggestions:

Add .function(...)

I imagine this to be the simpler one to implement but rather hard and inflexible to use

Let users add java-method-references with their database-function-string to JinqJPAStreamProvider

For example Math.ceil() could be added and translated like this:

streams.addNativeFunction(Math::ceil, "CEIL")
streams.streamAll(em, Book.class)
    .select(b -> new Pair(b.getName(), Math.ceil(b.getPrice())))

could get translated into

SELECT b.name, FUNCTION("CEIL", b.price) FROM Book b

How would this work for non-static methods? If I have the instance of an object and mapped one of this object's methods, could this case still be analyzed?

Multiple SuperTypes ignorred

When you extend classes with more than one @MappedSuperclass, only first one getters are put in safeMethods hash, and throws error on analyzing labda expression. In my case i try to call getId which is 2nd Superclass.
Example:

class BaseEntity { private int; public int getId();}
class BaseVersion extend BaseEntity {...}
class Product extend BaseVersion {...}

Product is missing all functions from BaseEntity, reason for that is in file and line
https://github.com/my2iu/Jinq/blob/master/jinq-jpa/main/org/jinq/jpa/transform/MetamodelUtil.java#L360

you make new array, not sure why but you forget to include previous subClasses.
Change code
FROM:
List newSubclasses = new ArrayList<>();
newSubclasses.add(className);
findMetamodelEntityGetters(jpaObject, newSubclasses);

TO:
List newSubclasses = new ArrayList<>(subclassNames);
newSubclasses.add(className);
findMetamodelEntityGetters(jpaObject, newSubclasses);

Cache or Precompile queries

I really love the abstraction of Jinq, but the analysis of complex queries takes a lot of time compared to JPQL-Queries or native SQL queries. Would it be possible to cache Jinq queries, which have already been analyzed, or better, to have a maven/gradle/... compiler plugin precompiling Jinq into JPQL or even already SQL?

I'm not sure on how to cache queries, i.e. how to identify them; mainly just brainstorming here :)

Precompilation could for example be done with lombok. This could mean, that queries, which should be precompiled, need to be annotated. Problems here could be (a) having queries propagating through multiple functions and (b) analyzing the "settings" of the JinqJPAStreamProvider (e.g. hints or native database function mapping (if this will be implemented)).

case insensitive in strings

I am looking a way to search string functions (compare , startsWith ) with case insensitive. Is there a a way to do that?

Using a method inside where

Hello,

I am trying to have methods inside my where statement. Here is a simplified example:

Collection<ExperimentLog> experimentLogs = experiments(entityManager)
               .where(log -> test(log.getGroupid(), groupid))
                .sortedDescendingBy(log -> log.getSubmittime())
                .limit(20)
                .toList();

And my test method looks like this one:

private boolean test(int test, int groupid) {
        return test == groupid;
    }

However, I get the following error:

java.lang.IllegalArgumentException: Lambda has an unknown format (an unsupported type of method handle is possibly being used here)
    at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeLambda(LambdaAnalysis.java:176)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

My understanding of streams and lambda in java 8 is very limited. I would appreciate any help.
Thanks!

can just suport 'select new xxxobj()' statement ?

like this:

.where(xxxx)
.select(m -> new UserWalletModel(m.getId(), m.getName(), m.getWallet().getBalance()))
.toList();

as like HQL:

.createQuery("select new com.yzx.discover.model.UserWalletModel(u.id, u.name,u.wallet.balance) " +
"from UserEntity u " +
"where u.wallet.balance > :balance")
.setParameter("balance", balance)
.list();

Add support to pass parameters in crossJoin

Is possible / feasible to implement crossJoin in a way that allows passing parameters while cross-joining?

Given these methods:

public JPAJinqStream<Customer> getCustomer(long id) {
    return streams.streamAll(em, Customer.class)
        .where(c -> c.getId() == id);
}

public JPAJinqStream<Sale> getSales(List<Long> ids) {
    return streams.streamAll(em, Sale.class)
        .where(s -> JPQL.isInList(s.getId(), ids));
}

Would it be possible to implement a crossJoin taking a lambda which takes the current type as parameter and returns the new stream to join with like this?

getCustomer(1337)
    .crossJoin(c -> getSales(c.getSales()));

Join two JinqStreams

I have two queries, which are both working and translatable into sql. The elements streamed in these queries are different and not connected. If I have two pre-filtered JPAJinqStreams and want to join them on one property, Jinq tells me, it is not possible, even though in SQL it is one of the easiest things to do.

Enough on these abstract stuff, let's get to an example:
I have two classes Class1 and Class2, both of which can be tagged with class Tag. I don't want List<Tag> to be a delegate of all classes being able to be tagged (in this example Class1 and Class2).
To get all valid Tag-Class1-Pairs, this query works perfectly as expected:

streams.streamAll(em, Class1.class)
    .join((c, source) -> source.stream(Tag.class))
    .where(p -> p.getOne().getId() == p.getTwo().getTaggedId())
    .forEach(System.out::println);

Producing:

SELECT A, B FROM Class1 A, Tag B WHERE A.id = B.taggedId

Now I'd like to pre-filter both streams (e.g. permission-wise) and get them separately by calling Service-Functions:

JPAJinqStream<Class1> classStream = service.getFilteredClassStream();
JPAJinqStream<Tag> tagStream = service.getFilteredTagStream();

classStream.join(c -> tagStream)
    .where(p -> p.getOne().getId() == p.getTwo().getTaggedId())
    .forEach(System.out::println);

This for whatever reason results in java.lang.reflect.InvocationTargetException Caused by: java.lang.IllegalArgumentException: Could not extract code from lambda. This error sometimes occurs because your lambda references objects that aren't Serializable.

But actually there is no major difference semantic-wise. In the first example, I create the new stream from inside the stream. In the second example I use one from outside. In the first example source.stream produces JinqStream<U>, which is the same as getFilteredTagStream() returning JPAJinqStream<Tag> extends JinqStream<Tag>.

So my question is: How do I join two different streams, produced in different contexts?

Does not work with Java 8 method references

I tried changing this line in the sample from

.sortedDescendingBy(c -> c.getSalary()

to

.sortedDescendingBy(Customer::getSalary)

and then it fails:

Exception in thread "main" java.lang.IllegalArgumentException: Could not translate code to a query
at org.jinq.jpa.JPAQueryComposer.translationFail(JPAQueryComposer.java:113)
at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:285)
at org.jinq.jpa.JPAQueryComposer.sortedBy(JPAQueryComposer.java:377)
at org.jinq.jpa.JPAQueryComposer.sortedBy(JPAQueryComposer.java:58)
at org.jinq.orm.stream.QueryJinqStream.sortedDescendingBy(QueryJinqStream.java:247)
at org.jinq.jpa.QueryJPAJinqStream.sortedDescendingBy(QueryJPAJinqStream.java:215)
at org.jinq.jpa.QueryJPAJinqStream.sortedDescendingBy(QueryJPAJinqStream.java:12)
at SampleMain.runSampleQueries(SampleMain.java:168)
at SampleMain.main(SampleMain.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: org.jinq.jpa.transform.QueryTransformException: ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitorException: Unhandled symbolic execution operation: (this.salary)
at org.jinq.jpa.transform.SortingTransform.apply(SortingTransform.java:41)
at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:281)
... 12 more
Caused by: ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitorException: Unhandled symbolic execution operation: (this.salary)
at org.jinq.jpa.transform.SymbExToColumns.defaultValue(SymbExToColumns.java:52)
at org.jinq.jpa.transform.SymbExToColumns.defaultValue(SymbExToColumns.java:39)
at ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitor.unaryOpValue(TypedValueVisitor.java:82)
at ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitor.getFieldValue(TypedValueVisitor.java:98)
at ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValue$GetFieldValue.visit(TypedValue.java:206)
at org.jinq.jpa.transform.JPQLQueryTransform.simplifyAndTranslatePathToColumns(JPQLQueryTransform.java:110)
at org.jinq.jpa.transform.JPQLQueryTransform.simplifyAndTranslateMainPathToColumns(JPQLQueryTransform.java:102)
at org.jinq.jpa.transform.JPQLQueryTransform.makeSelectExpression(JPQLQueryTransform.java:36)
at org.jinq.jpa.transform.SortingTransform.apply(SortingTransform.java:28)
... 13 more

registerAssociationAttribute does not take Inheritance into account

I investigated the problem @SalehAly reported here a bit.

SSCCE code

I have SuperClass and an extending SubClass. SuperClass has a public getter function, which I manually register using registerAssociationAttribute. If I stream SubClass.class and try to use that getter function, I'll get AnalyzerException: Unknown method foo encountered. Even if I register the method again on SubClass (which doesn't fail because the method is inherited), I still get the same error.

Sub query support

What needs to be done to support sub-queries like below so we don't get duplicate person records? JPQL seems to support this query format. Doing a JINQ's join and distinct seems to throw up errors when combined with paging and sorting.

SELECT * FROM Person
WHERE ID IN (SELECT ToId FROM Friends WHERE FromId = :personId )

Question regarding join & fetch

Hi Ming,

First of all, Jinq seems a very promissing library in comparision to existing options like QueryDSL.
Thanks for that ;)

As i can see in the documentation, when i want to execute a JOIN and FETCH all the related records, i have to do:

List<Country> countries = 
   streams.streamAll(em, Country.class)
      .where(c -> c.getContinent.equals("Europe"))
      .joinFetchList(c -> c.getCities())
      .toList();

for (Country c: countries) {
   System.out.println("Cities in country: " + c.getName());

   for (City city: c.getCities()) {
      System.out.println("   " + city.getName());
   }
}

The problem is that using maven version 1.8.4 of Jinq, the API differs and the main entity is not filled with its related childs, executing one query per each record. See my example:

List<Pair<Master, Detail>> records = reportsStream
        .where(m -> m.getId() <= QUERY_LIMIT)
        .joinList(m -> m.getDetails())
        .toList();

for (Pair<Master, Detail> record : records)
    System.out.println(record.getOne().getDetails().size());

See also that current version doesn't offer the joinFetchList method and the return type can't be List as i would expect ...

Any clues on this?

Best regards,
Ricardo

Allow Hibernate Search usage

Being able to leverage Hibernate Search alongside JPA would be great.

A possible approach would be: if all the properties involved in the lambda function have HS annotations, then generate a HS Query instead of a JPA one.

Grouping issue

I have spend 2 days trying to figure it out but without success so i wonder if it is a bug after all..
I am trying to group some data.
If my query is

streams
.streamAll(em, ParastatikaEntity.class)
.where(c -> c.getDate_created().after(from))
.where(c -> c.getDate_created().before(to))
.where(c -> c.getEidos().getTameio_affect() == 1)
.group(c -> c.getSynallassomenos().getName(),(name,stream)-> stream.sumBigDecimal(c -> c.getTotal_no_vat()))
.forEach(pair -> System.out.println(pair.getOne() + " " + pair.getTwo()));

it works fine, if i try to put it on a List with this

List<Pair<String,BigDecimal>> result =
streams
.streamAll(em, ParastatikaEntity.class)
.where(c -> c.getDate_created().after(from))
.where(c -> c.getDate_created().before(to))
.where(c -> c.getEidos().getTameio_affect() == 1)
.group(c -> c.getSynallassomenos().getName(),(name,stream)-> stream.sumBigDecimal(c -> c.getTotal_no_vat()));

i get

incompatible types: no instance(s) of type variable(s) U,V exist so that JPAJinqStream<Pair<U,V>> conforms to List<Pair<String,BigDecimal>>
where U,V,T are type-variables:
U extends Object declared in method <U,V>group(Select<T,U>,AggregateGroup<U,T,V>)
V extends Object declared in method <U,V>group(Select<T,U>,AggregateGroup<U,T,V>)
T extends Object declared in interface JPAJinqStream

Do i miss something here?

java.io.NotSerializableException trying to run a simple query

With the following code:

@Entity
public class Product {
   private String sku;
   ...
   public Product findSkuDuplicate(ProductRepository repository) {
        Product existing = repository.all()
                .where(product -> product.sku.equals(sku))
                .getOnlyValue();
        return existing != null && existing != this ? existing : null;
    } 
   ...
}

I get the following error:

[java.lang.IllegalArgumentException: Could not extract code from lambda. This error sometim
es occurs because your lambda references objects that aren't Serializable.] with root cause
java.io.NotSerializableException: org.teavm.flavour.example.model.Product
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at com.user00.thunk.SerializedLambda.extractLambda(SerializedLambda.java:52)
    at org.jinq.jpa.transform.LambdaInfo.analyze(LambdaInfo.java:30)
    at org.jinq.jpa.transform.LambdaAnalysisFactory.extractSurfaceInfo(LambdaAnalysisFactory.java:7)
    at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:269)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:364)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:58)
    at org.jinq.orm.stream.QueryJinqStream.where(QueryJinqStream.java:45)
    at org.jinq.jpa.QueryJPAJinqStream.where(QueryJPAJinqStream.java:86)
    at org.jinq.jpa.QueryJPAJinqStream.where(QueryJPAJinqStream.java:12)
    at org.teavm.flavour.example.model.Product.findSkuDuplicate(Product.java:80)

I can alter this code to refer to temporary variable that holds this.sku, but I am still interested why do you need to serialize lambdas?

Serialize / Deserialize Jinq expressions

Is it possible to serialize / deserialize Jinq expressions/streams e.g. to send them over network?

Reasoning behind question: In a microservice environment, a nice way to provide data, which needs to be aggregated by several services would be to send over the abstract Jinq stream instead of the loaded objects.
Let's take the following example: Service A handles users and Service B handles some data related to users. Both share the same database. When I want to fetch the data object with it's creator, Service B fetches the data and gets the creator-id. It sends the creator ID to Service A, which then returns the user to Service B. Service B aggregates this information and returns the full data set to Me.
This results in 2 DB queries, which must be executed after each other.

My question is, whether the following scenario could also be done this way:
Service B creates a JinqStream, which will fetch the data object. It serializes the stream, sends it over to Service A, which, after deserialization, adds it's aggregate to the JinqStream based on the user's id. It serializes it again, sending it back to Service A, which after deserialization executes it.
This results in only one DB-Query and the procedure is far more abstract on a higher level.

Kind Regards,
BH16

"Unknown method" when using eclipselink-static-weave with Lazy-Loading

I use the eclipselink-static-weave-plugin during compile time for my entities. For relations between classes I use the annotations OneToOne,OneToMany and ManyToOne. If I use eager loading, everything will work as expected and queries execute normally. Using FetchType.LAZY on OneToMany queries also works as expected. But using lazy loading together with OneToOne or ManyToOne relational annotations, then using the field's getter-methods inside queries, I get the following exception: org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: Unknown method Sale:getCustomer()LCustomer; encountered.

These are my entities:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name="CUSTOMER_ID")
    private List<Sale> sales;
}
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Sale {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    @ManyToOne(fetch = FetchType.LAZY)
    private Customer customer;
}

The following code (joining OneToMany) works as expected:

streams.streamAll(em, Customer.class)
        .join(c -> JinqStream.from(c.getSales()))
        .forEach(System.out::println);

The following one, working with ManyToOne, produces the issue:

streams.streamAll(em, Sale.class)
        .joinFetch(s -> JinqStream.of(s.getCustomer()))
        .forEach(System.out::println);

It results in

java.lang.reflect.InvocationTargetException
Caused by: java.lang.IllegalArgumentException: Could not analyze lambda code
Caused by: org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: Unknown method Sale:getCustomer()LCustomer; encountered

Interestingly, in the decompiled class files, the method getCustomer does exist:

public Customer getCustomer() {
    return this._persistence_get_customer();
}

How get primaryKeys By Jinq ?

I add below code into JinqJPAStreamProvider:
public JPAJinqStream selectPrimaryKeys(JPAJinqStream base) {
JPAQueryComposer jpaComposer = ((QueryJPAJinqStream) base).jpaComposer;
SelectFromWhere query = (SelectFromWhere) jpaComposer.query;
SelectFromWhere copy = query.shallowCopy();
org.jinq.jpa.jpqlquery.RowReader reader = copy.getRowReader();
ColumnExpressions columnExpressions = new ColumnExpressions(reader);
columnExpressions.columns.add(new ReadFieldExpression(
((SelectOnly) (copy)).cols.getOnlyColumn(), "id"));
copy.cols = columnExpressions;
return new QueryJPAJinqStream(JPAQueryComposer.findAllEntities(
metamodel, cachedQueries, lambdaAnalyzer,
jpqlQueryTransformConfigurationFactory, jpaComposer.em, hints,
copy));
}

But there is erro in "toList" when I run below code , why?
JPAJinqStream idStream =new JinqJPAStreamProvider(getEntityManager()
.getMetamodel()).selectPrimaryKeys(stream);
List idList = idStream.toList() ;

limit error

when I use spring boot jpa with hibernate and sqlserver2014, I met the error:
Hibernate: select note0_.id as id1_0_, note0_.body as body2_0_, note0_.title as title3_0_ from Note note0_ limit ?
2015-09-03 16:27:49.846 WARN 6924 --- [tp1673604690-19] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 102, SQLState: 42000
2015-09-03 16:27:49.847 ERROR 6924 --- [tp1673604690-19] o.h.engine.jdbc.spi.SqlExceptionHelper : “limit”附近有语法错误。

why? who can help me .By th way , my jinq version is 1.8.4.

Simplify getting started page

The getting started page says that you have to download and compile Jinq to get started. It would be preferable if it let the user know that Jinq is available via Maven Central since that's how most people will want to use the library

Using boolean methods starting with is throws an Exception

Using boolean methods in entities starting with is, like isRead, throws an exception org.jinq.rebased.org.objectweb.asm.tree.analysis.AnalyzerException: Unknown method
using getRead does not..
.where(pair -> !pair.getTwo().isRead() ) throws exception

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.