Giter VIP home page Giter VIP logo

honeyeql's Introduction

HoneyEQL

HoneyEQL is a Clojure library enables you to query the database declaratively using the EDN Query Language(EQL). It aims to simplify the effort required to work with the relational databases in Clojure. It also provides database modification operations support using Clojure maps with namespace qualified keys.

Clojars Project

Supports Postgres (9.4 & above) and MySQL (8.0 & above)

Rationale

When a query involves more than one table, the declarative nature of SQL depreciates. Depends on the type of relationship, we have to put appropriate join conditions.

Let's assume that we have the following schema.

To get all the films of an actor with the id 148 along with his/her first name & last name, we have to query it as

(jdbc/execute! ds ["SELECT actor.first_name, actor.last_name, film.title
                    FROM actor
                    LEFT OUTER JOIN film_actor ON film_actor.actor_id = actor.actor_id
                    LEFT OUTER JOIN film ON film_actor.film_id = film.film_id
                    WHERE actor.actor_id = ?" 148])

The query result would look like

[{:actor/first_name "EMILY", :actor/last_name "DEE", :film/title "ANONYMOUS HUMAN"}
 {:actor/first_name "EMILY", :actor/last_name "DEE", :film/title "BASIC EASY"}
 {:actor/first_name "EMILY", :actor/last_name "DEE", :film/title "CHAMBER ITALIAN"}
 ...]

Then we need to do the group by operation on the first_name & last_name attributes at the application layer to get the exact result result that we want!

How about making these steps truly declarative?

With HoneyEQL, we can do it as

(heql/query-single 
  db-adapter  
  {[:actor/actor-id 148] 
   [:actor/first-name 
    :actor/last-name 
    {:actor/films 
     [:film/title]}]})

The above query yields the results in the exact-shape that we wanted and without any explicit data transformations.

{:actor/first-name "EMILY"
 :actor/last-name "DEE"
 :actor/films [{:film/title "ANONYMOUS HUMAN"}
               {:film/title "BASIC EASY"}
               {:film/title "CHAMBER ITALIAN"}
               ...]}

As the query syntax is made up of Clojure's data structures, we can construct it dynamically at runtime.

HoneyEQL transforms the EQL into single efficient SQL and query the database using next.jdbc.

Documentation

cljdoc badge

Running Tests

> ./test/database/start.sh # starts four docker containers
> clj -X:test # run after all the docker container started running
> ./test/database/stop.sh # stops all the four running docker containers

Acknowledgements

Walkable is the inspiration behind HoneyEQL.

HoneyEQL is not possible without the following excellent Clojure libraries.

The samples in the documentation of HoneyEQL uses the Sakila database from JOOQ extensively.

License

The use and distribution terms for this software are covered by the Eclipse Public License - v 2.0. By using this software in any fashion, you are agreeing to be bound by the terms of this license.

honeyeql's People

Contributors

dekelpilli avatar demystifyfp avatar tamizhvendan 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

honeyeql's Issues

Support MariaDB?

MariaDB should be the same as MySQL for most intents and purposes, but the JDBC product name differs.

I did a quick attempt in the REPL, and if I hack honeyeql.meta-data/fetch to override the "MariaDB" db-product-name with "MySQL" it does look like the adapter is intialized correctly (entity meta-data looks correct).

But I can't seem to get any results, the result is empty (adding a tap> listener to trace the SQL, the query looks correct). Perhaps some other place requires changes as well?

Support for in-memory databases (h2) for tests?

Hi,

It would be nice to have honeyeql work with in-memory databases. I don't think it should do much - just start initially.

While playing around with graphqlize I've tried to fix the failing test in graphqlize-demo. I had no success.

I think it should be usefull for tests. Another option would be to use docker containers for tests.

This is what I get for using an H2 datasource.

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.graphqlize.java.springboot.GraphQLizeResolverProvider]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: No method in multimethod 'get-db-config' for dispatch value: H2
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:216)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310)
	... 129 more
Caused by: java.lang.IllegalArgumentException: No method in multimethod 'get-db-config' for dispatch value: H2
	at clojure.lang.MultiFn.getFn(MultiFn.java:156)
	at clojure.lang.MultiFn.invoke(MultiFn.java:229)
	at honeyeql.meta_data$fetch.invokeStatic(meta_data.clj:328)
	at honeyeql.meta_data$fetch.invoke(meta_data.clj:324)
	at honeyeql.db$initialize.invokeStatic(db.clj:12)
	at honeyeql.db$initialize.invoke(db.clj:7)
	at graphqlize.lacinia.core$schema.invokeStatic(core.clj:39)
	at graphqlize.lacinia.core$schema.invoke(core.clj:38)
	at graphqlize.java_interop$initialize.invokeStatic(java_interop.clj:10)
	at graphqlize.java_interop$initialize.invoke(java_interop.clj:9)
	at clojure.lang.Var.invoke(Var.java:384)
	at org.graphqlize.java.GraphQLizeResolver.<init>(GraphQLizeResolver.java:17)
	at org.graphqlize.java.springboot.GraphQLizeResolverProvider.<init>(GraphQLizeResolverProvider.java:16)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:203)
	... 131 more

There is also a few versions of sakila db for h2.
https://github.com/maxandersen/sakila-h2

Compound foreign keys are not joined correctly

I have a table defined like this:

CREATE TABLE IF NOT EXISTS merged_pull_request_user (
  scm_repo_id INT NOT NULL,
...
  FOREIGN KEY (scm_repo_id, pull_request_number)
    REFERENCES pull_request(scm_repo_id, pull_request_number)
...

However, honeyeql is only taking one column of the compound key. The attribute joining merged_pull_request_user to pull_request is :merged-pull-request-user/pull-request-by-pull-request-number, and the generated query only joins on pull_request_number.

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.