Querying

So far we learnt how to create and persist entities but what about querying for such? Long story short, Glagol DSL uses a built-in SQL dialect for the purpose. In general, there are a few things to consider about the Glagol Query Language:

  • Queries can only be utilized within repository methods
  • Queries target entities not database tables
  • Queries are executed immediately
  • Queries are a type of expressions

Finding all entities

We start by creating a findAll method in the Song repository:

namespace MusicLib

repository for Song {
    public void save(Song song) {
        persist song;
        flush;
    }

    public void remove(Song song) {
        remove song;
        flush;
    }

    public Song[] findAll() {
        Song[] songs = SELECT s[] FROM Song s;

        return songs;
    }
}

Secondly, lets look closely at what we did here. Obviously, the SELECT s FROM Song s is a Glagol Query. One can easily recognize the great similarities between SQL and Glagol QL. However, think of it this way - Glagol Query Language is used to ask for entities where SQL usually queries database tables directly. Therefore, the result of a Glagol Query is either an entity or a collection of entities.

Lets break down the query from above. The first part is SELECT s[]. Simply put, we say that we want to select a list of s’s where s is just an alias defined in the FROM part. Furthermore, FROM Song s is exactly the part where we first select the target entity and then we alias it so it can be referenced in other parts of the query.

Notice how the selection part says s[]. In case you remove the brackets then the query will return the first entity directly. Hence, when you want to select the whole result set then you simply add the brackets.

Thirdly, since queries are just expressions we can refactor the bit from above and simply return the query expression directly:

namespace MusicLib

repository for Song {
    public void save(Song song) {
        persist song;
        flush;
    }

    public void remove(Song song) {
        remove song;
        flush;
    }

    public Song[] findAll() {
        return SELECT s[] FROM Song s;
    }
}

Finally, in order to see how the query works we simply use it in the controller:

namespace MusicLib

rest controller /song {

    repository<Song> songs = get selfie;

    index {
        return songs.findAll();
    }
}

Last thing to do is to compile using $ glagol compile. Now simply curl localhost:8081/song and you will see a list of song objects!

Querying for a single entity

Next task is to create a typical find(int id) method that will query for just one entity. You guessed it - we need a WHERE clause:

namespace MusicLib

repository for Song {
    public void save(Song song) {
        persist song;
        flush;
    }

    public void remove(Song song) {
        remove song;
        flush;
    }

    public Song[] findAll() {
        return SELECT s[] FROM Song s;
    }

    public Song find(int id) {
        return SELECT s FROM Song s WHERE s.id = <<id>>;
    }
}

As mentioned earlier, if we want to select only one entity we simply write SELECT s. Secondly, lets investigate the WHERE s.id = <<id>> clause. It is obvious that we access a field from the entity by targeting the s alias. The right side of the equation indicates that we embed a Glagol DSL expression. In the example above we simply pass the id parameter that is provided by the method. However, we can use any expression we like there (like WHERE s.id = <<id + 232>>). The << and >> are just delimiters that indicate the start and end of an embedded expression.

In order to show how the finder method works lets modify our sandbox controller in the following way:

namespace MusicLib

rest controller /song {

    repository<Song> songs = get selfie;

    index {
        return songs.find(1);
    }
}

Compile the source and simply curl localhost:8081/song to test as usual.

In the next chapter we are going to learn how to put everything together under a unified Rest API using the controller.