Repositories and entities¶
In the previous chapter we investigated some basics of creating and using entities. However, the examples so far were leaving the entities static - without persistence with a database.
Prepare the database¶
Lets create a database table for our MusicLib::Song
entity:
USE `glagol`;
CREATE TABLE `songs` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NULL,
`genre` VARCHAR(45) NULL,
`author` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
Attention
If you are using the Docker Compose default project structure you can just put the SQL snippet displayed above in the ./database/data.sql
file. The database folder is imported by the MySQL docker container upon build - just rebuild your stack and the table will be created and ready to use. Additionally, you can tweak the database name the app is using by changing the DB_DATABASE
environmental variable from docker-compose.yml
. The database name for any Glagol DSL app defaults to glagol
.
Annotating the entity¶
Next step is to tell Glagol DSL that the Song
entity related to the glagol.songs
database table.
First, add the @table
annotation just before the declaration of the entity:
namespace MusicLib
@table="songs"
entity Song {
int id;
string title;
string genre;
string author;
}
After you compile the sources the environment will know that the Song
entity is bundled with the glagol.songs
table.
Secondly, we need to annotate the primary key field and flag it as auto-incremented. Simply add the @id
and @sequence
annotations just before the int id;
property declaration:
namespace MusicLib
@table="songs"
entity Song {
@id
@sequence
int id;
string title;
string genre;
string author;
}
The @id
annotation will tell Glagol DSL that the targeted field is the primary key field. As for the @sequence
annotation - it will indicate that the field is set for auto-increment.
Compile the sources using the already familiar glagol compile
command.
Now we told Glagol DSL about all the metadata required to bundle the entity with an existing database table.
Songs repository¶
Lets insert some data into the database using the Song entity!
First, we need a Repository object. In general, repositories are a special type of objects that hold the sole responsibility of supporting the lifecycle of entities. Moreover, a Repository is a frequently used enterprise design pattern which has been repeatedly publicised by a number of influential authors such as Martin Fowler and Eric Evans throughout the last two decades. To put it simply, a repository can persist(create, update), remove and retrieve entities from the data storage.
Glagol DSL provides a built-in syntax declaration for repositories:
namespace MusicLib
repository for Song {
}
Save this code as src/MusicLib/SongRepository.g
.
Lets investigate the code snippet. From repository for Song
we can conclude that repositories are, in a way, attached to entities. Additionally, Glagol DSL allows only one repository per entity (one-on-one relationship) to be created - doing otherwise will result in typecheck errors during compilation. Last but not least, the source file name has to follow the mandatory naming convention of <Entity>Repository.g
where <Entity>
is the name of the targeted entity.
So far so good. However, our new repository does not do anything yet. Lets change that by introducing a save
method:
namespace MusicLib
repository for Song {
public void save(Song song) {
persist song;
flush;
}
}
Yep - it is that simple. Repositories expose the persist
and flush
statements. The first one tells Glagol DSL that we want to initiate the persistence of the object that is being passed. Secondly, flush
statement will save all the data into the data storage. Think of it this way - persist
will tell Glagol DSL “Hey, here is an object for you to keep an eye on!”, and flush
says “Bring my changes to the database, please!”.
Note
Entity persisting and flushing is inspired and based on Doctrine 2 ORM’s way of operating with entities.
Finally, lets save our Song entity into the database! Modify the SongController.g
to use the repository:
namespace MusicLib
rest controller /song {
repository<Song> songs = get repository<Song>;
index {
Song balkanSong = new Song("Virus", "Marko Markovic Brass Band");
songs.save(balkanSong);
return balkanSong;
}
}
Lets investigate this piece of code. The very first thing to notice is repository<Song> songs = get repository<Song>;
- in this line we simply define a new property songs
which is of type Song repository type. Moreover, you lets focus on two main keypoints here:
repository<Song>
- this is the syntax used to address repository types;get repository<Song>
- this indicates that the property should be automatically set with the repository instance for a value.
Hint
The line repository<Song> songs = get repository<Song>;
can be simplified to repository<Song> songs = get selfie;
. In general, the selfie keyword will reflect the type declared in the property (in this case repository<Song>
).
Now just compile once again and test using curl localhost:8081/song
! You will see a response just similar to:
{
"id": 1,
"title": "Virus",
"genre": "Balkan",
"author": "Marko Markovic Brass Band"
}
Notice that this time there is a value assigned to the id
field. Generally speaking, this is the first indicator that the data was successfully inserted into the data storage. In fact, lets query MySQL directly to see the stored data:
mysql> SELECT * FROM glagol.songs;
+----+-------+--------+---------------------------+
| id | title | genre | author |
+----+-------+--------+---------------------------+
| 1 | Virus | Balkan | Marko Markovic Brass Band |
+----+-------+--------+---------------------------+
1 row in set (0.00 sec)
Removing entities¶
Very similarly to persisting entities we can also remove such. However, instead of the persist
statement Glagol DSL provides the remove
counterpart:
namespace MusicLib
repository for Song {
public void save(Song song) {
persist song;
flush;
}
public void remove(Song song) {
remove song;
flush;
}
}
Notice, that flushing the requested changes is still necessary if you want to delete the entity records.
In the next chapter we are going to look into how to query entities using Glagol DSL’s embedded query language!