Creating clients
Let’s put our new infrastructure to use and wire up the CreateClientView. If you remember, we present a save command that when clicked on, calls onCreateClientSaveExecuted() on CommandController. In order to be able to perform anything useful, CommandController needs visibility of the client instance to be serialized and saved, and an implementation of the IDatabaseController interface to perform the create operation for us.
Inject them into the constructor in command-controller.h, including any necessary headers:
explicit CommandController(QObject* _parent = nullptr, IDatabaseController* databaseController = nullptr, models::Client* newClient = nullptr);
As we’ve seen a few times now, add the member variables to Implementation:
IDatabaseController* databaseController{nullptr}; Client* newClient{nullptr};
Pass them through the CommandController constructor to the Implementation constructor:
Implementation(CommandController* _commandController, IDatabaseController* _databaseController, Client* _newClient) : commandController(_commandController) , databaseController(_databaseController) , newClient(_newClient) { ... }
CommandController::CommandController(QObject* parent, IDatabaseController* databaseController, Client* newClient) : QObject(parent) { implementation.reset(new Implementation(this, databaseController, newClient)); }
Now we can update the onCreateClientSaveExecuted() method to create our new client:
void CommandController::onCreateClientSaveExecuted() { qDebug() << "You executed the Save command!";
implementation->databaseController->createRow(implementation->newClient->key(), implementation->newClient->id(), implementation->newClient->toJson());
qDebug() << "New client saved."; }
Our client instance provides us with all the information we need to be able to save it to the database, and the database controller performs the database interactions.
Our CommandController is now ready, but we’re not actually injecting the database controller or new client in yet, so head over to master-controller.cpp and add an instance of a DatabaseController as we did with CommandController and NavigationController. Add a private member, accessor method, and Q_PROPERTY.
In the Implementation constructor, we need to ensure that we initialize the new client and DatabaseController before we initialize the CommandController, and then pass the pointers through:
Implementation(MasterController* _masterController) : masterController(_masterController) { databaseController = new DatabaseController(masterController); navigationController = new NavigationController(masterController); newClient = new Client(masterController); commandController = new CommandController(masterController, databaseController, newClient); }
Build and run cm-ui, and you should see messages in the Application Output from the newly instantiated DatabaseController, telling you that it has created the database and table:
Database created using Sqlite version: 3.20.1
Database tables created
Take a look at the output folder where your binaries are, and you will see a new cm.sqlite file.
If you navigate to Create Client View, enter a name, and click on the Save button, you will see further output, confirming that the new client has been saved successfully:
You executed the Save command!
New client saved
Let’s take a look inside our database and see what work has been done for us. There are several SQLite browsing applications and web browser plugins available, but the one I tend to use is found at http://sqlitebrowser.org/. Download and install this, or any other client of your choice for your operating system, and open the cm.sqlite file:
You will see that we have a client table, just as we asked for, with two fields: id and json. Browse Data for the client table, and you will see our newly created record with the name property we entered on the UI:
Fantastic, we have created our first client in the database. Note that the DatabaseController initialization methods are idempotent, so you can launch the application again and the existing database will not be affected. Similarly, if you manually delete the cm.sqlite file, then launching the application will create a new version for you (without the old data), which is a simple way of deleting test data.
Let’s make a quick tweak to add the reference property of the client. In CreateClientView, duplicate the StringEditorSingleLine component bound to ui_name, and bind the new control to ui_reference. Build, run, and create a new client:
Our new client happily uses the specified client reference as the unique primary key: