Let's make a Query builder using Go
To understand the uses of
factory pattern and
singleton pattern in real-life application.
Nowadays we can’t think to write raw
sql queries in our applications. Because writing
sql queries are boring also you have to think about a lot of security staff all the time. ORM (Object-relational mapping) and query builder make it very much easy and convenient.
If you are a
Laravel guy like me you should fall in love with its ORM called
Eloquent . In Golang I have used the GORM ORM several times. Most of the
orm come with a
query builder .
When you are using a framework like Laravel, django for rapid application development, you can any choose any database like mysql, Postgres, mssql, mongodb, sqlite from different flavors. And after completion of your application, you can change the database by typing a word (driver/database name).
Now the question is, do all the different database query languages are same? The plain answer is NO. All the database has different DML for its own.
For example, when we perform a
get method call on some model, depending on the selected driver the query executed in different dialects.
In an imaginary ORM, when we perform this operation
userModel.Get() It will generate different queries depending on the database, like in
mysql it’ll generate a query
SELECT * FROM users and in
mongodb it’ll generate query
Factory pattern is a creational pattern that provides one of the best way to create object. In this case, you don’t have to take panic about how the object created, what is going on underneath. Learn more about it here…
In singleton pattern ensure a class can only one object is created. If you want to create another instance from that particular class it will provide you the previously created object. Read more about it here…
The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation
Note all the three definitions are from Wikipedia
Let's build a fake Query builder to simulate the factory + singleton pattern
querybuilder directory inside
$GOPATH/src/ and create these files.
In this case, we are building a package
db inside the
querybuilder directory where our main package resides.
db.go file inside the
db directory and write the code like below:
db.go file between line 12–17 we created a type interface which contains four method signatures. Between lines 40–50, the
databaseFactory function takes a driver constant as argument, and based on that argument it creates an instance of that database driver, in this case, it just creates the object, but it may need some more argument, some dependencies to create the object. So we hide the process of object creation, which known as factory pattern. All the types (Mysql /Sqlite/MongoDb) are implementing the DB interface so our return type is DB. If we need to add more drivers in the future, we can simply implement the DB interface and add this inside our
switch statement like the previous drivers.
Let's take a look at the line between 30–36, where we used another creation pattern known as the singleton pattern. Here we restricted the users to obtain multiple objects from types (Mysql/Sqlite/MongoDb) so that the connection remains single. We used sync package to get a singleton object and in this case, the object will be thread-safe (In different goroutines the object will remain the same object).
Let's create 3 more files
db to make the driver types.
Now we just finished building the query builder lets use it, to use it we are going to create a main.go file inside the
In line 5 we imported our library
querybuilder/db and line 11 we create an instance of our db library using
db.New() passing MySql as our database.
Our factory and singleton remain alive in the
New() method. When we passed the constant
db.MYSQL a factory created our object based on input, and we used
sync package to create only a single object from that particular type. No matter where we used the db object we always receive the same object over and over. In line 11 we created our first db object and used several methods from the object. In line 18 we set the table name on which the query will be performed and used in line 20, 23 and 26 to perform some queries. But if you look carefully you can see in line 31 we create another object from the query builder and assigned in
db1 variable. Then we performed a Get query in line 37, this time we did not say the table name but it will perform the query on the
users table because we set the table name before on the same object. No matter how many times you asked to create a DB object you will get the same object with the previous connection.
Well, where we used the Builder design pattern? If you look closely you can see all the three concrete implementations used builder design pattern to create complex SQL queries. If we add another method called
Limit` we can implement limit definition for different dialects and if the client invokes the
Limit method then it will add limit functionality.
Though we did not make a working query builder we simulate an idea to create them, basically we focused on how can we use the factory pattern, singleton pattern. If you need the full source code you’ll find it here.
Note: I’ll try to update all of my articles in this series. To get update follow me on twitter or medium. One more thing, if you find any mistake or misleading in these articles please knock me or write a comment. Thank you
If you like my writing please follow me Saddam H.