Skip to content

Latest commit

 

History

History
43 lines (28 loc) · 3.67 KB

code-generation.md

File metadata and controls

43 lines (28 loc) · 3.67 KB

ObjectBox Dart – Code generation

To make it possible to read and write ObjectBox entity instances as easily as possible, wrapper code needs to be generated. Such code is only generated for Dart classes which have been annotated to indicate that they represent an ObjectBox entity (i.e. using @Entity). The code is generated by executing pub run build_runner build.

See docs:

Basics

In order to set up code generation, a new package needs to be created exclusively for this task. Here, it it called objectbox_generator. This package needs to contain a build.yaml as well as an entry point for the builder, objectbox_generator.dart which defines code-generator factories for two generators used in build.yaml.

Merging

After all entities have been found in the project, they're compared to an existing model definition in
an objectbox-model.json and merged. Also note that in this step, IDs and UIDs are generated automatically for new instances. UIDs are always random, IDs are assigned in ascending order. UIDs may never be reused, e.g. after a property has been removed, and previously used UIDs of remove instances (entities, properties, indexes, ...) are stored in the JSON file.

Testing

For accomplishing actually automated testing capabilities for objectbox_generator, various wrapper classes are needed, as the build package is only designed to generate output files; yet, during testing, it is necessary to dump generated code to string variables, so they can be compared easily by Dart's test framework.

The entry function for generator testing is the main function of generator_test.dart. It makes sure that any existing file called objectbox-model.json is removed before every test, because we want a fresh start each time.

Helper classes

The build package internally uses designated classes for reading from and writing to files or, to be more general, any kind of assets. In this case, we do not want to involve any kind of files as output and only very specific files as input, so it is necessary to create our own versions of the so-called AssetReader and AssetWriter.

In helpers.dart, _InMemoryAssetWriter is supposed to receive a single output string and store it in memory. Eventually, the string it stores will be the output of EntityGenerator.

On the other hand, _SingleFileAssetReader shall read a single input Dart source file from the test/cases directory. Note that currently, test cases have the rather ugly file extension .dart_testcase, such as single_entity.dart_testcase. This is a workaround, because otherwise, running pub run build_runner build in the repository's root directory would generate .g.dart files from all .dart files in the repository. An option to exclude certain directories from build_runner is yet to be found.

Executing the tests

Eventually, the function runBuilder can be executed, which is part of the build package. It encapsulates everything related to generating the final output. Thus, after it is finished and in case generation was successful, the _InMemoryAssetWriter instance contains the generated code, which can then be compared against the expected code.