Posted on February 15, 2019While working on my most recent hobby project in Dart, I ran into the simple problem of having a database but no data. I didn’t really want to manually go filling tables, so I tried creating a library which could do this automatically. Note that this was done using the Aqueduct server framework in Dart but it can easily be ported to a different less feature-rich environment.
All about schemes
So I first had to figure out how I wanted the user to be able to specify how to fill any new objects. Aqueduct maintains instances of a ManagedEntity class which contains all of the structural data of a table. This was perfect for my needs and is also the first argument to the final GenerationScheme class. Its second argument is the field-function mapping to be used for the actual generation of data. This seemed the best solution instead of having the user be limited to, for example, some DSL which would then be converted to random strings
Using, for example, the # symbol for random numbers and C for random characters we could express Dutch postal codes as ####CC
.
Ordering
When generating data for a database, there are several approaches one could take. One possibility, would be to visualize objects as graphs, with the nodes are the individual rows. This would require generating instances of foreign key relationship satisfying graphs which you could then convert into queries. This way each connected component would have to be inserted, in the correct order, separately.One other approach, is where you visualize the entire database scheme as a graph and generate objects for tables one by one. This is also the one implemented, due to its relative simplicity.The order of the tables, which we will generate objects for, is the same as the topological sort of the graph where the nodes are the tables and the edges are the foreign key relationships. The topological sort namely represents the order of dependencies between the nodes, where the nodes containing no dependencies themselves are the first in the sorting. This is useful in knowing which objects can be easily created by themselves, requiring no reference to any other object. For the objects that do contain references, we can just insert references to already created objects considering every object can only be considered for creation if every of its depencies have already been created.This does assume that the database scheme contains no cyclic dependencies or self referencing tables. The approach described here was implemented in the Dart package flood while working on a project where I needed a database containing data to be able to visualize any of the UI elements containing data.