Skip to content

WIP query #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
88dd2d3
Implement query and builder related ffi functions
Buggaboo Sep 19, 2019
bb470cd
at least op overloading is working...
Buggaboo Sep 20, 2019
bd7a32e
minor typo
Buggaboo Sep 20, 2019
a8c849b
another attempt to fix the test
Buggaboo Sep 20, 2019
26e5b33
focus, do aliases later
Buggaboo Sep 20, 2019
39e6a8c
streamline enums
Buggaboo Sep 20, 2019
e820156
Finalized query condition design, also got tests running
Buggaboo Sep 20, 2019
15e9b7a
added operator overloads for int properties
Buggaboo Oct 2, 2019
7698354
added queryAny and queryAll to the box
Buggaboo Oct 2, 2019
23bb90f
added contains / contain to the party
Buggaboo Oct 2, 2019
004bcd2
added close to new queries
Buggaboo Oct 2, 2019
07a5059
updated dummy type for isNull / notNull
Buggaboo Oct 2, 2019
0d2e907
cleaned up tests
Buggaboo Oct 2, 2019
2b3b91b
added tests for double and booleans (both are not supported atm)
Buggaboo Oct 2, 2019
0b19c16
added implementation and tests for `in`, `notIn`, `greater`, `less`
Buggaboo Oct 2, 2019
b14c10c
updated test for `contain` and `contains` for String
Buggaboo Oct 2, 2019
b9c5189
* Modified function signature of find find_ids, maybe unnecessary
Buggaboo Oct 3, 2019
e81d351
Merge branch 'query' into dev-query
Buggaboo Oct 3, 2019
6690bd2
minor cleanup
Buggaboo Oct 3, 2019
231c781
updated readme
Buggaboo Oct 3, 2019
e80fe14
forgot symbol associativity
Buggaboo Oct 8, 2019
42f1152
added bool and double to supported types, still segfaulting on isNull…
Buggaboo Oct 9, 2019
b9ae9d9
try finally resource release
Buggaboo Oct 9, 2019
7481113
Merge branch 'dev' into dev-query
Buggaboo Oct 9, 2019
81895fd
renamed disjunctive normal form (dnf) to anyGroup
Buggaboo Oct 9, 2019
6c5bc56
Implemented other `free` functions for struct pointers
Buggaboo Oct 9, 2019
114d183
changed limit default to zero
Buggaboo Oct 9, 2019
462f74c
renamed condition operators
Buggaboo Oct 9, 2019
06fe677
_queryBuilderPtr -> _cBuilder
Buggaboo Oct 9, 2019
1f868a2
oops, corrected cop in params
Buggaboo Oct 9, 2019
0e2f88e
Added comment about type aliases
Oct 10, 2019
e34f02a
changed the ffi function return types for query_find(_ids) to Uint64,
Buggaboo Oct 10, 2019
55d7f70
kill your darlings: removed queryAll/queryAny that applies a reduce o…
Buggaboo Oct 10, 2019
dbcbe0f
kill your darlings: removed qb_strings_contain for Vector<String> types
Buggaboo Oct 10, 2019
768a7ef
moved out QueryBuilder into its own file within the internal library …
Buggaboo Oct 10, 2019
c9c0a0e
Merge branch 'dev-query' of github.com:Buggaboo/objectbox-dart into d…
Buggaboo Oct 10, 2019
be2aa90
Introduced support for other int-ish types.
Buggaboo Oct 11, 2019
e454a52
Moved out OBXOrderFlag to constants
Buggaboo Oct 11, 2019
ce1e0e3
removed unused generic param
Buggaboo Oct 11, 2019
1e91e20
Merge branch 'dev' into dev-query
Buggaboo Oct 11, 2019
bc05781
wrong number of params
Buggaboo Oct 12, 2019
df00e23
implemented manual type mapping
Buggaboo Oct 12, 2019
cbb44aa
fixed bad merge
Buggaboo Oct 12, 2019
9e8f49a
reimplemented find/findFirst
Buggaboo Oct 13, 2019
9497784
added bounds check to findFirst
Buggaboo Oct 13, 2019
75101fe
fixed minor issues with tests
Buggaboo Oct 13, 2019
b164fb5
added describe(_params)
Buggaboo Oct 13, 2019
d4d6613
oops
Buggaboo Oct 13, 2019
43324e0
added bool to integer conditions
Buggaboo Oct 13, 2019
5b36eda
corrected "dynamic" issue (dart type analysis hickup), and fixed oops…
Buggaboo Oct 13, 2019
ddeef77
corrected skewed tree construction and minimized the number of condit…
Buggaboo Oct 14, 2019
2987190
Merge branch 'dev' into dev-query
Buggaboo Oct 14, 2019
13e8c0e
Merge branch 'dev' into dev-query
Buggaboo Oct 14, 2019
aebd560
IntegerQuery apply simplification
vaind Oct 15, 2019
81c3ac5
create scoped TestEnv for tests
vaind Oct 15, 2019
b1fae6a
define and use OBX_id_array ffi struct
vaind Oct 15, 2019
00f60cc
updated README
Buggaboo Oct 16, 2019
02c656a
Merge pull request #1 from vaind/dev-query
Buggaboo Oct 16, 2019
92259ae
Merge branch 'dev-query' of github.com:Buggaboo/objectbox-dart into d…
Buggaboo Oct 16, 2019
4f0c2cf
replaced fields from Entity_ with named params
Buggaboo Oct 16, 2019
bfc0bc4
removed unused variables
Buggaboo Oct 16, 2019
3fae217
Renamed QueryCondition to ConditionGroup
Buggaboo Oct 16, 2019
57d9325
Renamed
Buggaboo Oct 16, 2019
3cccbf3
bindings no longer looks in lib automagically
Buggaboo Oct 16, 2019
196f964
streamline Query any/all grouping using ConditionGroup
vaind Oct 17, 2019
c6579ad
privatize QueryProperty internals so they don't pollute query code co…
vaind Oct 17, 2019
479e8a6
Revert "bindings no longer looks in lib automagically"
Buggaboo Oct 19, 2019
dabcaa9
Merge pull request #2 from vaind/dev-query
Buggaboo Oct 19, 2019
9cc3318
Merge branch 'dev-query' of github.com:Buggaboo/objectbox-dart into d…
Buggaboo Oct 19, 2019
0538b4d
Merge branch 'dev' into dev-query
Buggaboo Oct 19, 2019
075f5bd
Added workaround for signed dart binary issue from brew
Buggaboo Oct 19, 2019
e693c07
comment clean up
Buggaboo Oct 19, 2019
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
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ To try out the demo code in this repository, follow these steps:
(i.e. the file `test/test.g.dart`) and is necessary each time you add or change a class annotated with `@Entity(...)`.
4. Finally run `pub run test` to run the unit tests.

Mac OS signed dart binary issue
-------------------------------

If dart complains that it cannot find the `libobjectbox.dylib`, after you've installed by following step 1,
then you probably have to unsign the dart binary:

```bash
sudo xcode --remove-signature `which dart`
```

source: [dart issue](https://github.com/dart-lang/sdk/issues/38314#issuecomment-534102841)

Dart integration
----------------
In general, Dart class annotations are used to mark classes as ObjectBox entities and provide meta information.
Expand Down Expand Up @@ -98,6 +110,40 @@ print("refetched note: ${box.get(note.id)}");
store.close();
```

Query and QueryBuilder
----------------------

Basic querying can be done with e.g.:

```dart
// var store ...
// var box ...

box.putMany([Note(), Note(), Note()]);
box.put(Note.construct("Hello world!"));

final queryNullText = box.query(Note_.text.isNull()).build();

assert (queryNullText.count() == 3);

queryNullText.close(); // We have to manually close queries and query builders.
```

More complex queries can be constructed using `and/or` operators.
Also there is basic operator overloading support for `equal`, `greater`, `less`, `and` and `or`,
respectively `==`, `>`, `<`, `&`, `|`.

```dart
// final box ...

box.query(text.equal("meh").or(text.equal("bleh")).or(text.contains("Hello"))).build();

// equivalent to

final overloaded = ((text == "meh") | (text == "bleh")) | text.contains("Hello");
box.query(overloaded as Condition).build(); // the cast is necessary due to the type analyzer
```

Basic technical approach
------------------------
ObjectBox offers a [C API](https://github.com/objectbox/objectbox-c) which can be called by [Dart FFI](https://dart.dev/server/c-interop).
Expand Down
55 changes: 55 additions & 0 deletions bin/objectbox_model_generator/lib/src/code_chunks.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import "package:objectbox/src/modelinfo/index.dart";
import "package:analyzer/dart/element/element.dart";
import "package:objectbox/src/bindings/constants.dart" show OBXPropertyType;
import "package:source_gen/source_gen.dart" show InvalidGenerationSourceError;

class CodeChunks {
static String modelInfoLoader() => """
Expand Down Expand Up @@ -43,4 +46,56 @@ class CodeChunks {
const ${name}_OBXDefs = EntityDefinition<${name}>(_${name}_OBXModelGetter, _${name}_OBXReader, _${name}_OBXBuilder);
""";
}

static String _queryConditionBuilder(ModelEntity readEntity) {
final ret = <String>[];
for (var f in readEntity.properties) {

final name = f.name;

// see OBXPropertyType
String fieldType;
switch(f.type) {
case OBXPropertyType.Bool:
fieldType = "Boolean";
break;
case OBXPropertyType.String:
fieldType = "String";
break;
float:
case OBXPropertyType.Double:
fieldType = "Double";
break;
case OBXPropertyType.Float:
continue float;
integer:
case OBXPropertyType.Int:
fieldType = "Integer";
break;
case OBXPropertyType.Byte:
continue integer;
case OBXPropertyType.Short:
continue integer;
case OBXPropertyType.Char:
continue integer;
case OBXPropertyType.Long:
continue integer;
default:
throw InvalidGenerationSourceError("Unsupported property type (${f.type}): ${readEntity.name}.${name}");
}

ret.add("""
static final ${name} = Query${fieldType}Property(entityId:${readEntity.id.id}, propertyId:${f.id.id}, obxType:${f.type});
""");
}
return ret.join();
}

static String queryConditionClasses(ModelEntity readEntity) {
// TODO add entity.id check to throw an error Box if the wrong entity.property is used
return """
class ${readEntity.name}_ {
${_queryConditionBuilder(readEntity)}
}""";
}
}
76 changes: 39 additions & 37 deletions bin/objectbox_model_generator/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "package:build/src/builder/build_step.dart";
import "package:source_gen/source_gen.dart";

import "package:objectbox/objectbox.dart" as obx;
import "package:objectbox/src/annotations.dart";
import "package:objectbox/src/bindings/constants.dart";

import "code_chunks.dart";
Expand All @@ -25,6 +26,9 @@ class EntityGenerator extends GeneratorForAnnotation<obx.Entity> {
return ModelInfo.fromMap(json.decode(await (File(ALL_MODELS_JSON).readAsString())));
}

final _propertyChecker = const TypeChecker.fromRuntime(Property);
final _idChecker = const TypeChecker.fromRuntime(Id);

@override
Future<String> generateForAnnotatedElement(
Element elementBare, ConstantReader annotation, BuildStep buildStep) async {
Expand Down Expand Up @@ -56,49 +60,44 @@ class EntityGenerator extends GeneratorForAnnotation<obx.Entity> {
int fieldType, flags = 0;
int propUid;

if (f.metadata != null && f.metadata.length == 1) {
var annotElmt = f.metadata[0].element as ConstructorElement;
var annotType = annotElmt.returnType.toString();
var annotVal = f.metadata[0].computeConstantValue();
var fieldTypeAnnot; // for the future, with custom type sizes allowed: annotVal.getField("type");
fieldType = fieldTypeAnnot?.toIntValue();
propUid = annotVal.getField("uid").toIntValue();

// find property flags
if (annotType == "Id") {
if (hasIdProperty) {
throw InvalidGenerationSourceError(
"in target ${elementBare.name}: has more than one properties annotated with @Id");
}
if (fieldType != null) {
throw InvalidGenerationSourceError(
"in target ${elementBare.name}: programming error: @Id property may not specify a type");
}
if (f.type.toString() != "int") {
throw InvalidGenerationSourceError(
"in target ${elementBare.name}: field with @Id property has type '${f.type.toString()}', but it must be 'int'");
}

fieldType = OBXPropertyType.Long;
flags |= OBXPropertyFlag.ID;
hasIdProperty = true;
} else if (annotType == "Property") {
// nothing special
} else {
// skip unknown annotations
print(
"warning: skipping field '${f.name}' in entity '${element.name}', as it has the unknown annotation type '$annotType'");
continue;
if (_idChecker.hasAnnotationOfExact(f)) {
if (hasIdProperty) {
throw InvalidGenerationSourceError(
"in target ${elementBare.name}: has more than one properties annotated with @Id");
}
if (f.type.toString() != "int")
throw InvalidGenerationSourceError(
"in target ${elementBare.name}: field with @Id property has type '${f.type.toString()}', but it must be 'int'");

hasIdProperty = true;

fieldType = OBXPropertyType.Long;
flags |= OBXPropertyFlag.ID;

final _idAnnotation = _idChecker.firstAnnotationOfExact(f);
propUid = _idAnnotation.getField('uid').toIntValue();
}else if (_propertyChecker.hasAnnotationOfExact(f)) {
final _propertyAnnotation = _propertyChecker.firstAnnotationOfExact(f);
propUid = _propertyAnnotation.getField('uid').toIntValue();
fieldType = _propertyAnnotation.getField('type').toIntValue();
flags = _propertyAnnotation.getField('flag').toIntValue() ?? 0;

print ("annotated property found on ${f.name} with parameters: propUid(${propUid}) fieldType(${fieldType}) flags(${flags})");
}else {
print ("property found on ${f.name} with parameters: propUid(${propUid}) fieldType(${fieldType}) flags(${flags})");
}

if (fieldType == null) {
var fieldTypeStr = f.type.toString();
if (fieldTypeStr == "int") {
fieldType = OBXPropertyType.Int;
} else if (fieldTypeStr == "String") {
if (fieldTypeStr == "int") // dart: 8 bytes
fieldType = OBXPropertyType.Long; // ob: 8 bytes
else if (fieldTypeStr == "String")
fieldType = OBXPropertyType.String;
} else {
else if (fieldTypeStr == "bool") // 1 byte
fieldType = OBXPropertyType.Bool; // 1 byte
else if (fieldTypeStr == "double") // dart: 8 bytes
fieldType = OBXPropertyType.Double; // ob: 8 bytes
else {
print(
"warning: skipping field '${f.name}' in entity '${element.name}', as it has the unsupported type '$fieldTypeStr'");
continue;
Expand All @@ -125,6 +124,9 @@ class EntityGenerator extends GeneratorForAnnotation<obx.Entity> {
// main code for instance builders and readers
ret += CodeChunks.instanceBuildersReaders(readEntity);

// for building queries
ret += CodeChunks.queryConditionClasses(readEntity);

return ret;
} catch (e, s) {
print(s);
Expand Down
1 change: 1 addition & 0 deletions lib/objectbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export "src/model.dart";
export "src/store.dart";
export "src/box.dart";
export "src/modelinfo/index.dart";
export "src/query/index.dart";
14 changes: 12 additions & 2 deletions lib/src/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ class Entity {
const Entity({this.uid});
}

/**
* A dart int value can map to different OBXPropertyTypes,
* e.g. Short (Int16), Int (Int32), Long (Int64), all signed values.
* Also a dart double can also map to e.g. Float and Double
*
* Property allows the mapping to be specific. The defaults are
* e.g. Int -> Int64, double -> Float64, bool -> Bool.
*
* Use OBXPropertyType and OBXPropertyFlag values, resp. for type and flag.
*/
class Property {
final int uid;
const Property({this.uid});
final int uid, type, flag;
const Property({this.type = null, this.flag = null, this.uid = null});
}

class Id {
Expand Down
Loading