From b0f6c5bc45fefe0c0aef72ba8531d8bb0910fed3 Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:17:09 +0200 Subject: [PATCH 1/7] Format all code using 'dartfmt -l 120' --- .gitignore | 1 + .../lib/builder.dart | 3 +- .../lib/src/generator.dart | 130 ++-- .../objectbox_demo_desktop/lib/main.dart | 156 ++--- lib/src/bindings/bindings.dart | 219 ++++--- lib/src/bindings/constants.dart | 130 ++-- lib/src/bindings/helpers.dart | 10 +- lib/src/bindings/signatures.dart | 18 +- lib/src/box.dart | 619 +++++++++--------- lib/src/common.dart | 47 +- lib/src/model.dart | 105 +-- lib/src/store.dart | 80 ++- test/test.dart | 165 +++-- 13 files changed, 868 insertions(+), 815 deletions(-) diff --git a/.gitignore b/.gitignore index 882b3f6dc..d4ad8c173 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ lib/*.dll lib/*.dylib lib/*.so lib/*.a +.vscode/ diff --git a/bin/objectbox_model_generator/lib/builder.dart b/bin/objectbox_model_generator/lib/builder.dart index 3ccfc8fb0..bd484c3a4 100644 --- a/bin/objectbox_model_generator/lib/builder.dart +++ b/bin/objectbox_model_generator/lib/builder.dart @@ -2,5 +2,4 @@ import "package:build/build.dart"; import "package:source_gen/source_gen.dart"; import "package:objectbox_model_generator/src/generator.dart"; -Builder objectboxModelFactory(BuilderOptions options) => - SharedPartBuilder([EntityGenerator()], "objectbox_model"); +Builder objectboxModelFactory(BuilderOptions options) => SharedPartBuilder([EntityGenerator()], "objectbox_model"); diff --git a/bin/objectbox_model_generator/lib/src/generator.dart b/bin/objectbox_model_generator/lib/src/generator.dart index 7825122d6..3a9d9c612 100644 --- a/bin/objectbox_model_generator/lib/src/generator.dart +++ b/bin/objectbox_model_generator/lib/src/generator.dart @@ -7,15 +7,15 @@ import "package:objectbox/objectbox.dart"; import "package:objectbox/src/bindings/constants.dart"; class EntityGenerator extends GeneratorForAnnotation { - @override - FutureOr generateForAnnotatedElement(Element elementBare, ConstantReader annotation, BuildStep buildStep) { - if(elementBare is! ClassElement) - throw InvalidGenerationSourceError("in target ${elementBare.name}: annotated element isn't a class"); + @override + FutureOr generateForAnnotatedElement(Element elementBare, ConstantReader annotation, BuildStep buildStep) { + if (elementBare is! ClassElement) + throw InvalidGenerationSourceError("in target ${elementBare.name}: annotated element isn't a class"); - // get basic entity info - var entity = Entity(id: annotation.read('id').intValue, uid: annotation.read('uid').intValue); - var element = elementBare as ClassElement; - var ret = """ + // get basic entity info + var entity = Entity(id: annotation.read('id').intValue, uid: annotation.read('uid').intValue); + var element = elementBare as ClassElement; + var ret = """ const _${element.name}_OBXModel = { "entity": { "name": "${element.name}", @@ -25,58 +25,62 @@ class EntityGenerator extends GeneratorForAnnotation { "properties": [ """; - // read all suitable annotated properties - var props = []; - String idPropertyName; - for(var f in element.fields) { - if(f.metadata == null || f.metadata.length != 1) // skip unannotated fields - continue; - var annotElmt = f.metadata[0].element as ConstructorElement; - var annotType = annotElmt.returnType.toString(); - var annotVal = f.metadata[0].computeConstantValue(); - var fieldTypeObj = annotVal.getField("type"); - int fieldType = fieldTypeObj == null ? null : fieldTypeObj.toIntValue(); + // read all suitable annotated properties + var props = []; + String idPropertyName; + for (var f in element.fields) { + if (f.metadata == null || f.metadata.length != 1) // skip unannotated fields + continue; + var annotElmt = f.metadata[0].element as ConstructorElement; + var annotType = annotElmt.returnType.toString(); + var annotVal = f.metadata[0].computeConstantValue(); + var fieldTypeObj = annotVal.getField("type"); + int fieldType = fieldTypeObj == null ? null : fieldTypeObj.toIntValue(); - var prop = { - "name": f.name, - "id": annotVal.getField("id").toIntValue(), - "uid": annotVal.getField("uid").toIntValue(), - "flags": 0, - }; + var prop = { + "name": f.name, + "id": annotVal.getField("id").toIntValue(), + "uid": annotVal.getField("uid").toIntValue(), + "flags": 0, + }; - if(annotType == "Id") { - if(idPropertyName != null) - 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'"); + if (annotType == "Id") { + if (idPropertyName != null) + 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; - prop["flags"] = OBXPropertyFlag.ID; - idPropertyName = f.name; - } else if(annotType == "Property") { - // nothing special here - } else { - // skip unknown annotations - continue; - } + fieldType = OBXPropertyType.Long; + prop["flags"] = OBXPropertyFlag.ID; + idPropertyName = f.name; + } else if (annotType == "Property") { + // nothing special here + } else { + // skip unknown annotations + continue; + } - if(fieldType == null) { - var fieldTypeStr = f.type.toString(); - if(fieldTypeStr == "int") - fieldType = OBXPropertyType.Int; - else if(fieldTypeStr == "String") - fieldType = OBXPropertyType.String; - else { - print("warning: skipping field '${f.name}' in entity '${element.name}', as it has the unsupported type '$fieldTypeStr'"); - continue; - } - } + if (fieldType == null) { + var fieldTypeStr = f.type.toString(); + if (fieldTypeStr == "int") + fieldType = OBXPropertyType.Int; + else if (fieldTypeStr == "String") + fieldType = OBXPropertyType.String; + else { + print( + "warning: skipping field '${f.name}' in entity '${element.name}', as it has the unsupported type '$fieldTypeStr'"); + continue; + } + } - prop["type"] = fieldType; - props.add(prop); - ret += """ + prop["type"] = fieldType; + props.add(prop); + ret += """ { "name": "${prop['name']}", "id": ${prop['id']}, @@ -86,14 +90,14 @@ class EntityGenerator extends GeneratorForAnnotation { "flatbuffers_id": ${(prop['id'] as int) - 1}, }, """; - } + } - // some checks on the entity's integrity - if(idPropertyName == null) - throw InvalidGenerationSourceError("in target ${elementBare.name}: has no properties annotated with @Id"); + // some checks on the entity's integrity + if (idPropertyName == null) + throw InvalidGenerationSourceError("in target ${elementBare.name}: has no properties annotated with @Id"); - // main code for instance builders and readers - ret += """ + // main code for instance builders and readers + ret += """ ], "idPropertyName": "${idPropertyName}", }; @@ -117,6 +121,6 @@ class EntityGenerator extends GeneratorForAnnotation { }; """; - return ret; - } + return ret; + } } diff --git a/examples/flutter/objectbox_demo_desktop/lib/main.dart b/examples/flutter/objectbox_demo_desktop/lib/main.dart index 37690c52d..2cc934595 100644 --- a/examples/flutter/objectbox_demo_desktop/lib/main.dart +++ b/examples/flutter/objectbox_demo_desktop/lib/main.dart @@ -6,102 +6,104 @@ part "main.g.dart"; @Entity(id: 1, uid: 1) class Note { - @Id(id: 1, uid: 1001) - int id; + @Id(id: 1, uid: 1001) + int id; - @Property(id: 2, uid: 1002) - String text; + @Property(id: 2, uid: 1002) + String text; - Note(); - Note.construct(this.text); - toString() => "Note{id: $id, text: $text}"; + Note(); + Note.construct(this.text); + toString() => "Note{id: $id, text: $text}"; } void main() { - // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override - debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; + // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override + debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; - runApp(MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - title: "ObjectBox Demo", - theme: ThemeData(primarySwatch: Colors.blue, fontFamily: "Roboto"), - home: MyHomePage(title: "ObjectBox Demo"), - ); - } + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "ObjectBox Demo", + theme: ThemeData(primarySwatch: Colors.blue, fontFamily: "Roboto"), + home: MyHomePage(title: "ObjectBox Demo"), + ); + } } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key key, this.title}) : super(key: key); - final String title; + final String title; - @override - _MyHomePageState createState() => _MyHomePageState(); + @override + _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { - String _status = ""; - Store _store; - Box _box; - int _lastPutId; + String _status = ""; + Store _store; + Box _box; + int _lastPutId; - void _testGet() { - final Note fetchedNote = _lastPutId == null ? null : _box.get(_lastPutId); - setState(() { - if(_lastPutId == null) { - _status += "cannot get, as nothing was put in this session yet\n"; - return; - } - _status += "fetched note: $fetchedNote\n"; - }); - } + void _testGet() { + final Note fetchedNote = _lastPutId == null ? null : _box.get(_lastPutId); + setState(() { + if (_lastPutId == null) { + _status += "cannot get, as nothing was put in this session yet\n"; + return; + } + _status += "fetched note: $fetchedNote\n"; + }); + } - void _testPut() { - _lastPutId = _box.put(Note.construct("Hello")); - setState(() { - _status += "put new note with id $_lastPutId\n"; - }); - } + void _testPut() { + _lastPutId = _box.put(Note.construct("Hello")); + setState(() { + _status += "put new note with id $_lastPutId\n"; + }); + } - @override - void initState() { - _store = Store([[Note, Note_OBXDefs]]); - _box = Box(_store); - super.initState(); - } + @override + void initState() { + _store = Store([ + [Note, Note_OBXDefs] + ]); + _box = Box(_store); + super.initState(); + } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: Text(widget.title)), - body: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - FlatButton( - onPressed: _testGet, - child: Text("get"), - color: Colors.blue, - textColor: Colors.white, - ), - FlatButton( - onPressed: _testPut, - child: Text("put"), - color: Colors.blue, - textColor: Colors.white, - ), - ], - ), - Text("$_status"), - ], - ), - ); - } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(widget.title)), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + FlatButton( + onPressed: _testGet, + child: Text("get"), + color: Colors.blue, + textColor: Colors.white, + ), + FlatButton( + onPressed: _testPut, + child: Text("put"), + color: Colors.blue, + textColor: Colors.white, + ), + ], + ), + Text("$_status"), + ], + ), + ); + } } diff --git a/lib/src/bindings/bindings.dart b/lib/src/bindings/bindings.dart index 0120657dc..84940f6a7 100644 --- a/lib/src/bindings/bindings.dart +++ b/lib/src/bindings/bindings.dart @@ -5,117 +5,138 @@ import "signatures.dart"; // bundles all C functions to be exposed to Dart class _ObjectBoxBindings { - DynamicLibrary objectbox; + DynamicLibrary objectbox; + + // common functions + void Function(Pointer major, Pointer minor, Pointer patch) obx_version; + Pointer Function() obx_version_string; + void Function(Pointer array) obx_bytes_array_free; + + // error info + int Function() obx_last_error_code; + Pointer Function() obx_last_error_message; + int Function() obx_last_error_secondary; + void Function() obx_last_error_clear; + + // schema model creation + Pointer Function() obx_model; + int Function(Pointer model) obx_model_free; + int Function(Pointer model, Pointer name, int entity_id, int entity_uid) obx_model_entity; + int Function(Pointer model, Pointer name, int type, int property_id, int property_uid) + obx_model_property; + int Function(Pointer model, int flags) obx_model_property_flags; + int Function(Pointer model, int property_id, int property_uid) obx_model_entity_last_property_id; + int Function(Pointer model, int entity_id, int entity_uid) obx_model_last_entity_id; + + // object store management + Pointer Function() obx_opt; + int Function(Pointer opt, Pointer dir) obx_opt_directory; + void Function(Pointer opt, int size_in_kb) obx_opt_max_db_size_in_kb; + void Function(Pointer opt, int file_mode) obx_opt_file_mode; + void Function(Pointer opt, int max_readers) obx_opt_max_readers; + int Function(Pointer opt, Pointer model) obx_opt_model; + void Function(Pointer opt) obx_opt_free; + Pointer Function(Pointer opt) obx_store_open; + int Function(Pointer store) obx_store_close; + + // transactions + Pointer Function(Pointer store) obx_txn_write; + Pointer Function(Pointer store) obx_txn_read; + int Function(Pointer txn) obx_txn_close; + int Function(Pointer txn) obx_txn_abort; + int Function(Pointer txn) obx_txn_success; + + // box management + Pointer Function(Pointer store, int entity_id) obx_box; + int Function(Pointer box, int id, Pointer out_contains) obx_box_contains; + int Function(Pointer box, Pointer ids, Pointer out_contains) obx_box_contains_many; + int Function(Pointer box, int id, Pointer> data, Pointer size) obx_box_get; + Pointer Function(Pointer box, Pointer ids) obx_box_get_many; + Pointer Function(Pointer box) obx_box_get_all; + int Function(Pointer box, int id_or_zero) obx_box_id_for_put; + int Function(Pointer box, int count, Pointer out_first_id) obx_box_ids_for_put; + int Function(Pointer box, int id, Pointer data, int size, int mode) obx_box_put; + int Function(Pointer box, Pointer objects, Pointer ids, int mode) obx_box_put_many; + int Function(Pointer box, int id) obx_box_remove; + + _ObjectBoxBindings() { + var libName = "objectbox"; + if (Platform.isWindows) + libName += ".dll"; + else if (Platform.isMacOS) + libName = "lib" + libName + ".dylib"; + else if (Platform.isLinux || Platform.isAndroid) + libName = "lib" + libName + ".so"; + else + throw Exception("unsupported platform detected"); + objectbox = DynamicLibrary.open(libName); // common functions - void Function(Pointer major, Pointer minor, Pointer patch) obx_version; - Pointer Function() obx_version_string; - void Function(Pointer array) obx_bytes_array_free; + obx_version = objectbox.lookup>("obx_version").asFunction(); + obx_version_string = + objectbox.lookup>("obx_version_string").asFunction(); + obx_bytes_array_free = + objectbox.lookup>("obx_bytes_array_free").asFunction(); // error info - int Function() obx_last_error_code; - Pointer Function() obx_last_error_message; - int Function() obx_last_error_secondary; - void Function() obx_last_error_clear; + obx_last_error_code = + objectbox.lookup>("obx_last_error_code").asFunction(); + obx_last_error_message = + objectbox.lookup>("obx_last_error_message").asFunction(); + obx_last_error_secondary = + objectbox.lookup>("obx_last_error_secondary").asFunction(); + obx_last_error_clear = + objectbox.lookup>("obx_last_error_clear").asFunction(); // schema model creation - Pointer Function() obx_model; - int Function(Pointer model) obx_model_free; - int Function(Pointer model, Pointer name, int entity_id, int entity_uid) obx_model_entity; - int Function(Pointer model, Pointer name, int type, int property_id, int property_uid) obx_model_property; - int Function(Pointer model, int flags) obx_model_property_flags; - int Function(Pointer model, int property_id, int property_uid) obx_model_entity_last_property_id; - int Function(Pointer model, int entity_id, int entity_uid) obx_model_last_entity_id; + obx_model = objectbox.lookup>("obx_model").asFunction(); + obx_model_free = objectbox.lookup>("obx_model_free").asFunction(); + obx_model_entity = objectbox.lookup>("obx_model_entity").asFunction(); + obx_model_property = + objectbox.lookup>("obx_model_property").asFunction(); + obx_model_property_flags = + objectbox.lookup>("obx_model_property_flags").asFunction(); + obx_model_entity_last_property_id = objectbox + .lookup>("obx_model_entity_last_property_id") + .asFunction(); + obx_model_last_entity_id = + objectbox.lookup>("obx_model_last_entity_id").asFunction(); // object store management - Pointer Function() obx_opt; - int Function(Pointer opt, Pointer dir) obx_opt_directory; - void Function(Pointer opt, int size_in_kb) obx_opt_max_db_size_in_kb; - void Function(Pointer opt, int file_mode) obx_opt_file_mode; - void Function(Pointer opt, int max_readers) obx_opt_max_readers; - int Function(Pointer opt, Pointer model) obx_opt_model; - void Function(Pointer opt) obx_opt_free; - Pointer Function(Pointer opt) obx_store_open; - int Function(Pointer store) obx_store_close; + obx_opt = objectbox.lookup>("obx_opt").asFunction(); + obx_opt_directory = objectbox.lookup>("obx_opt_directory").asFunction(); + obx_opt_max_db_size_in_kb = + objectbox.lookup>("obx_opt_max_db_size_in_kb").asFunction(); + obx_opt_file_mode = objectbox.lookup>("obx_opt_file_mode").asFunction(); + obx_opt_max_readers = + objectbox.lookup>("obx_opt_max_readers").asFunction(); + obx_opt_model = objectbox.lookup>("obx_opt_model").asFunction(); + obx_store_open = objectbox.lookup>("obx_store_open").asFunction(); + obx_store_close = objectbox.lookup>("obx_store_close").asFunction(); // transactions - Pointer Function(Pointer store) obx_txn_write; - Pointer Function(Pointer store) obx_txn_read; - int Function(Pointer txn) obx_txn_close; - int Function(Pointer txn) obx_txn_abort; - int Function(Pointer txn) obx_txn_success; + obx_txn_write = objectbox.lookup>("obx_txn_write").asFunction(); + obx_txn_read = objectbox.lookup>("obx_txn_read").asFunction(); + obx_txn_close = objectbox.lookup>("obx_txn_close").asFunction(); + obx_txn_abort = objectbox.lookup>("obx_txn_abort").asFunction(); + obx_txn_success = objectbox.lookup>("obx_txn_success").asFunction(); // box management - Pointer Function(Pointer store, int entity_id) obx_box; - int Function(Pointer box, int id, Pointer out_contains) obx_box_contains; - int Function(Pointer box, Pointer ids, Pointer out_contains) obx_box_contains_many; - int Function(Pointer box, int id, Pointer> data, Pointer size) obx_box_get; - Pointer Function(Pointer box, Pointer ids) obx_box_get_many; - Pointer Function(Pointer box) obx_box_get_all; - int Function(Pointer box, int id_or_zero) obx_box_id_for_put; - int Function(Pointer box, int count, Pointer out_first_id) obx_box_ids_for_put; - int Function(Pointer box, int id, Pointer data, int size, int mode) obx_box_put; - int Function(Pointer box, Pointer objects, Pointer ids, int mode) obx_box_put_many; - int Function(Pointer box, int id) obx_box_remove; - - _ObjectBoxBindings() { - var libName = "objectbox"; - if(Platform.isWindows) libName += ".dll"; - else if(Platform.isMacOS) libName = "lib" + libName + ".dylib"; - else if(Platform.isLinux || Platform.isAndroid) libName = "lib" + libName + ".so"; - else throw Exception("unsupported platform detected"); - objectbox = DynamicLibrary.open(libName); - - // common functions - obx_version = objectbox.lookup>("obx_version").asFunction(); - obx_version_string = objectbox.lookup>("obx_version_string").asFunction(); - obx_bytes_array_free = objectbox.lookup>("obx_bytes_array_free").asFunction(); - - // error info - obx_last_error_code = objectbox.lookup>("obx_last_error_code").asFunction(); - obx_last_error_message = objectbox.lookup>("obx_last_error_message").asFunction(); - obx_last_error_secondary = objectbox.lookup>("obx_last_error_secondary").asFunction(); - obx_last_error_clear = objectbox.lookup>("obx_last_error_clear").asFunction(); - - // schema model creation - obx_model = objectbox.lookup>("obx_model").asFunction(); - obx_model_free = objectbox.lookup>("obx_model_free").asFunction(); - obx_model_entity = objectbox.lookup>("obx_model_entity").asFunction(); - obx_model_property = objectbox.lookup>("obx_model_property").asFunction(); - obx_model_property_flags = objectbox.lookup>("obx_model_property_flags").asFunction(); - obx_model_entity_last_property_id = objectbox.lookup>("obx_model_entity_last_property_id").asFunction(); - obx_model_last_entity_id = objectbox.lookup>("obx_model_last_entity_id").asFunction(); - - // object store management - obx_opt = objectbox.lookup>("obx_opt").asFunction(); - obx_opt_directory = objectbox.lookup>("obx_opt_directory").asFunction(); - obx_opt_max_db_size_in_kb = objectbox.lookup>("obx_opt_max_db_size_in_kb").asFunction(); - obx_opt_file_mode = objectbox.lookup>("obx_opt_file_mode").asFunction(); - obx_opt_max_readers = objectbox.lookup>("obx_opt_max_readers").asFunction(); - obx_opt_model = objectbox.lookup>("obx_opt_model").asFunction(); - obx_store_open = objectbox.lookup>("obx_store_open").asFunction(); - obx_store_close = objectbox.lookup>("obx_store_close").asFunction(); - - // transactions - obx_txn_write = objectbox.lookup>("obx_txn_write").asFunction(); - obx_txn_read = objectbox.lookup>("obx_txn_read").asFunction(); - obx_txn_close = objectbox.lookup>("obx_txn_close").asFunction(); - obx_txn_abort = objectbox.lookup>("obx_txn_abort").asFunction(); - obx_txn_success = objectbox.lookup>("obx_txn_success").asFunction(); - - // box management - obx_box = objectbox.lookup>("obx_box").asFunction(); - obx_box_contains = objectbox.lookup>("obx_box_contains").asFunction(); - obx_box_contains_many = objectbox.lookup>("obx_box_contains_many").asFunction(); - obx_box_get = objectbox.lookup>("obx_box_get").asFunction(); - obx_box_get_many = objectbox.lookup>("obx_box_get_many").asFunction(); - obx_box_get_all = objectbox.lookup>("obx_box_get_all").asFunction(); - obx_box_id_for_put = objectbox.lookup>("obx_box_id_for_put").asFunction(); - obx_box_ids_for_put = objectbox.lookup>("obx_box_ids_for_put").asFunction(); - obx_box_put = objectbox.lookup>("obx_box_put").asFunction(); - obx_box_put_many = objectbox.lookup>("obx_box_put_many").asFunction(); - obx_box_remove = objectbox.lookup>("obx_box_remove").asFunction(); - } + obx_box = objectbox.lookup>("obx_box").asFunction(); + obx_box_contains = objectbox.lookup>("obx_box_contains").asFunction(); + obx_box_contains_many = + objectbox.lookup>("obx_box_contains_many").asFunction(); + obx_box_get = objectbox.lookup>("obx_box_get").asFunction(); + obx_box_get_many = objectbox.lookup>("obx_box_get_many").asFunction(); + obx_box_get_all = objectbox.lookup>("obx_box_get_all").asFunction(); + obx_box_id_for_put = + objectbox.lookup>("obx_box_id_for_put").asFunction(); + obx_box_ids_for_put = + objectbox.lookup>("obx_box_ids_for_put").asFunction(); + obx_box_put = objectbox.lookup>("obx_box_put").asFunction(); + obx_box_put_many = objectbox.lookup>("obx_box_put_many").asFunction(); + obx_box_remove = objectbox.lookup>("obx_box_remove").asFunction(); + } } _ObjectBoxBindings _cachedBindings; diff --git a/lib/src/bindings/constants.dart b/lib/src/bindings/constants.dart index cfb0e8b75..3698d76dc 100644 --- a/lib/src/bindings/constants.dart +++ b/lib/src/bindings/constants.dart @@ -1,85 +1,85 @@ class OBXPropertyType { - static const int Bool = 1; - static const int Byte = 2; - static const int Short = 3; - static const int Char = 4; - static const int Int = 5; - static const int Long = 6; - static const int Float = 7; - static const int Double = 8; - static const int String = 9; - static const int Date = 10; - static const int Relation = 11; - static const int ByteVector = 23; - static const int StringVector = 30; + static const int Bool = 1; + static const int Byte = 2; + static const int Short = 3; + static const int Char = 4; + static const int Int = 5; + static const int Long = 6; + static const int Float = 7; + static const int Double = 8; + static const int String = 9; + static const int Date = 10; + static const int Relation = 11; + static const int ByteVector = 23; + static const int StringVector = 30; } // see objectbox.h for more info class OBXPropertyFlag { - static const int ID = 1; - static const int NON_PRIMITIVE_TYPE = 2; - static const int NOT_NULL = 4; - static const int INDEXED = 8; - static const int RESERVED = 16; - static const int UNIQUE = 32; - static const int ID_MONOTONIC_SEQUENCE = 64; - static const int ID_SELF_ASSIGNABLE = 128; - static const int INDEX_PARTIAL_SKIP_NULL = 256; - static const int INDEX_PARTIAL_SKIP_ZERO = 512; - static const int VIRTUAL = 1024; - static const int INDEX_HASH = 2048; - static const int INDEX_HASH64 = 4096; - static const int UNSIGNED = 8192; + static const int ID = 1; + static const int NON_PRIMITIVE_TYPE = 2; + static const int NOT_NULL = 4; + static const int INDEXED = 8; + static const int RESERVED = 16; + static const int UNIQUE = 32; + static const int ID_MONOTONIC_SEQUENCE = 64; + static const int ID_SELF_ASSIGNABLE = 128; + static const int INDEX_PARTIAL_SKIP_NULL = 256; + static const int INDEX_PARTIAL_SKIP_ZERO = 512; + static const int VIRTUAL = 1024; + static const int INDEX_HASH = 2048; + static const int INDEX_HASH64 = 4096; + static const int UNSIGNED = 8192; } // see objectbox.h for more info class OBXPutMode { - static const int PUT = 1; - static const int INSERT = 2; - static const int UPDATE = 3; + static const int PUT = 1; + static const int INSERT = 2; + static const int UPDATE = 3; } class OBXError { - /// Successful result - static const int OBX_SUCCESS = 0; + /// Successful result + static const int OBX_SUCCESS = 0; - /// Returned by e.g. get operations if nothing was found for a specific ID. - /// This is NOT an error condition, and thus no last error info is set. - static const int OBX_NOT_FOUND = 404; + /// Returned by e.g. get operations if nothing was found for a specific ID. + /// This is NOT an error condition, and thus no last error info is set. + static const int OBX_NOT_FOUND = 404; - // General errors - static const int OBX_ERROR_ILLEGAL_STATE = 10001; - static const int OBX_ERROR_ILLEGAL_ARGUMENT = 10002; - static const int OBX_ERROR_ALLOCATION = 10003; - static const int OBX_ERROR_NO_ERROR_INFO = 10097; - static const int OBX_ERROR_GENERAL = 10098; - static const int OBX_ERROR_UNKNOWN = 10099; + // General errors + static const int OBX_ERROR_ILLEGAL_STATE = 10001; + static const int OBX_ERROR_ILLEGAL_ARGUMENT = 10002; + static const int OBX_ERROR_ALLOCATION = 10003; + static const int OBX_ERROR_NO_ERROR_INFO = 10097; + static const int OBX_ERROR_GENERAL = 10098; + static const int OBX_ERROR_UNKNOWN = 10099; - // Storage errors (often have a secondary error code) - static const int OBX_ERROR_DB_FULL = 10101; - static const int OBX_ERROR_MAX_READERS_EXCEEDED = 10102; - static const int OBX_ERROR_STORE_MUST_SHUTDOWN = 10103; - static const int OBX_ERROR_STORAGE_GENERAL = 10199; + // Storage errors (often have a secondary error code) + static const int OBX_ERROR_DB_FULL = 10101; + static const int OBX_ERROR_MAX_READERS_EXCEEDED = 10102; + static const int OBX_ERROR_STORE_MUST_SHUTDOWN = 10103; + static const int OBX_ERROR_STORAGE_GENERAL = 10199; - // Data errors - static const int OBX_ERROR_UNIQUE_VIOLATED = 10201; - static const int OBX_ERROR_NON_UNIQUE_RESULT = 10202; - static const int OBX_ERROR_PROPERTY_TYPE_MISMATCH = 10203; - static const int OBX_ERROR_CONSTRAINT_VIOLATED = 10299; + // Data errors + static const int OBX_ERROR_UNIQUE_VIOLATED = 10201; + static const int OBX_ERROR_NON_UNIQUE_RESULT = 10202; + static const int OBX_ERROR_PROPERTY_TYPE_MISMATCH = 10203; + static const int OBX_ERROR_CONSTRAINT_VIOLATED = 10299; - // STD errors - static const int OBX_ERROR_STD_ILLEGAL_ARGUMENT = 10301; - static const int OBX_ERROR_STD_OUT_OF_RANGE = 10302; - static const int OBX_ERROR_STD_LENGTH = 10303; - static const int OBX_ERROR_STD_BAD_ALLOC = 10304; - static const int OBX_ERROR_STD_RANGE = 10305; - static const int OBX_ERROR_STD_OVERFLOW = 10306; - static const int OBX_ERROR_STD_OTHER = 10399; + // STD errors + static const int OBX_ERROR_STD_ILLEGAL_ARGUMENT = 10301; + static const int OBX_ERROR_STD_OUT_OF_RANGE = 10302; + static const int OBX_ERROR_STD_LENGTH = 10303; + static const int OBX_ERROR_STD_BAD_ALLOC = 10304; + static const int OBX_ERROR_STD_RANGE = 10305; + static const int OBX_ERROR_STD_OVERFLOW = 10306; + static const int OBX_ERROR_STD_OTHER = 10399; - // Inconsistencies detected - static const int OBX_ERROR_SCHEMA = 10501; - static const int OBX_ERROR_FILE_CORRUPT = 10502; + // Inconsistencies detected + static const int OBX_ERROR_SCHEMA = 10501; + static const int OBX_ERROR_FILE_CORRUPT = 10502; - /// A requested schema object (e.g. entity or property) was not found in the schema - static const int OBX_ERROR_SCHEMA_OBJECT_NOT_FOUND = 10503; + /// A requested schema object (e.g. entity or property) was not found in the schema + static const int OBX_ERROR_SCHEMA_OBJECT_NOT_FOUND = 10503; } diff --git a/lib/src/bindings/helpers.dart b/lib/src/bindings/helpers.dart index dc8177f13..11f83cd3d 100644 --- a/lib/src/bindings/helpers.dart +++ b/lib/src/bindings/helpers.dart @@ -1,15 +1,13 @@ import "dart:ffi"; -import "dart:typed_data" show Uint8List; import "constants.dart"; import "../common.dart"; checkObx(errorCode) { - if(errorCode != OBXError.OBX_SUCCESS) - throw ObjectBoxException(Common.lastErrorString(errorCode)); + if (errorCode != OBXError.OBX_SUCCESS) throw ObjectBoxException(Common.lastErrorString(errorCode)); } checkObxPtr(Pointer ptr, String msg, [bool hasLastError = false]) { - if(ptr == null || ptr.address == 0) - throw ObjectBoxException("$msg: ${hasLastError ? Common.lastErrorString() : ""}"); - return ptr; + if (ptr == null || ptr.address == 0) + throw ObjectBoxException("$msg: ${hasLastError ? Common.lastErrorString() : ""}"); + return ptr; } diff --git a/lib/src/bindings/signatures.dart b/lib/src/bindings/signatures.dart index e23206636..fba6f3ece 100644 --- a/lib/src/bindings/signatures.dart +++ b/lib/src/bindings/signatures.dart @@ -14,10 +14,13 @@ typedef obx_last_error_clear_native_t = Void Function(); // schema model creation typedef obx_model_native_t = Pointer Function(); typedef obx_model_free_native_t = Int32 Function(Pointer); -typedef obx_model_entity_native_t = Int32 Function(Pointer model, Pointer name, Uint32 entity_id, Uint64 entity_uid); -typedef obx_model_property_native_t = Int32 Function(Pointer model, Pointer name, Uint32 type, Uint64 property_id, Uint64 property_uid); +typedef obx_model_entity_native_t = Int32 Function( + Pointer model, Pointer name, Uint32 entity_id, Uint64 entity_uid); +typedef obx_model_property_native_t = Int32 Function( + Pointer model, Pointer name, Uint32 type, Uint64 property_id, Uint64 property_uid); typedef obx_model_property_flags_native_t = Int32 Function(Pointer model, Uint32 flags); -typedef obx_model_entity_last_property_id_native_t = Int32 Function(Pointer model, Uint32 property_id, Uint64 property_uid); +typedef obx_model_entity_last_property_id_native_t = Int32 Function( + Pointer model, Uint32 property_id, Uint64 property_uid); typedef obx_model_last_entity_id_native_t = Int32 Function(Pointer model, Uint32 entity_id, Uint64 entity_uid); // object store management @@ -40,12 +43,15 @@ typedef obx_txn_success_native_t = Int32 Function(Pointer txn); // box management typedef obx_box_native_t = Pointer Function(Pointer store, Uint32 entity_id); typedef obx_box_contains_native_t = Int32 Function(Pointer box, Uint64 id, Pointer out_contains); -typedef obx_box_contains_many_native_t = Int32 Function(Pointer box, Pointer ids, Pointer out_contains); -typedef obx_box_get_native_t = Int32 Function(Pointer box, Uint64 id, Pointer> data, Pointer size); +typedef obx_box_contains_many_native_t = Int32 Function( + Pointer box, Pointer ids, Pointer out_contains); +typedef obx_box_get_native_t = Int32 Function( + Pointer box, Uint64 id, Pointer> data, Pointer size); typedef obx_box_get_many_native_t = Pointer Function(Pointer box, Pointer ids); typedef obx_box_get_all_native_t = Pointer Function(Pointer box); typedef obx_box_id_for_put_native_t = Uint64 Function(Pointer box, Uint64 id_or_zero); typedef obx_box_ids_for_put_native_t = Int32 Function(Pointer box, Uint64 count, Pointer out_first_id); typedef obx_box_put_native_t = Int32 Function(Pointer box, Uint64 id, Pointer data, Int32 size, Int32 mode); -typedef obx_box_put_many_native_t = Int32 Function(Pointer box, Pointer objects, Pointer ids, Int32 mode); +typedef obx_box_put_many_native_t = Int32 Function( + Pointer box, Pointer objects, Pointer ids, Int32 mode); typedef obx_box_remove_native_t = Int32 Function(Pointer box, Uint64 id); diff --git a/lib/src/box.dart b/lib/src/box.dart index c09070cfb..bc2e41a7d 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -8,343 +8,368 @@ import "bindings/constants.dart"; import "bindings/helpers.dart"; enum PutMode { - Put, - Insert, - Update, + Put, + Insert, + Update, } class _OBXFBEntity { - _OBXFBEntity._(this._bc, this._bcOffset); - static const fb.Reader<_OBXFBEntity> reader = const _OBXFBEntityReader(); - factory _OBXFBEntity(Uint8List bytes) { - fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes); - return reader.read(rootRef, 0); - } + _OBXFBEntity._(this._bc, this._bcOffset); + static const fb.Reader<_OBXFBEntity> reader = const _OBXFBEntityReader(); + factory _OBXFBEntity(Uint8List bytes) { + fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } - final fb.BufferContext _bc; - final int _bcOffset; + final fb.BufferContext _bc; + final int _bcOffset; - getProp(propReader, int field) => propReader.vTableGet(_bc, _bcOffset, field); + getProp(propReader, int field) => propReader.vTableGet(_bc, _bcOffset, field); } class _OBXFBEntityReader extends fb.TableReader<_OBXFBEntity> { - const _OBXFBEntityReader(); + const _OBXFBEntityReader(); - @override - _OBXFBEntity createObject(fb.BufferContext bc, int offset) => - new _OBXFBEntity._(bc, offset); + @override + _OBXFBEntity createObject(fb.BufferContext bc, int offset) => new _OBXFBEntity._(bc, offset); } -class _IDArray { // wrapper for "struct OBX_id_array" - Pointer _idsPtr, _structPtr; +class _IDArray { + // wrapper for "struct OBX_id_array" + Pointer _idsPtr, _structPtr; - _IDArray(List ids) { - _idsPtr = Pointer.allocate(count: ids.length); - for(int i = 0; i < ids.length; ++i) - _idsPtr.elementAt(i).store(ids[i]); - _structPtr = Pointer.allocate(count: 2); - _structPtr.store(_idsPtr.address); - _structPtr.elementAt(1).store(ids.length); - } + _IDArray(List ids) { + _idsPtr = Pointer.allocate(count: ids.length); + for (int i = 0; i < ids.length; ++i) _idsPtr.elementAt(i).store(ids[i]); + _structPtr = Pointer.allocate(count: 2); + _structPtr.store(_idsPtr.address); + _structPtr.elementAt(1).store(ids.length); + } - get ptr => _structPtr; + get ptr => _structPtr; - free() { - _idsPtr.free(); - _structPtr.free(); - } + free() { + _idsPtr.free(); + _structPtr.free(); + } } class _ByteBuffer { - Pointer _ptr; - int _size; - - _ByteBuffer(this._ptr, this._size); - - _ByteBuffer.allocate(Uint8List dartData, [bool align = true]) { - _ptr = Pointer.allocate(count: align ? ((dartData.length + 3.0) ~/ 4.0) * 4 : dartData.length); - for(int i = 0; i < dartData.length; ++i) - _ptr.elementAt(i).store(dartData[i]); - _size = dartData.length; - } - - _ByteBuffer.fromOBXBytes(Pointer obxPtr) { // extract fields from "struct OBX_bytes" - _ptr = Pointer.fromAddress(obxPtr.load()); - _size = obxPtr.elementAt(1).load(); - } - - get ptr => _ptr; - get voidPtr => Pointer.fromAddress(_ptr.address); - get address => _ptr.address; - get size => _size; - - Uint8List get data { - var buffer = new Uint8List(size); - for(int i = 0; i < size; ++i) - buffer[i] = _ptr.elementAt(i).load(); - return buffer; - } - - free() => _ptr.free(); + Pointer _ptr; + int _size; + + _ByteBuffer(this._ptr, this._size); + + _ByteBuffer.allocate(Uint8List dartData, [bool align = true]) { + _ptr = Pointer.allocate(count: align ? ((dartData.length + 3.0) ~/ 4.0) * 4 : dartData.length); + for (int i = 0; i < dartData.length; ++i) _ptr.elementAt(i).store(dartData[i]); + _size = dartData.length; + } + + _ByteBuffer.fromOBXBytes(Pointer obxPtr) { + // extract fields from "struct OBX_bytes" + _ptr = Pointer.fromAddress(obxPtr.load()); + _size = obxPtr.elementAt(1).load(); + } + + get ptr => _ptr; + get voidPtr => Pointer.fromAddress(_ptr.address); + get address => _ptr.address; + get size => _size; + + Uint8List get data { + var buffer = new Uint8List(size); + for (int i = 0; i < size; ++i) buffer[i] = _ptr.elementAt(i).load(); + return buffer; + } + + free() => _ptr.free(); } class _SerializedByteBufferArray { - Pointer _outerPtr, _innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes + Pointer _outerPtr, + _innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes - _SerializedByteBufferArray(this._outerPtr, this._innerPtr); - get ptr => _outerPtr; + _SerializedByteBufferArray(this._outerPtr, this._innerPtr); + get ptr => _outerPtr; - free() { - _innerPtr.free(); - _outerPtr.free(); - } + free() { + _innerPtr.free(); + _outerPtr.free(); + } } class _ByteBufferArray { - List<_ByteBuffer> _buffers; - - _ByteBufferArray(this._buffers); - - _ByteBufferArray.fromOBXBytesArray(Pointer bytesArray) { - _buffers = []; - Pointer bufferPtrs = Pointer.fromAddress(bytesArray.load()); // bytesArray.bytes - int numBuffers = bytesArray.elementAt(1).load(); // bytesArray.count - for(int i = 0; i < numBuffers; ++i) // loop through instances of "struct OBX_bytes" - _buffers.add(_ByteBuffer.fromOBXBytes(bufferPtrs.elementAt(2 * i))); // 2 * i, because each instance of "struct OBX_bytes" has .data and .size + List<_ByteBuffer> _buffers; + + _ByteBufferArray(this._buffers); + + _ByteBufferArray.fromOBXBytesArray(Pointer bytesArray) { + _buffers = []; + Pointer bufferPtrs = Pointer.fromAddress(bytesArray.load()); // bytesArray.bytes + int numBuffers = bytesArray.elementAt(1).load(); // bytesArray.count + for (int i = 0; i < numBuffers; ++i) // loop through instances of "struct OBX_bytes" + _buffers.add(_ByteBuffer.fromOBXBytes( + bufferPtrs.elementAt(2 * i))); // 2 * i, because each instance of "struct OBX_bytes" has .data and .size + } + + _SerializedByteBufferArray toOBXBytesArray() { + Pointer bufferPtrs = Pointer.allocate(count: _buffers.length * 2); + for (int i = 0; i < _buffers.length; ++i) { + bufferPtrs.elementAt(2 * i).store(_buffers[i].ptr.address); + bufferPtrs.elementAt(2 * i + 1).store(_buffers[i].size); } - _SerializedByteBufferArray toOBXBytesArray() { - Pointer bufferPtrs = Pointer.allocate(count: _buffers.length * 2); - for(int i = 0; i < _buffers.length; ++i) { - bufferPtrs.elementAt(2 * i).store(_buffers[i].ptr.address); - bufferPtrs.elementAt(2 * i + 1).store(_buffers[i].size); - } - - Pointer outerPtr = Pointer.allocate(count: 2); - outerPtr.store(bufferPtrs.address); - outerPtr.elementAt(1).store(_buffers.length); - return _SerializedByteBufferArray(outerPtr, bufferPtrs); - } + Pointer outerPtr = Pointer.allocate(count: 2); + outerPtr.store(bufferPtrs.address); + outerPtr.elementAt(1).store(_buffers.length); + return _SerializedByteBufferArray(outerPtr, bufferPtrs); + } - get buffers => _buffers; + get buffers => _buffers; } class Box { - Store _store; - Pointer _objectboxBox; - var _entityDefinition, _entityReader, _entityBuilder; - - Box(this._store) { - _entityDefinition = _store.getEntityModelDefinitionFromClass(T); - _entityReader = _store.getEntityReaderFromClass(); - _entityBuilder = _store.getEntityBuilderFromClass(); - - _objectboxBox = bindings.obx_box(_store.ptr, _entityDefinition["entity"]["id"]); - checkObxPtr(_objectboxBox, "failed to create box"); + Store _store; + Pointer _objectboxBox; + var _entityDefinition, _entityReader, _entityBuilder; + + Box(this._store) { + _entityDefinition = _store.getEntityModelDefinitionFromClass(T); + _entityReader = _store.getEntityReaderFromClass(); + _entityBuilder = _store.getEntityBuilderFromClass(); + + _objectboxBox = bindings.obx_box(_store.ptr, _entityDefinition["entity"]["id"]); + checkObxPtr(_objectboxBox, "failed to create box"); + } + + _ByteBuffer _marshal(propVals) { + var builder = new fb.Builder(initialSize: 1024); + + // write all strings + Map offsets = {}; + _entityDefinition["properties"].forEach((p) { + switch (p["type"]) { + case OBXPropertyType.String: + offsets[p["name"]] = builder.writeString(propVals[p["name"]]); + break; + } + }); + + // create table and write actual properties + // TODO: make sure that Id property has a value >= 1 + builder.startTable(); + _entityDefinition["properties"].forEach((p) { + var field = p["flatbuffers_id"], value = propVals[p["name"]]; + switch (p["type"]) { + case OBXPropertyType.Bool: + builder.addBool(field, value); + break; + case OBXPropertyType.Char: + builder.addInt8(field, value); + break; + case OBXPropertyType.Byte: + builder.addUint8(field, value); + break; + case OBXPropertyType.Short: + builder.addInt16(field, value); + break; + case OBXPropertyType.Int: + builder.addInt32(field, value); + break; + case OBXPropertyType.Long: + builder.addInt64(field, value); + break; + case OBXPropertyType.String: + builder.addOffset(field, offsets[p["name"]]); + break; + default: + throw Exception("unsupported type: ${p['type']}"); // TODO: support more types + } + }); + + var endOffset = builder.endTable(); + return _ByteBuffer.allocate(builder.finish(endOffset)); + } + + T _unmarshal(_ByteBuffer buffer) { + if (buffer.size == 0 || buffer.address == 0) return null; + Map propVals = {}; + var entity = new _OBXFBEntity(buffer.data); + + _entityDefinition["properties"].forEach((p) { + var propReader; + switch (p["type"]) { + case OBXPropertyType.Bool: + propReader = fb.BoolReader(); + break; + case OBXPropertyType.Char: + propReader = fb.Int8Reader(); + break; + case OBXPropertyType.Byte: + propReader = fb.Uint8Reader(); + break; + case OBXPropertyType.Short: + propReader = fb.Int16Reader(); + break; + case OBXPropertyType.Int: + propReader = fb.Int32Reader(); + break; + case OBXPropertyType.Long: + propReader = fb.Int64Reader(); + break; + case OBXPropertyType.String: + propReader = fb.StringReader(); + break; + default: + throw Exception("unsupported type: ${p['type']}"); // TODO: support more types + } + + propVals[p["name"]] = entity.getProp(propReader, (p["flatbuffers_id"] + 2) * 2); + }); + + return _entityBuilder(propVals); + } + + // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h) + List _unmarshalArray(Pointer bytesArray) { + return _ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => _unmarshal(b)).toList(); + } + + _getOBXPutMode(PutMode mode) { + switch (mode) { + case PutMode.Put: + return OBXPutMode.PUT; + case PutMode.Insert: + return OBXPutMode.INSERT; + case PutMode.Update: + return OBXPutMode.UPDATE; } - - _ByteBuffer _marshal(propVals) { - var builder = new fb.Builder(initialSize: 1024); - - // write all strings - Map offsets = {}; - _entityDefinition["properties"].forEach((p) { - switch(p["type"]) { - case OBXPropertyType.String: offsets[p["name"]] = builder.writeString(propVals[p["name"]]); break; - } - }); - - // create table and write actual properties - // TODO: make sure that Id property has a value >= 1 - builder.startTable(); - _entityDefinition["properties"].forEach((p) { - var field = p["flatbuffers_id"], value = propVals[p["name"]]; - switch(p["type"]) { - case OBXPropertyType.Bool: builder.addBool(field, value); break; - case OBXPropertyType.Char: builder.addInt8(field, value); break; - case OBXPropertyType.Byte: builder.addUint8(field, value); break; - case OBXPropertyType.Short: builder.addInt16(field, value); break; - case OBXPropertyType.Int: builder.addInt32(field, value); break; - case OBXPropertyType.Long: builder.addInt64(field, value); break; - case OBXPropertyType.String: builder.addOffset(field, offsets[p["name"]]); break; - default: throw Exception("unsupported type: ${p['type']}"); // TODO: support more types - } - }); - - var endOffset = builder.endTable(); - return _ByteBuffer.allocate(builder.finish(endOffset)); + } + + // if the respective ID property is given as null or 0, a newly assigned ID is returned, otherwise the existing ID is returned + int put(T inst, {PutMode mode = PutMode.Put}) { + var propVals = _entityReader(inst); + var idPropName = _entityDefinition["idPropertyName"]; + if (propVals[idPropName] == null || propVals[idPropName] == 0) { + final id = bindings.obx_box_id_for_put(_objectboxBox, 0); + propVals[idPropName] = id; } - T _unmarshal(_ByteBuffer buffer) { - if(buffer.size == 0 || buffer.address == 0) - return null; - Map propVals = {}; - var entity = new _OBXFBEntity(buffer.data); - - _entityDefinition["properties"].forEach((p) { - var propReader; - switch(p["type"]) { - case OBXPropertyType.Bool: propReader = fb.BoolReader(); break; - case OBXPropertyType.Char: propReader = fb.Int8Reader(); break; - case OBXPropertyType.Byte: propReader = fb.Uint8Reader(); break; - case OBXPropertyType.Short: propReader = fb.Int16Reader(); break; - case OBXPropertyType.Int: propReader = fb.Int32Reader(); break; - case OBXPropertyType.Long: propReader = fb.Int64Reader(); break; - case OBXPropertyType.String: propReader = fb.StringReader(); break; - default: throw Exception("unsupported type: ${p['type']}"); // TODO: support more types - } - - propVals[p["name"]] = entity.getProp(propReader, (p["flatbuffers_id"] + 2) * 2); - }); - - return _entityBuilder(propVals); + // put object into box and free the buffer + _ByteBuffer buffer = _marshal(propVals); + checkObx( + bindings.obx_box_put(_objectboxBox, propVals[idPropName], buffer.voidPtr, buffer.size, _getOBXPutMode(mode))); + buffer.free(); + return propVals[idPropName]; + } + + // only instances whose ID property ot null or 0 will be given a new, valid number for that. A list of the final IDs is returned + List putMany(List insts, {PutMode mode = PutMode.Put}) { + if (insts.length == 0) return []; + + // read all property values and find number of instances where ID is missing + var allPropVals = insts.map(_entityReader).toList(); + var idPropName = _entityDefinition["idPropertyName"]; + int numInstsMissingId = 0; + for (var instPropVals in allPropVals) + if (instPropVals[idPropName] == null || instPropVals[idPropName] == 0) ++numInstsMissingId; + + // generate new IDs for these instances and set them + Pointer firstIdMemory; + if (numInstsMissingId != 0) { + firstIdMemory = Pointer.allocate(count: 1); + checkObx(bindings.obx_box_ids_for_put(_objectboxBox, numInstsMissingId, firstIdMemory)); + int nextId = firstIdMemory.load(); + firstIdMemory.free(); + for (var instPropVals in allPropVals) + if (instPropVals[idPropName] == null || instPropVals[idPropName] == 0) instPropVals[idPropName] = nextId++; } - // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h) - List _unmarshalArray(Pointer bytesArray) { - return _ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => _unmarshal(b)).toList(); + // because obx_box_put_many also needs a list of all IDs of the elements to be put into the box, generate this list now (only needed if not all IDs have been generated) + Pointer allIdsMemory = Pointer.allocate(count: insts.length); + for (int i = 0; i < allPropVals.length; ++i) allIdsMemory.elementAt(i).store(allPropVals[i][idPropName]); + + // marshal all objects to be put into the box + var putObjects = _ByteBufferArray(allPropVals.map(_marshal).toList()).toOBXBytesArray(); + + checkObx(bindings.obx_box_put_many(_objectboxBox, putObjects.ptr, allIdsMemory, _getOBXPutMode(mode))); + putObjects.free(); + allIdsMemory.free(); + return allPropVals.map((p) => p[idPropName] as int).toList(); + } + + // TODO move to Store + T _runInTransaction(bool readOnly, T Function() fn) { + assert(readOnly); // TODO implement write transactions + + Pointer txn = bindings.obx_txn_read(_store.ptr); + checkObxPtr(txn, "failed to created transaction"); + try { + return fn(); + } finally { + checkObx(bindings.obx_txn_close(txn)); } - - _getOBXPutMode(PutMode mode) { - switch(mode) { - case PutMode.Put: return OBXPutMode.PUT; - case PutMode.Insert: return OBXPutMode.INSERT; - case PutMode.Update: return OBXPutMode.UPDATE; - } - } - - // if the respective ID property is given as null or 0, a newly assigned ID is returned, otherwise the existing ID is returned - int put(T inst, {PutMode mode = PutMode.Put}) { - var propVals = _entityReader(inst); - var idPropName = _entityDefinition["idPropertyName"]; - if(propVals[idPropName] == null || propVals[idPropName] == 0) { - final id = bindings.obx_box_id_for_put(_objectboxBox, 0); - propVals[idPropName] = id; - } - - // put object into box and free the buffer - _ByteBuffer buffer = _marshal(propVals); - checkObx(bindings.obx_box_put(_objectboxBox, propVals[idPropName], buffer.voidPtr, buffer.size, _getOBXPutMode(mode))); - buffer.free(); - return propVals[idPropName]; - } - - // only instances whose ID property ot null or 0 will be given a new, valid number for that. A list of the final IDs is returned - List putMany(List insts, {PutMode mode = PutMode.Put}) { - if(insts.length == 0) - return []; - - // read all property values and find number of instances where ID is missing - var allPropVals = insts.map(_entityReader).toList(); - var idPropName = _entityDefinition["idPropertyName"]; - int numInstsMissingId = 0; - for(var instPropVals in allPropVals) - if(instPropVals[idPropName] == null || instPropVals[idPropName] == 0) - ++numInstsMissingId; - - // generate new IDs for these instances and set them - Pointer firstIdMemory; - if(numInstsMissingId != 0) { - firstIdMemory = Pointer.allocate(count: 1); - checkObx(bindings.obx_box_ids_for_put(_objectboxBox, numInstsMissingId, firstIdMemory)); - int nextId = firstIdMemory.load(); - firstIdMemory.free(); - for(var instPropVals in allPropVals) - if(instPropVals[idPropName] == null || instPropVals[idPropName] == 0) - instPropVals[idPropName] = nextId++; - - } - - // because obx_box_put_many also needs a list of all IDs of the elements to be put into the box, generate this list now (only needed if not all IDs have been generated) - Pointer allIdsMemory = Pointer.allocate(count: insts.length); - for(int i = 0; i < allPropVals.length; ++i) - allIdsMemory.elementAt(i).store(allPropVals[i][idPropName]); - - // marshal all objects to be put into the box - var putObjects = _ByteBufferArray(allPropVals.map(_marshal).toList()).toOBXBytesArray(); - - checkObx(bindings.obx_box_put_many(_objectboxBox, putObjects.ptr, allIdsMemory, _getOBXPutMode(mode))); - putObjects.free(); - allIdsMemory.free(); - return allPropVals.map((p) => p[idPropName] as int).toList(); - } - - // TODO move to Store - T _runInTransaction(bool readOnly, T Function() fn) { - assert(readOnly); // TODO implement write transactions - - Pointer txn = bindings.obx_txn_read(_store.ptr); - checkObxPtr(txn, "failed to created transaction"); - try { - return fn(); - } finally { - checkObx(bindings.obx_txn_close(txn)); - } - } - - get(int id) { - Pointer> dataPtr = Pointer>.allocate(); - Pointer sizePtr = Pointer.allocate(); - - // get element with specified id from database - return _runInTransaction(true, () { - checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr)); - - Pointer data = Pointer.fromAddress(dataPtr.load>().address); - var size = sizePtr.load(); - - // transform bytes from memory to Dart byte list - var buffer = _ByteBuffer(data, size); - dataPtr.free(); - sizePtr.free(); - - return _unmarshal(buffer); - }); + } + + get(int id) { + Pointer> dataPtr = Pointer>.allocate(); + Pointer sizePtr = Pointer.allocate(); + + // get element with specified id from database + return _runInTransaction(true, () { + checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr)); + + Pointer data = Pointer.fromAddress(dataPtr.load>().address); + var size = sizePtr.load(); + + // transform bytes from memory to Dart byte list + var buffer = _ByteBuffer(data, size); + dataPtr.free(); + sizePtr.free(); + + return _unmarshal(buffer); + }); + } + + List _getMany(Pointer Function() cCall) { + return _runInTransaction(true, () { + // OBX_bytes_array*, has two Uint64 members (data and size) + Pointer bytesArray = cCall(); + try { + return _unmarshalArray(bytesArray); + } finally { + bindings.obx_bytes_array_free(bytesArray); + } + }); + } + + // returns list of ids.length objects of type T, each corresponding to the location of its ID in the ids array. Non-existant IDs become null + List getMany(List ids) { + if (ids.length == 0) return []; + + // write ids in buffer for FFI call + var idArray = new _IDArray(ids); + + try { + return _getMany(() => checkObxPtr( + bindings.obx_box_get_many(_objectboxBox, idArray.ptr), "failed to get many objects from box", true)); + } finally { + idArray.free(); } + } - List _getMany(Pointer Function() cCall) { - return _runInTransaction(true, () { - // OBX_bytes_array*, has two Uint64 members (data and size) - Pointer bytesArray = cCall(); - try { - return _unmarshalArray(bytesArray); - } finally { - bindings.obx_bytes_array_free(bytesArray); - } - }); - } - - // returns list of ids.length objects of type T, each corresponding to the location of its ID in the ids array. Non-existant IDs become null - List getMany(List ids) { - if (ids.length == 0) - return []; - - // write ids in buffer for FFI call - var idArray = new _IDArray(ids); - - try { - return _getMany(() => - checkObxPtr( - bindings.obx_box_get_many(_objectboxBox, idArray.ptr), - "failed to get many objects from box", true)); - } finally { - idArray.free(); - } - } - - List getAll() { - return _getMany(() => - checkObxPtr( - bindings.obx_box_get_all(_objectboxBox), - "failed to get all objects from box", true)); - } + List getAll() { + return _getMany( + () => checkObxPtr(bindings.obx_box_get_all(_objectboxBox), "failed to get all objects from box", true)); + } - close() { - if(_store != null) { - _store.close(); - _store = null; - } + close() { + if (_store != null) { + _store.close(); + _store = null; } + } - get ptr => _objectboxBox; + get ptr => _objectboxBox; } diff --git a/lib/src/common.dart b/lib/src/common.dart index 4146218cb..121ddaf90 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -4,34 +4,35 @@ import "bindings/bindings.dart"; import "package:ffi/ffi.dart"; class Common { - static List version() { - Pointer majorPtr = Pointer.allocate(), minorPtr = Pointer.allocate(), patchPtr = Pointer.allocate(); - bindings.obx_version(majorPtr, minorPtr, patchPtr); - var ret = [majorPtr.load(), minorPtr.load(), patchPtr.load()]; - majorPtr.free(); - minorPtr.free(); - patchPtr.free(); - return ret; - } + static List version() { + Pointer majorPtr = Pointer.allocate(), + minorPtr = Pointer.allocate(), + patchPtr = Pointer.allocate(); + bindings.obx_version(majorPtr, minorPtr, patchPtr); + var ret = [majorPtr.load(), minorPtr.load(), patchPtr.load()]; + majorPtr.free(); + minorPtr.free(); + patchPtr.free(); + return ret; + } - static String versionString() { - return Utf8.fromUtf8(bindings.obx_version_string().cast()); - } + static String versionString() { + return Utf8.fromUtf8(bindings.obx_version_string().cast()); + } - static String lastErrorString([err]) { - if(err != null) - return "code $err"; + static String lastErrorString([err]) { + if (err != null) return "code $err"; - int last = bindings.obx_last_error_code(); - int last2 = bindings.obx_last_error_secondary(); - String desc = Utf8.fromUtf8(bindings.obx_last_error_message().cast()); - return "code $last, $last2 ($desc)"; - } + int last = bindings.obx_last_error_code(); + int last2 = bindings.obx_last_error_secondary(); + String desc = Utf8.fromUtf8(bindings.obx_last_error_message().cast()); + return "code $last, $last2 ($desc)"; + } } class ObjectBoxException { - final String message; - ObjectBoxException(msg) : message = "ObjectBoxException: " + msg; + final String message; + ObjectBoxException(msg) : message = "ObjectBoxException: " + msg; - String toString() => message; + String toString() => message; } diff --git a/lib/src/model.dart b/lib/src/model.dart index efa559291..7b53d7a12 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -6,73 +6,74 @@ import "bindings/helpers.dart"; import "package:ffi/ffi.dart"; class Entity { - final int id, uid; - const Entity({this.id, this.uid}) : assert(id != null && id != 0), assert(uid != null && uid != 0); + final int id, uid; + const Entity({this.id, this.uid}) + : assert(id != null && id != 0), + assert(uid != null && uid != 0); } class Property { - final int type; - final int id, uid; - const Property({this.id, this.uid, this.type = null}); + final int type; + final int id, uid; + const Property({this.id, this.uid, this.type = null}); } class Id { - final int id, uid; - const Id({this.id, this.uid}); // type is always long + final int id, uid; + const Id({this.id, this.uid}); // type is always long } class Model { - Pointer _objectboxModel; + Pointer _objectboxModel; - Model(List> modelDefinitions) { - _objectboxModel = bindings.obx_model(); - checkObxPtr(_objectboxModel, "failed to create model"); + Model(List> modelDefinitions) { + _objectboxModel = bindings.obx_model(); + checkObxPtr(_objectboxModel, "failed to create model"); + try { + // transform classes into model descriptions and loop through them + modelDefinitions.forEach((m) { + // start entity + var entityUtf8 = Utf8.toUtf8(m["entity"]["name"]); try { - // transform classes into model descriptions and loop through them - modelDefinitions.forEach((m) { - // start entity - var entityUtf8 = Utf8.toUtf8(m["entity"]["name"]); - try { - var entityNamePointer = entityUtf8.cast(); - checkObx(bindings.obx_model_entity( - _objectboxModel, entityNamePointer, m["entity"]["id"], - m["entity"]["uid"])); - }finally { - // same pointer - entityUtf8.free(); - } - - // add all properties - m["properties"].forEach((p) { - var propertyUtf8 = Utf8.toUtf8(p["name"]); - try { - var propertyNamePointer = propertyUtf8.cast(); - checkObx(bindings.obx_model_property(_objectboxModel, propertyNamePointer, p["type"], p["id"], p["uid"])); - checkObx(bindings.obx_model_property_flags(_objectboxModel, p["flags"])); - }finally { - propertyUtf8.free(); - } - }); + var entityNamePointer = entityUtf8.cast(); + checkObx( + bindings.obx_model_entity(_objectboxModel, entityNamePointer, m["entity"]["id"], m["entity"]["uid"])); + } finally { + // same pointer + entityUtf8.free(); + } - // set last property id - if(m["properties"].length > 0) { - var lastProp = m["properties"][m["properties"].length - 1]; - checkObx(bindings.obx_model_entity_last_property_id(_objectboxModel, lastProp["id"], lastProp["uid"])); - } - }); + // add all properties + m["properties"].forEach((p) { + var propertyUtf8 = Utf8.toUtf8(p["name"]); + try { + var propertyNamePointer = propertyUtf8.cast(); + checkObx(bindings.obx_model_property(_objectboxModel, propertyNamePointer, p["type"], p["id"], p["uid"])); + checkObx(bindings.obx_model_property_flags(_objectboxModel, p["flags"])); + } finally { + propertyUtf8.free(); + } + }); - // set last entity id - if(modelDefinitions.length > 0) { - var lastEntity = modelDefinitions[modelDefinitions.length - 1]["entity"]; - bindings.obx_model_last_entity_id(_objectboxModel, lastEntity["id"], lastEntity["uid"]); - } - } catch(e) { - bindings.obx_model_free(_objectboxModel); - _objectboxModel = null; - rethrow; + // set last property id + if (m["properties"].length > 0) { + var lastProp = m["properties"][m["properties"].length - 1]; + checkObx(bindings.obx_model_entity_last_property_id(_objectboxModel, lastProp["id"], lastProp["uid"])); } + }); + + // set last entity id + if (modelDefinitions.length > 0) { + var lastEntity = modelDefinitions[modelDefinitions.length - 1]["entity"]; + bindings.obx_model_last_entity_id(_objectboxModel, lastEntity["id"], lastEntity["uid"]); + } + } catch (e) { + bindings.obx_model_free(_objectboxModel); + _objectboxModel = null; + rethrow; } + } - get ptr => _objectboxModel; + get ptr => _objectboxModel; } diff --git a/lib/src/store.dart b/lib/src/store.dart index 064d84f17..08d163301 100644 --- a/lib/src/store.dart +++ b/lib/src/store.dart @@ -7,58 +7,54 @@ import "model.dart"; import "package:ffi/ffi.dart"; - - class Store { - Pointer _objectboxStore; - Map> _modelDefinitions = {}; + Pointer _objectboxStore; + Map> _modelDefinitions = {}; - Store(List> defs, {String directory, int maxDBSizeInKB, int fileMode, int maxReaders}) { // TODO: allow setting options, e.g. database path - defs.forEach((d) => _modelDefinitions[d[0]] = d[1]); - var model = Model(defs.map((d) => d[1]["model"] as Map).toList()); + Store(List> defs, {String directory, int maxDBSizeInKB, int fileMode, int maxReaders}) { + // TODO: allow setting options, e.g. database path + defs.forEach((d) => _modelDefinitions[d[0]] = d[1]); + var model = Model(defs.map((d) => d[1]["model"] as Map).toList()); - var opt = bindings.obx_opt(); - checkObxPtr(opt, "failed to create store options"); + var opt = bindings.obx_opt(); + checkObxPtr(opt, "failed to create store options"); + try { + checkObx(bindings.obx_opt_model(opt, model.ptr)); + if (directory != null && directory.length != 0) { + var cStr = Utf8.toUtf8(directory).cast(); try { - checkObx(bindings.obx_opt_model(opt, model.ptr)); - if (directory != null && directory.length != 0) { - var cStr = Utf8.toUtf8(directory).cast(); - try { - checkObx(bindings.obx_opt_directory(opt, cStr)); - }finally { - cStr.free(); - } - } - if (maxDBSizeInKB != null && maxDBSizeInKB > 0) - bindings.obx_opt_max_db_size_in_kb(opt, maxDBSizeInKB); - if (fileMode != null && fileMode >= 0) - bindings.obx_opt_file_mode(opt, fileMode); - if (maxReaders != null && maxReaders > 0) - bindings.obx_opt_max_readers(opt, maxReaders); - } catch(e) { - bindings.obx_opt_free(opt); - rethrow; + checkObx(bindings.obx_opt_directory(opt, cStr)); + } finally { + cStr.free(); } - _objectboxStore = bindings.obx_store_open(opt); - checkObxPtr(_objectboxStore, "failed to create store"); + } + if (maxDBSizeInKB != null && maxDBSizeInKB > 0) bindings.obx_opt_max_db_size_in_kb(opt, maxDBSizeInKB); + if (fileMode != null && fileMode >= 0) bindings.obx_opt_file_mode(opt, fileMode); + if (maxReaders != null && maxReaders > 0) bindings.obx_opt_max_readers(opt, maxReaders); + } catch (e) { + bindings.obx_opt_free(opt); + rethrow; } + _objectboxStore = bindings.obx_store_open(opt); + checkObxPtr(_objectboxStore, "failed to create store"); + } - close() { - checkObx(bindings.obx_store_close(_objectboxStore)); - } + close() { + checkObx(bindings.obx_store_close(_objectboxStore)); + } - getEntityModelDefinitionFromClass(cls) { - return _modelDefinitions[cls]["model"]; - } + getEntityModelDefinitionFromClass(cls) { + return _modelDefinitions[cls]["model"]; + } - getEntityReaderFromClass() { - return _modelDefinitions[T]["reader"] as Map Function(T); - } + getEntityReaderFromClass() { + return _modelDefinitions[T]["reader"] as Map Function(T); + } - getEntityBuilderFromClass() { - return _modelDefinitions[T]["builder"] as T Function(Map); - } + getEntityBuilderFromClass() { + return _modelDefinitions[T]["builder"] as T Function(Map); + } - get ptr => _objectboxStore; + get ptr => _objectboxStore; } diff --git a/test/test.dart b/test/test.dart index f8a1f099c..c8d27b786 100644 --- a/test/test.dart +++ b/test/test.dart @@ -5,103 +5,102 @@ part "test.g.dart"; @Entity(id: 1, uid: 1) class TestEntity { - @Id(id: 1, uid: 1001) - int id; + @Id(id: 1, uid: 1001) + int id; - @Property(id: 2, uid: 1002) - String text; + @Property(id: 2, uid: 1002) + String text; - TestEntity(); - TestEntity.constructWithId(this.id, this.text); - TestEntity.construct(this.text); + TestEntity(); + TestEntity.constructWithId(this.id, this.text); + TestEntity.construct(this.text); } main() { - Store store; - Box box; + Store store; + Box box; - setUp(() { - store = Store([[TestEntity, TestEntity_OBXDefs]]); - box = Box(store); - }); - - group("box", () { - test(".put() returns a valid id", () { - int putId = box.put(TestEntity.construct("Hello")); - expect(putId, greaterThan(0)); - }); + setUp(() { + store = Store([ + [TestEntity, TestEntity_OBXDefs] + ]); + box = Box(store); + }); - test(".get() returns the correct item", () { - final int putId = box.put(TestEntity.construct("Hello")); - final TestEntity item = box.get(putId); - expect(item.id, equals(putId)); - expect(item.text, equals("Hello")); - }); + group("box", () { + test(".put() returns a valid id", () { + int putId = box.put(TestEntity.construct("Hello")); + expect(putId, greaterThan(0)); + }); - test(".put() and box.get() keep Unicode characters", () { - final String text = "😄你好"; - final TestEntity inst = box.get(box.put(TestEntity.construct(text))); - expect(inst.text, equals(text)); - }); + test(".get() returns the correct item", () { + final int putId = box.put(TestEntity.construct("Hello")); + final TestEntity item = box.get(putId); + expect(item.id, equals(putId)); + expect(item.text, equals("Hello")); + }); - test(".put() can update an item", () { - final int putId1 = box.put(TestEntity.construct("One")); - final int putId2 = box.put(TestEntity.constructWithId(putId1, "Two")); - expect(putId2, equals(putId1)); - final TestEntity item = box.get(putId2); - expect(item.text, equals("Two")); - }); + test(".put() and box.get() keep Unicode characters", () { + final String text = "😄你好"; + final TestEntity inst = box.get(box.put(TestEntity.construct(text))); + expect(inst.text, equals(text)); + }); - test(".getAll retrieves all items", () { - final int id1 = box.put(TestEntity.construct("One")); - final int id2 = box.put(TestEntity.construct("Two")); - final int id3 = box.put(TestEntity.construct("Three")); - final List items = box.getAll(); - expect(items.length, equals(3)); - expect(items.where((i) => i.id == id1).single.text, equals("One")); - expect(items.where((i) => i.id == id2).single.text, equals("Two")); - expect(items.where((i) => i.id == id3).single.text, equals("Three")); - }); + test(".put() can update an item", () { + final int putId1 = box.put(TestEntity.construct("One")); + final int putId2 = box.put(TestEntity.constructWithId(putId1, "Two")); + expect(putId2, equals(putId1)); + final TestEntity item = box.get(putId2); + expect(item.text, equals("Two")); + }); - test(".putMany inserts multiple items", () { - final List items = [ - TestEntity.construct("One"), - TestEntity.construct("Two"), - TestEntity.construct("Three") - ]; - box.putMany(items); - final List itemsFetched = box.getAll(); - expect(itemsFetched.length, equals(items.length)); - }); + test(".getAll retrieves all items", () { + final int id1 = box.put(TestEntity.construct("One")); + final int id2 = box.put(TestEntity.construct("Two")); + final int id3 = box.put(TestEntity.construct("Three")); + final List items = box.getAll(); + expect(items.length, equals(3)); + expect(items.where((i) => i.id == id1).single.text, equals("One")); + expect(items.where((i) => i.id == id2).single.text, equals("Two")); + expect(items.where((i) => i.id == id3).single.text, equals("Three")); + }); - test(".putMany returns the new item IDs", () { - final List items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"].map((s) => TestEntity.construct(s)).toList(); - final List ids = box.putMany(items); - expect(ids.length, equals(items.length)); - for(int i = 0; i < items.length; ++i) - expect(box.get(ids[i]).text, equals(items[i].text)); - }); + test(".putMany inserts multiple items", () { + final List items = [ + TestEntity.construct("One"), + TestEntity.construct("Two"), + TestEntity.construct("Three") + ]; + box.putMany(items); + final List itemsFetched = box.getAll(); + expect(itemsFetched.length, equals(items.length)); + }); - test(".getMany correctly handles non-existant items", () { - final List items = ["One", "Two"].map((s) => TestEntity.construct(s)).toList(); - final List ids = box.putMany(items); - int otherId = 1; - while(ids.indexWhere((id) => id == otherId) != -1) - ++otherId; - final List fetchedItems = box.getMany([ids[0], otherId, ids[1]]); - expect(fetchedItems.length, equals(3)); - expect(fetchedItems[0].text, equals("One")); - expect(fetchedItems[1], equals(null)); - expect(fetchedItems[2].text, equals("Two")); - }); + test(".putMany returns the new item IDs", () { + final List items = + ["One", "Two", "Three", "Four", "Five", "Six", "Seven"].map((s) => TestEntity.construct(s)).toList(); + final List ids = box.putMany(items); + expect(ids.length, equals(items.length)); + for (int i = 0; i < items.length; ++i) expect(box.get(ids[i]).text, equals(items[i].text)); }); - tearDown(() { - if(store != null) - store.close(); - store = null; - var dir = new Directory("objectbox"); - if(dir.existsSync()) - dir.deleteSync(recursive: true); + test(".getMany correctly handles non-existant items", () { + final List items = ["One", "Two"].map((s) => TestEntity.construct(s)).toList(); + final List ids = box.putMany(items); + int otherId = 1; + while (ids.indexWhere((id) => id == otherId) != -1) ++otherId; + final List fetchedItems = box.getMany([ids[0], otherId, ids[1]]); + expect(fetchedItems.length, equals(3)); + expect(fetchedItems[0].text, equals("One")); + expect(fetchedItems[1], equals(null)); + expect(fetchedItems[2].text, equals("Two")); }); + }); + + tearDown(() { + if (store != null) store.close(); + store = null; + var dir = new Directory("objectbox"); + if (dir.existsSync()) dir.deleteSync(recursive: true); + }); } From ed69c56a440544c9881bc351181fd18ca46112ff Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:21:00 +0200 Subject: [PATCH 2/7] Move ObjectBox struct wrappers to separate file --- lib/src/bindings/structs.dart | 97 +++++++++++++++++++++++++++++ lib/src/box.dart | 112 +++------------------------------- 2 files changed, 106 insertions(+), 103 deletions(-) create mode 100644 lib/src/bindings/structs.dart diff --git a/lib/src/bindings/structs.dart b/lib/src/bindings/structs.dart new file mode 100644 index 000000000..53668feab --- /dev/null +++ b/lib/src/bindings/structs.dart @@ -0,0 +1,97 @@ +import "dart:ffi"; +import "dart:typed_data" show Uint8List; + +class IDArray { + // wrapper for "struct OBX_id_array" + Pointer _idsPtr, _structPtr; + + IDArray(List ids) { + _idsPtr = Pointer.allocate(count: ids.length); + for (int i = 0; i < ids.length; ++i) _idsPtr.elementAt(i).store(ids[i]); + _structPtr = Pointer.allocate(count: 2); + _structPtr.store(_idsPtr.address); + _structPtr.elementAt(1).store(ids.length); + } + + get ptr => _structPtr; + + free() { + _idsPtr.free(); + _structPtr.free(); + } +} + +class ByteBuffer { + Pointer _ptr; + int _size; + + ByteBuffer(this._ptr, this._size); + + ByteBuffer.allocate(Uint8List dartData, [bool align = true]) { + _ptr = Pointer.allocate(count: align ? ((dartData.length + 3.0) ~/ 4.0) * 4 : dartData.length); + for (int i = 0; i < dartData.length; ++i) _ptr.elementAt(i).store(dartData[i]); + _size = dartData.length; + } + + ByteBuffer.fromOBXBytes(Pointer obxPtr) { + // extract fields from "struct OBX_bytes" + _ptr = Pointer.fromAddress(obxPtr.load()); + _size = obxPtr.elementAt(1).load(); + } + + get ptr => _ptr; + get voidPtr => Pointer.fromAddress(_ptr.address); + get address => _ptr.address; + get size => _size; + + Uint8List get data { + var buffer = new Uint8List(size); + for (int i = 0; i < size; ++i) buffer[i] = _ptr.elementAt(i).load(); + return buffer; + } + + free() => _ptr.free(); +} + +class _SerializedByteBufferArray { + Pointer _outerPtr, + _innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes + + _SerializedByteBufferArray(this._outerPtr, this._innerPtr); + get ptr => _outerPtr; + + free() { + _innerPtr.free(); + _outerPtr.free(); + } +} + +class ByteBufferArray { + List _buffers; + + ByteBufferArray(this._buffers); + + ByteBufferArray.fromOBXBytesArray(Pointer bytesArray) { + _buffers = []; + Pointer bufferPtrs = Pointer.fromAddress(bytesArray.load()); // bytesArray.bytes + int numBuffers = bytesArray.elementAt(1).load(); // bytesArray.count + for (int i = 0; i < numBuffers; ++i) // loop through instances of "struct OBX_bytes" + _buffers.add(ByteBuffer.fromOBXBytes( + bufferPtrs.elementAt(2 * i))); // 2 * i, because each instance of "struct OBX_bytes" has .data and .size + } + + _SerializedByteBufferArray toOBXBytesArray() { + Pointer bufferPtrs = Pointer.allocate(count: _buffers.length * 2); + for (int i = 0; i < _buffers.length; ++i) { + bufferPtrs.elementAt(2 * i).store(_buffers[i].ptr.address); + bufferPtrs.elementAt(2 * i + 1).store(_buffers[i].size); + } + + Pointer outerPtr = Pointer.allocate(count: 2); + outerPtr.store(bufferPtrs.address); + outerPtr.elementAt(1).store(_buffers.length); + return _SerializedByteBufferArray(outerPtr, bufferPtrs); + } + + get buffers => _buffers; +} diff --git a/lib/src/box.dart b/lib/src/box.dart index bc2e41a7d..e20f1587f 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -6,6 +6,7 @@ import "store.dart"; import "bindings/bindings.dart"; import "bindings/constants.dart"; import "bindings/helpers.dart"; +import "bindings/structs.dart"; enum PutMode { Put, @@ -34,101 +35,6 @@ class _OBXFBEntityReader extends fb.TableReader<_OBXFBEntity> { _OBXFBEntity createObject(fb.BufferContext bc, int offset) => new _OBXFBEntity._(bc, offset); } -class _IDArray { - // wrapper for "struct OBX_id_array" - Pointer _idsPtr, _structPtr; - - _IDArray(List ids) { - _idsPtr = Pointer.allocate(count: ids.length); - for (int i = 0; i < ids.length; ++i) _idsPtr.elementAt(i).store(ids[i]); - _structPtr = Pointer.allocate(count: 2); - _structPtr.store(_idsPtr.address); - _structPtr.elementAt(1).store(ids.length); - } - - get ptr => _structPtr; - - free() { - _idsPtr.free(); - _structPtr.free(); - } -} - -class _ByteBuffer { - Pointer _ptr; - int _size; - - _ByteBuffer(this._ptr, this._size); - - _ByteBuffer.allocate(Uint8List dartData, [bool align = true]) { - _ptr = Pointer.allocate(count: align ? ((dartData.length + 3.0) ~/ 4.0) * 4 : dartData.length); - for (int i = 0; i < dartData.length; ++i) _ptr.elementAt(i).store(dartData[i]); - _size = dartData.length; - } - - _ByteBuffer.fromOBXBytes(Pointer obxPtr) { - // extract fields from "struct OBX_bytes" - _ptr = Pointer.fromAddress(obxPtr.load()); - _size = obxPtr.elementAt(1).load(); - } - - get ptr => _ptr; - get voidPtr => Pointer.fromAddress(_ptr.address); - get address => _ptr.address; - get size => _size; - - Uint8List get data { - var buffer = new Uint8List(size); - for (int i = 0; i < size; ++i) buffer[i] = _ptr.elementAt(i).load(); - return buffer; - } - - free() => _ptr.free(); -} - -class _SerializedByteBufferArray { - Pointer _outerPtr, - _innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes - - _SerializedByteBufferArray(this._outerPtr, this._innerPtr); - get ptr => _outerPtr; - - free() { - _innerPtr.free(); - _outerPtr.free(); - } -} - -class _ByteBufferArray { - List<_ByteBuffer> _buffers; - - _ByteBufferArray(this._buffers); - - _ByteBufferArray.fromOBXBytesArray(Pointer bytesArray) { - _buffers = []; - Pointer bufferPtrs = Pointer.fromAddress(bytesArray.load()); // bytesArray.bytes - int numBuffers = bytesArray.elementAt(1).load(); // bytesArray.count - for (int i = 0; i < numBuffers; ++i) // loop through instances of "struct OBX_bytes" - _buffers.add(_ByteBuffer.fromOBXBytes( - bufferPtrs.elementAt(2 * i))); // 2 * i, because each instance of "struct OBX_bytes" has .data and .size - } - - _SerializedByteBufferArray toOBXBytesArray() { - Pointer bufferPtrs = Pointer.allocate(count: _buffers.length * 2); - for (int i = 0; i < _buffers.length; ++i) { - bufferPtrs.elementAt(2 * i).store(_buffers[i].ptr.address); - bufferPtrs.elementAt(2 * i + 1).store(_buffers[i].size); - } - - Pointer outerPtr = Pointer.allocate(count: 2); - outerPtr.store(bufferPtrs.address); - outerPtr.elementAt(1).store(_buffers.length); - return _SerializedByteBufferArray(outerPtr, bufferPtrs); - } - - get buffers => _buffers; -} - class Box { Store _store; Pointer _objectboxBox; @@ -143,7 +49,7 @@ class Box { checkObxPtr(_objectboxBox, "failed to create box"); } - _ByteBuffer _marshal(propVals) { + ByteBuffer _marshal(propVals) { var builder = new fb.Builder(initialSize: 1024); // write all strings @@ -189,10 +95,10 @@ class Box { }); var endOffset = builder.endTable(); - return _ByteBuffer.allocate(builder.finish(endOffset)); + return ByteBuffer.allocate(builder.finish(endOffset)); } - T _unmarshal(_ByteBuffer buffer) { + T _unmarshal(ByteBuffer buffer) { if (buffer.size == 0 || buffer.address == 0) return null; Map propVals = {}; var entity = new _OBXFBEntity(buffer.data); @@ -233,7 +139,7 @@ class Box { // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h) List _unmarshalArray(Pointer bytesArray) { - return _ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => _unmarshal(b)).toList(); + return ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => _unmarshal(b)).toList(); } _getOBXPutMode(PutMode mode) { @@ -257,7 +163,7 @@ class Box { } // put object into box and free the buffer - _ByteBuffer buffer = _marshal(propVals); + ByteBuffer buffer = _marshal(propVals); checkObx( bindings.obx_box_put(_objectboxBox, propVals[idPropName], buffer.voidPtr, buffer.size, _getOBXPutMode(mode))); buffer.free(); @@ -291,7 +197,7 @@ class Box { for (int i = 0; i < allPropVals.length; ++i) allIdsMemory.elementAt(i).store(allPropVals[i][idPropName]); // marshal all objects to be put into the box - var putObjects = _ByteBufferArray(allPropVals.map(_marshal).toList()).toOBXBytesArray(); + var putObjects = ByteBufferArray(allPropVals.map(_marshal).toList()).toOBXBytesArray(); checkObx(bindings.obx_box_put_many(_objectboxBox, putObjects.ptr, allIdsMemory, _getOBXPutMode(mode))); putObjects.free(); @@ -324,7 +230,7 @@ class Box { var size = sizePtr.load(); // transform bytes from memory to Dart byte list - var buffer = _ByteBuffer(data, size); + var buffer = ByteBuffer(data, size); dataPtr.free(); sizePtr.free(); @@ -349,7 +255,7 @@ class Box { if (ids.length == 0) return []; // write ids in buffer for FFI call - var idArray = new _IDArray(ids); + var idArray = new IDArray(ids); try { return _getMany(() => checkObxPtr( From b65bc1c87703550056e4c67a9571c7b39f975f75 Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:34:49 +0200 Subject: [PATCH 3/7] Move Flatbuffers marshalling to separate file --- lib/src/bindings/flatbuffers.dart | 126 +++++++++++++++++++++++++++++ lib/src/box.dart | 128 ++---------------------------- 2 files changed, 133 insertions(+), 121 deletions(-) create mode 100644 lib/src/bindings/flatbuffers.dart diff --git a/lib/src/bindings/flatbuffers.dart b/lib/src/bindings/flatbuffers.dart new file mode 100644 index 000000000..cd1b6cde0 --- /dev/null +++ b/lib/src/bindings/flatbuffers.dart @@ -0,0 +1,126 @@ +import "dart:ffi"; +import "dart:typed_data" show Uint8List; +import "package:flat_buffers/flat_buffers.dart" as fb; + +import "constants.dart"; +import "structs.dart"; + +class _OBXFBEntity { + _OBXFBEntity._(this._bc, this._bcOffset); + static const fb.Reader<_OBXFBEntity> reader = const _OBXFBEntityReader(); + factory _OBXFBEntity(Uint8List bytes) { + fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } + + final fb.BufferContext _bc; + final int _bcOffset; + + getProp(propReader, int field) => propReader.vTableGet(_bc, _bcOffset, field); +} + +class _OBXFBEntityReader extends fb.TableReader<_OBXFBEntity> { + const _OBXFBEntityReader(); + + @override + _OBXFBEntity createObject(fb.BufferContext bc, int offset) => new _OBXFBEntity._(bc, offset); +} + +class OBXFlatbuffersManager { + var _entityDefinition, _entityReader, _entityBuilder; + + OBXFlatbuffersManager(this._entityDefinition, this._entityReader, this._entityBuilder); + + ByteBuffer marshal(propVals) { + var builder = new fb.Builder(initialSize: 1024); + + // write all strings + Map offsets = {}; + _entityDefinition["properties"].forEach((p) { + switch (p["type"]) { + case OBXPropertyType.String: + offsets[p["name"]] = builder.writeString(propVals[p["name"]]); + break; + } + }); + + // create table and write actual properties + // TODO: make sure that Id property has a value >= 1 + builder.startTable(); + _entityDefinition["properties"].forEach((p) { + var field = p["flatbuffers_id"], value = propVals[p["name"]]; + switch (p["type"]) { + case OBXPropertyType.Bool: + builder.addBool(field, value); + break; + case OBXPropertyType.Char: + builder.addInt8(field, value); + break; + case OBXPropertyType.Byte: + builder.addUint8(field, value); + break; + case OBXPropertyType.Short: + builder.addInt16(field, value); + break; + case OBXPropertyType.Int: + builder.addInt32(field, value); + break; + case OBXPropertyType.Long: + builder.addInt64(field, value); + break; + case OBXPropertyType.String: + builder.addOffset(field, offsets[p["name"]]); + break; + default: + throw Exception("unsupported type: ${p['type']}"); // TODO: support more types + } + }); + + var endOffset = builder.endTable(); + return ByteBuffer.allocate(builder.finish(endOffset)); + } + + T unmarshal(ByteBuffer buffer) { + if (buffer.size == 0 || buffer.address == 0) return null; + Map propVals = {}; + var entity = new _OBXFBEntity(buffer.data); + + _entityDefinition["properties"].forEach((p) { + var propReader; + switch (p["type"]) { + case OBXPropertyType.Bool: + propReader = fb.BoolReader(); + break; + case OBXPropertyType.Char: + propReader = fb.Int8Reader(); + break; + case OBXPropertyType.Byte: + propReader = fb.Uint8Reader(); + break; + case OBXPropertyType.Short: + propReader = fb.Int16Reader(); + break; + case OBXPropertyType.Int: + propReader = fb.Int32Reader(); + break; + case OBXPropertyType.Long: + propReader = fb.Int64Reader(); + break; + case OBXPropertyType.String: + propReader = fb.StringReader(); + break; + default: + throw Exception("unsupported type: ${p['type']}"); // TODO: support more types + } + + propVals[p["name"]] = entity.getProp(propReader, (p["flatbuffers_id"] + 2) * 2); + }); + + return _entityBuilder(propVals); + } + + // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h) + List unmarshalArray(Pointer bytesArray) { + return ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => unmarshal(b)).toList(); + } +} diff --git a/lib/src/box.dart b/lib/src/box.dart index e20f1587f..1fe3ef3df 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -1,10 +1,9 @@ import "dart:ffi"; -import "dart:typed_data" show Uint8List; -import "package:flat_buffers/flat_buffers.dart" as fb; import "store.dart"; import "bindings/bindings.dart"; import "bindings/constants.dart"; +import "bindings/flatbuffers.dart"; import "bindings/helpers.dart"; import "bindings/structs.dart"; @@ -14,134 +13,21 @@ enum PutMode { Update, } -class _OBXFBEntity { - _OBXFBEntity._(this._bc, this._bcOffset); - static const fb.Reader<_OBXFBEntity> reader = const _OBXFBEntityReader(); - factory _OBXFBEntity(Uint8List bytes) { - fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes); - return reader.read(rootRef, 0); - } - - final fb.BufferContext _bc; - final int _bcOffset; - - getProp(propReader, int field) => propReader.vTableGet(_bc, _bcOffset, field); -} - -class _OBXFBEntityReader extends fb.TableReader<_OBXFBEntity> { - const _OBXFBEntityReader(); - - @override - _OBXFBEntity createObject(fb.BufferContext bc, int offset) => new _OBXFBEntity._(bc, offset); -} - class Box { Store _store; Pointer _objectboxBox; - var _entityDefinition, _entityReader, _entityBuilder; + var _entityDefinition, _entityReader, _entityBuilder, _fbManager; Box(this._store) { _entityDefinition = _store.getEntityModelDefinitionFromClass(T); _entityReader = _store.getEntityReaderFromClass(); _entityBuilder = _store.getEntityBuilderFromClass(); + _fbManager = new OBXFlatbuffersManager(_entityDefinition, _entityReader, _entityBuilder); _objectboxBox = bindings.obx_box(_store.ptr, _entityDefinition["entity"]["id"]); checkObxPtr(_objectboxBox, "failed to create box"); } - ByteBuffer _marshal(propVals) { - var builder = new fb.Builder(initialSize: 1024); - - // write all strings - Map offsets = {}; - _entityDefinition["properties"].forEach((p) { - switch (p["type"]) { - case OBXPropertyType.String: - offsets[p["name"]] = builder.writeString(propVals[p["name"]]); - break; - } - }); - - // create table and write actual properties - // TODO: make sure that Id property has a value >= 1 - builder.startTable(); - _entityDefinition["properties"].forEach((p) { - var field = p["flatbuffers_id"], value = propVals[p["name"]]; - switch (p["type"]) { - case OBXPropertyType.Bool: - builder.addBool(field, value); - break; - case OBXPropertyType.Char: - builder.addInt8(field, value); - break; - case OBXPropertyType.Byte: - builder.addUint8(field, value); - break; - case OBXPropertyType.Short: - builder.addInt16(field, value); - break; - case OBXPropertyType.Int: - builder.addInt32(field, value); - break; - case OBXPropertyType.Long: - builder.addInt64(field, value); - break; - case OBXPropertyType.String: - builder.addOffset(field, offsets[p["name"]]); - break; - default: - throw Exception("unsupported type: ${p['type']}"); // TODO: support more types - } - }); - - var endOffset = builder.endTable(); - return ByteBuffer.allocate(builder.finish(endOffset)); - } - - T _unmarshal(ByteBuffer buffer) { - if (buffer.size == 0 || buffer.address == 0) return null; - Map propVals = {}; - var entity = new _OBXFBEntity(buffer.data); - - _entityDefinition["properties"].forEach((p) { - var propReader; - switch (p["type"]) { - case OBXPropertyType.Bool: - propReader = fb.BoolReader(); - break; - case OBXPropertyType.Char: - propReader = fb.Int8Reader(); - break; - case OBXPropertyType.Byte: - propReader = fb.Uint8Reader(); - break; - case OBXPropertyType.Short: - propReader = fb.Int16Reader(); - break; - case OBXPropertyType.Int: - propReader = fb.Int32Reader(); - break; - case OBXPropertyType.Long: - propReader = fb.Int64Reader(); - break; - case OBXPropertyType.String: - propReader = fb.StringReader(); - break; - default: - throw Exception("unsupported type: ${p['type']}"); // TODO: support more types - } - - propVals[p["name"]] = entity.getProp(propReader, (p["flatbuffers_id"] + 2) * 2); - }); - - return _entityBuilder(propVals); - } - - // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h) - List _unmarshalArray(Pointer bytesArray) { - return ByteBufferArray.fromOBXBytesArray(bytesArray).buffers.map((b) => _unmarshal(b)).toList(); - } - _getOBXPutMode(PutMode mode) { switch (mode) { case PutMode.Put: @@ -163,7 +49,7 @@ class Box { } // put object into box and free the buffer - ByteBuffer buffer = _marshal(propVals); + ByteBuffer buffer = _fbManager.marshal(propVals); checkObx( bindings.obx_box_put(_objectboxBox, propVals[idPropName], buffer.voidPtr, buffer.size, _getOBXPutMode(mode))); buffer.free(); @@ -197,7 +83,7 @@ class Box { for (int i = 0; i < allPropVals.length; ++i) allIdsMemory.elementAt(i).store(allPropVals[i][idPropName]); // marshal all objects to be put into the box - var putObjects = ByteBufferArray(allPropVals.map(_marshal).toList()).toOBXBytesArray(); + var putObjects = ByteBufferArray(allPropVals.map(_fbManager.marshal).toList()).toOBXBytesArray(); checkObx(bindings.obx_box_put_many(_objectboxBox, putObjects.ptr, allIdsMemory, _getOBXPutMode(mode))); putObjects.free(); @@ -234,7 +120,7 @@ class Box { dataPtr.free(); sizePtr.free(); - return _unmarshal(buffer); + return _fbManager.unmarshal(buffer); }); } @@ -243,7 +129,7 @@ class Box { // OBX_bytes_array*, has two Uint64 members (data and size) Pointer bytesArray = cCall(); try { - return _unmarshalArray(bytesArray); + return _fbManager.unmarshalArray(bytesArray); } finally { bindings.obx_bytes_array_free(bytesArray); } From a33faeb4f9cee087f310bf7cb5d370104c91618d Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:35:09 +0200 Subject: [PATCH 4/7] Remove Box.close --- lib/src/box.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/src/box.dart b/lib/src/box.dart index 1fe3ef3df..dd313a25b 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -156,12 +156,5 @@ class Box { () => checkObxPtr(bindings.obx_box_get_all(_objectboxBox), "failed to get all objects from box", true)); } - close() { - if (_store != null) { - _store.close(); - _store = null; - } - } - get ptr => _objectboxBox; } From 67b9edd590ff72b26761ca33496f001adfcb75bc Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:39:03 +0200 Subject: [PATCH 5/7] Move Common.lastErrorString to helpers.dart --- lib/src/bindings/helpers.dart | 17 ++++++++++++++--- lib/src/common.dart | 9 --------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/src/bindings/helpers.dart b/lib/src/bindings/helpers.dart index 11f83cd3d..18d27966e 100644 --- a/lib/src/bindings/helpers.dart +++ b/lib/src/bindings/helpers.dart @@ -1,13 +1,24 @@ import "dart:ffi"; +import "package:ffi/ffi.dart"; + +import "bindings.dart"; import "constants.dart"; import "../common.dart"; checkObx(errorCode) { - if (errorCode != OBXError.OBX_SUCCESS) throw ObjectBoxException(Common.lastErrorString(errorCode)); + if (errorCode != OBXError.OBX_SUCCESS) throw ObjectBoxException(lastObxErrorString(errorCode)); } checkObxPtr(Pointer ptr, String msg, [bool hasLastError = false]) { - if (ptr == null || ptr.address == 0) - throw ObjectBoxException("$msg: ${hasLastError ? Common.lastErrorString() : ""}"); + if (ptr == null || ptr.address == 0) throw ObjectBoxException("$msg: ${hasLastError ? lastObxErrorString() : ""}"); return ptr; } + +String lastObxErrorString([err]) { + if (err != null) return "code $err"; + + int last = bindings.obx_last_error_code(); + int last2 = bindings.obx_last_error_secondary(); + String desc = Utf8.fromUtf8(bindings.obx_last_error_message().cast()); + return "code $last, $last2 ($desc)"; +} diff --git a/lib/src/common.dart b/lib/src/common.dart index 121ddaf90..dd4010f55 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -19,15 +19,6 @@ class Common { static String versionString() { return Utf8.fromUtf8(bindings.obx_version_string().cast()); } - - static String lastErrorString([err]) { - if (err != null) return "code $err"; - - int last = bindings.obx_last_error_code(); - int last2 = bindings.obx_last_error_secondary(); - String desc = Utf8.fromUtf8(bindings.obx_last_error_message().cast()); - return "code $last, $last2 ($desc)"; - } } class ObjectBoxException { From 8095cc08ea4ee6efad5f0db8adfaf5b5784a693c Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:44:43 +0200 Subject: [PATCH 6/7] Remove generated flatbuffers_id property --- .../lib/src/generator.dart | 71 +++++++++---------- lib/src/bindings/flatbuffers.dart | 4 +- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/bin/objectbox_model_generator/lib/src/generator.dart b/bin/objectbox_model_generator/lib/src/generator.dart index 3a9d9c612..cc4018933 100644 --- a/bin/objectbox_model_generator/lib/src/generator.dart +++ b/bin/objectbox_model_generator/lib/src/generator.dart @@ -16,14 +16,14 @@ class EntityGenerator extends GeneratorForAnnotation { var entity = Entity(id: annotation.read('id').intValue, uid: annotation.read('uid').intValue); var element = elementBare as ClassElement; var ret = """ - const _${element.name}_OBXModel = { - "entity": { - "name": "${element.name}", - "id": ${entity.id}, - "uid": ${entity.uid} - }, - "properties": [ - """; + const _${element.name}_OBXModel = { + "entity": { + "name": "${element.name}", + "id": ${entity.id}, + "uid": ${entity.uid} + }, + "properties": [ + """; // read all suitable annotated properties var props = []; @@ -81,15 +81,14 @@ class EntityGenerator extends GeneratorForAnnotation { prop["type"] = fieldType; props.add(prop); ret += """ - { - "name": "${prop['name']}", - "id": ${prop['id']}, - "uid": ${prop['uid']}, - "type": ${prop['type']}, - "flags": ${prop['flags']}, - "flatbuffers_id": ${(prop['id'] as int) - 1}, - }, - """; + { + "name": "${prop['name']}", + "id": ${prop['id']}, + "uid": ${prop['uid']}, + "type": ${prop['type']}, + "flags": ${prop['flags']}, + }, + """; } // some checks on the entity's integrity @@ -98,28 +97,28 @@ class EntityGenerator extends GeneratorForAnnotation { // main code for instance builders and readers ret += """ - ], - "idPropertyName": "${idPropertyName}", - }; + ], + "idPropertyName": "${idPropertyName}", + }; - ${element.name} _${element.name}_OBXBuilder(Map members) { - ${element.name} r = new ${element.name}(); - ${props.map((p) => "r.${p['name']} = members[\"${p['name']}\"];").join()} - return r; - } + ${element.name} _${element.name}_OBXBuilder(Map members) { + ${element.name} r = new ${element.name}(); + ${props.map((p) => "r.${p['name']} = members[\"${p['name']}\"];").join()} + return r; + } - Map _${element.name}_OBXReader(${element.name} inst) { - Map r = {}; - ${props.map((p) => "r[\"${p['name']}\"] = inst.${p['name']};").join()} - return r; - } + Map _${element.name}_OBXReader(${element.name} inst) { + Map r = {}; + ${props.map((p) => "r[\"${p['name']}\"] = inst.${p['name']};").join()} + return r; + } - const ${element.name}_OBXDefs = { - "model": _${element.name}_OBXModel, - "builder": _${element.name}_OBXBuilder, - "reader": _${element.name}_OBXReader, - }; - """; + const ${element.name}_OBXDefs = { + "model": _${element.name}_OBXModel, + "builder": _${element.name}_OBXBuilder, + "reader": _${element.name}_OBXReader, + }; + """; return ret; } diff --git a/lib/src/bindings/flatbuffers.dart b/lib/src/bindings/flatbuffers.dart index cd1b6cde0..70ce6e694 100644 --- a/lib/src/bindings/flatbuffers.dart +++ b/lib/src/bindings/flatbuffers.dart @@ -48,7 +48,7 @@ class OBXFlatbuffersManager { // TODO: make sure that Id property has a value >= 1 builder.startTable(); _entityDefinition["properties"].forEach((p) { - var field = p["flatbuffers_id"], value = propVals[p["name"]]; + var field = p["id"] - 1, value = propVals[p["name"]]; switch (p["type"]) { case OBXPropertyType.Bool: builder.addBool(field, value); @@ -113,7 +113,7 @@ class OBXFlatbuffersManager { throw Exception("unsupported type: ${p['type']}"); // TODO: support more types } - propVals[p["name"]] = entity.getProp(propReader, (p["flatbuffers_id"] + 2) * 2); + propVals[p["name"]] = entity.getProp(propReader, (p["id"] + 1) * 2); }); return _entityBuilder(propVals); From 31166a94d7bcdc51516dec010ef4930df8619eae Mon Sep 17 00:00:00 2001 From: nalenz-objectbox <54843042+nalenz-objectbox@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:50:32 +0200 Subject: [PATCH 7/7] Add notice about code formatting to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 81bae2757..5414ce0e5 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ To try out the demo code in this repository, follow these steps: 3. Execute `pub run build_runner build`. This regenerates the ObjectBox model to make it usable in Dart (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 test/test.dart` to run the unit tests. +Contribution guide +------------------ +Please make sure that all code submitted via Pull Request needs to be formatted using `dartfmt -l 120`. You can configure your IDE to do this automatically, e.g. VS Code needs the project-specific settings `"editor.defaultFormatter": "Dart-Code.dart-code"` and `"dart.lineLength": 120`. + Dart integration ---------------- In general, Dart class annotations are used to mark classes as ObjectBox entities and provide meta information.