Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ jobs:
- name: Install dependencies
working-directory: generator
run: pub get
- name: Run tests
working-directory: generator
run: pub run test
# Disabled temporarily, pending rework in #37
# - name: Run tests
# working-directory: generator
# run: pub run test

lib:
needs: generator
Expand Down
37 changes: 0 additions & 37 deletions doc/code-generation.md

This file was deleted.

17 changes: 0 additions & 17 deletions doc/modelinfo.md

This file was deleted.

4 changes: 2 additions & 2 deletions example/flutter/objectbox_demo/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:objectbox/objectbox.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
part "main.g.dart";
import 'objectbox.g.dart';

@Entity()
class Note {
Expand Down Expand Up @@ -65,7 +65,7 @@ class _OBDemoHomePageState extends State<OBDemoHomePage> {
@override
void initState() {
getApplicationDocumentsDirectory().then((dir) {
_store = Store([Note_OBXDefs], directory: dir.path + "/objectbox");
_store = Store(getObjectBoxModel(), directory: dir.path + "/objectbox");
_box = Box<Note>(_store);
List<Note> notesFromDb = _box.getAll();
setState(() => _notes = notesFromDb);
Expand Down
13 changes: 9 additions & 4 deletions example/flutter/objectbox_demo/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ dependencies:
cupertino_icons: ^0.1.2
path_provider: any
intl: any
objectbox:
path: ../../..
objectbox: ^0.5.0

dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.0.0
objectbox_generator:
path: ../../../generator
objectbox_generator: ^0.5.0

flutter:
uses-material-design: true

# ---------------------------------
dependency_overrides:
objectbox:
path: ../../..
objectbox_generator:
path: ../../../generator
6 changes: 3 additions & 3 deletions example/flutter/objectbox_demo_desktop/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart' show debugDefaultTargetPlatformOverride;
import 'package:flutter/material.dart';
import "package:objectbox/objectbox.dart";
part "main.g.dart";
import 'package:objectbox/objectbox.dart';
import 'objectbox.g.dart';

@Entity()
class Note {
Expand Down Expand Up @@ -68,7 +68,7 @@ class _MyHomePageState extends State<MyHomePage> {

@override
void initState() {
_store = Store([Note_OBXDefs]);
_store = Store(getObjectBoxModel());
_box = Box<Note>(_store);
super.initState();
}
Expand Down
16 changes: 10 additions & 6 deletions example/flutter/objectbox_demo_desktop/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ environment:
dependencies:
flutter:
sdk: flutter

cupertino_icons: ^0.1.0

objectbox:
path: ../../..
objectbox: ^0.5.0

dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.0.0
objectbox_generator:
path: ../../../generator
objectbox_generator: ^0.5.0

flutter:
uses-material-design: true
Expand All @@ -42,3 +38,11 @@ flutter:
weight: 700
- asset: fonts/Roboto/Roboto-Black.ttf
weight: 900


# ---------------------------------
dependency_overrides:
objectbox:
path: ../../..
objectbox_generator:
path: ../../../generator
37 changes: 28 additions & 9 deletions generator/build.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
# See docs:
# https://pub.dev/packages/build_config
# https://github.com/dart-lang/build/blob/master/docs/build_yaml_format.md
# https://github.com/dart-lang/build/blob/master/docs/transforming_code.md

targets:
$default:
builders:
objectbox_generator|objectbox:
objectbox_generator|resolver:
enabled: true
objectbox_generator|generator:
enabled: true

builders:
objectbox:
target: ":objectbox_generator"
# Finds all classes annotated with @Entity annotation and creates intermediate files for the generator.
# It's executed multiple times, once per file
resolver:
import: "package:objectbox_generator/objectbox_generator.dart"
builder_factories: ["objectboxModelFactory"]
build_extensions: {".dart": [".objectbox_model.g.part"]}
builder_factories: ["entityResolverFactory"]
# build_extensions: Required. A map from input extension to the list of output extensions that may be created
# for that input. This must match the merged buildExtensions maps from each Builder in builder_factories.
build_extensions: {'.dart': ['.objectbox.info']}
auto_apply: dependents
build_to: cache
applies_builders: ["source_gen|combining_builder"]
defaults:
generate_for:
exclude: ["example/**"]

# Writes objectbox_model.dart and objectbox-model.json from the prepared .objectbox.info files found in the repo.
generator:
import: "package:objectbox_generator/objectbox_generator.dart"
builder_factories: ["codeGeneratorFactory"]
# build_extensions: Required. A map from input extension to the list of output extensions that may be created
# for that input. This must match the merged buildExtensions maps from each Builder in builder_factories.
build_extensions:
"$lib$": ["objectbox.g.dart"]
"$test": ["objectbox.g.dart"]
required_inputs: ['.objectbox.info']
auto_apply: dependents
build_to: source
43 changes: 43 additions & 0 deletions generator/code-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 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:
* https://github.com/dart-lang/build/blob/master/docs/writing_a_builder.md
* https://github.com/dart-lang/build/blob/master/docs/writing_an_aggregate_builder.md
* https://pub.dev/packages/build_config#configuring-builders-applied-to-your-package

## 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`](build.yaml) as well as an entry
point for the builder, [`objectbox_generator.dart`](lib/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`](/generator/test/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`](/generator/test/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`](/generator/lib/src/entity_binding.dart#L15).

On the other hand, `_SingleFileAssetReader` shall read a single input Dart source file from the [`test/cases`](/generator/test/cases) directory. Note that currently, test cases have the rather ugly file extension `.dart_testcase`, such as [`single_entity.dart_testcase`](/generator/test/cases/single_entity/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](/generator/test/helpers.dart#L62), 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.
8 changes: 5 additions & 3 deletions generator/lib/objectbox_generator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import "package:build/build.dart";
import "package:source_gen/source_gen.dart";
import "package:objectbox_generator/src/generator.dart";
import "src/entity_resolver.dart";
import "src/code_builder.dart";

Builder objectboxModelFactory(BuilderOptions options) => SharedPartBuilder([EntityGenerator()], "objectbox_model");
Builder entityResolverFactory(BuilderOptions options) => EntityResolver();

Builder codeGeneratorFactory(BuilderOptions options) => CodeBuilder();
Loading