Skip to content

Commit aa36d8f

Browse files
committed
Merge branch '5-flex-map'
2 parents 5b6ce1f + bbba77c commit aa36d8f

File tree

27 files changed

+1246
-50
lines changed

27 files changed

+1246
-50
lines changed

.github/workflows/code-analysis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ permissions:
1515
env:
1616
# Do code analysis with latest SDK.
1717
# Pick a concrete version instead of "latest" to avoid builds breaking due to changes in new SDKs.
18-
FLUTTER_VERSION: 3.35.2 # Available versions: https://docs.flutter.dev/release/archive
19-
DART_VERSION: 3.9.2 # Available versions: https://dart.dev/get-dart/archive
18+
FLUTTER_VERSION: 3.38.5 # Available versions: https://docs.flutter.dev/release/archive
19+
DART_VERSION: 3.10.4 # Available versions: https://dart.dev/get-dart/archive
2020

2121
jobs:
2222
format-and-analyze:

.github/workflows/test.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ env:
2020
# Run generator integration tests and init script with latest SDK.
2121
# Pick a concrete version instead of "latest" to avoid builds breaking due to changes in new SDKs.
2222
# NOTE: also update matrix configurations below!
23-
FLUTTER_VERSION: 3.35.2 # Available versions: https://docs.flutter.dev/release/archive
24-
DART_VERSION: 3.9.2 # Available versions: https://dart.dev/get-dart/archive
23+
FLUTTER_VERSION: 3.38.5 # Available versions: https://docs.flutter.dev/release/archive
24+
DART_VERSION: 3.10.4 # Available versions: https://dart.dev/get-dart/archive
2525

2626
jobs:
2727

@@ -67,7 +67,7 @@ jobs:
6767
# Pick a concrete version instead of "latest" to avoid builds breaking due to changes in new SDKs.
6868
# Can not use env variables here, only within 'steps'.
6969
# For available versions see https://dart.dev/get-dart/archive
70-
- 3.9.2
70+
- 3.10.4
7171
- 3.7.2 # Use latest bugfix release to get tooling fixes
7272
runs-on: ${{ matrix.os }}
7373
steps:
@@ -112,14 +112,14 @@ jobs:
112112
# Can not use env variables here, only within 'steps'.
113113
# For available versions see https://docs.flutter.dev/release/archive
114114
# NOTE Also update versions for Ubuntu below!
115-
- 3.35.2
115+
- 3.38.5
116116
- 3.29.3 # Use latest bugfix release to get tooling fixes
117117
include:
118118
# Test building for Android with highest supported JDK on latest Flutter SDK,
119119
# lowest supported JDK on lowest supported Flutter SDK. (Android is only built if a Linux
120120
# OS is detected, see integration-test.sh)
121121
- os: ubuntu-24.04
122-
flutter-version: 3.35.2
122+
flutter-version: 3.38.5
123123
jdk: 21
124124
- os: ubuntu-24.04
125125
flutter-version: 3.29.3 # Use latest bugfix release to get tooling fixes

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ objectbox.lib
2323

2424
# backup created by publish.sh - ignore to avoid publishing
2525
**/pubspec.yaml.original
26+
27+
# ObjectBox database files
28+
data.mdb
29+
lock.mdb

.gitlab-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ variables:
88
# # Pick a concrete version instead of "latest" to avoid builds breaking due to changes in new
99
# SDKs.
1010
# For available versions see https://hub.docker.com/_/dart/tags and https://dart.dev/get-dart/archive
11-
DART_VERSION_LATEST: '3.9.2'
12-
DART_VERSION_LOWEST: '3.7.2' # Use latest bugfix release to get tooling fixes
11+
DART_VERSION_LATEST: '3.10.4'
12+
DART_VERSION_LOWEST: '3.7.3' # Use latest bugfix release to get tooling fixes
1313
DART_VERSION: $DART_VERSION_LATEST # Also used for caching, see .cache template
1414

1515
.common:

CONTRIBUTING.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,47 @@ ObjectBox offers a [C API](https://github.com/objectbox/objectbox-c) which can b
2222
The C API is also used by the ObjectBox language bindings for [Go](https://github.com/objectbox/objectbox-go), [Swift](https://github.com/objectbox/objectbox-swift), and [Python](https://github.com/objectbox/objectbox-python).
2323
These languages may serve as an inspiration for this Dart implementation.
2424
Internally, ObjectBox uses [FlatBuffers](https://google.github.io/flatbuffers/) to store objects.
25+
26+
## Code organization
27+
28+
This is a multi-package Dart/Flutter repository.
29+
The core runtime library (`objectbox/`) provides the database API via Dart FFI bindings to the ObjectBox C library.
30+
Code generation (`generator/`) uses `build_runner` to produce entity bindings at compile time.
31+
Flutter apps include native libraries via platform-specific plugin packages (`flutter_libs/`, `sync_flutter_libs/`).
32+
33+
- **`objectbox/`** – Core runtime package published as `objectbox` on pub.dev.
34+
- `lib/objectbox.dart` – Public API exports (Store, Box, Query, annotations, Sync, etc.).
35+
- `lib/src/native/` – FFI bindings and native implementations (Store, Box, Query, Sync).
36+
- `lib/src/native/bindings/` – Auto-generated C bindings via `ffigen` and ObjectBox C headers.
37+
- `lib/src/modelinfo/` – Model metadata classes used by the generator and runtime.
38+
- `lib/src/relations/` – ToOne/ToMany relation implementations.
39+
- `lib/src/annotations.dart` – Entity/property annotations (`@Entity`, `@Id`, `@Property`, etc.).
40+
- `example/` – Example Dart/Flutter apps demonstrating usage.
41+
42+
- **`generator/`** – Code generator package published as `objectbox_generator`.
43+
- `lib/src/entity_resolver.dart` – Parses annotated entity classes using the Dart analyzer.
44+
- `lib/src/code_builder.dart` – Orchestrates code generation via `build_runner`.
45+
- `lib/src/code_chunks.dart` – Generates `objectbox.g.dart` and `objectbox-model.json`.
46+
- `integration-tests/` – End-to-end generator tests with sample entity definitions.
47+
48+
- **`flutter_libs/`** – Flutter plugin package (`objectbox_flutter_libs`) bundling native ObjectBox libraries for Android, iOS, Linux, macOS, and Windows.
49+
50+
- **`sync_flutter_libs/`** – Flutter plugin package (`objectbox_sync_flutter_libs`) bundling native libraries with ObjectBox Sync support.
51+
52+
- **`objectbox_test/`** – Internal test package (not published).
53+
Contains comprehensive tests for the runtime: Box, Query, relations, Sync, observers, isolates, etc.
54+
Uses `dependency_overrides` to test against local `objectbox/` and `generator/`.
55+
56+
- **`benchmark/`** – Performance benchmarks comparing ObjectBox operations.
57+
58+
- **`tool/`** – Shell scripts for development and release workflows:
59+
- Version management (`set-version.sh`, `set-c-version.sh`).
60+
- C library updates (`update-c-binding.sh`).
61+
- Publishing (`publish.sh`, `pub.sh`).
62+
63+
- **`dev-doc/`** – Internal developer documentation: updating the C library, adding property types, packaging, updating examples.
64+
65+
- **`.github/`** – GitHub Actions workflows and issue templates.
66+
67+
- **`.gitlab-ci.yml`** – GitLab CI pipeline configuration.
68+

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ and servers, both online and offline.
8484
🪂 **ACID compliant** - Atomic, Consistent, Isolated, Durable.\
8585
💻 **Multiplatform** - Android, iOS, macOS, Linux, Windows, any POSIX-system.\
8686
🌱 **Scalable** - grows with your app, handling millions of objects with ease.\
87-
💚 **Sustainable** - frugal on CPU, Memory and battery / power use, reducing CO2 emmissions.
87+
💚 **Sustainable** - frugal on CPU, Memory and battery / power use, reducing CO2 emissions.
8888

8989
🔗 **[Relations](https://docs.objectbox.io/relations)** - object links / relationships are built-in.\
9090
💐 **[Queries](https://docs.objectbox.io/queries)** - filter data as needed, even across relations.\
@@ -107,7 +107,9 @@ Continue with our ➡️ **[Getting Started guide](https://docs.objectbox.io/get
107107

108108
### Flutter Database Performance Benchmarks
109109

110-
We tested across the four main database operations, CRUD (create, read, update, delete). Each test was run multiple times and executed manually outside of the measured time. Data preparation and evaluation were done outside of the measured time.
110+
We tested across the four main database operations, CRUD (create, read, update, delete).
111+
Each test was run multiple times and executed manually.
112+
Data preparation and evaluation were done outside the measured time.
111113

112114
Here are the benchmarks for ObjectBox vs sqflite vs Hive (last updated 2021-09-11) 👇
113115

@@ -131,7 +133,7 @@ For general news on ObjectBox, [check our blog](https://objectbox.io/blog)!
131133

132134
## Contributing
133135

134-
Do you want to check out the ObjectBox code itself? E.g. see in action, run tests, or even contribute code?
136+
Do you want to check out the ObjectBox code itself? E.g. see it in action, run tests, or even contribute code?
135137
Great! Clone/check out this repository and run this to generate code and get you started quickly:
136138

137139
```bash
@@ -154,6 +156,8 @@ This repository holds all ObjectBox Dart/Flutter packages as separate directorie
154156
There's also a separate repository benchmarking objectbox (and other databases) in Flutter:
155157
[objectbox-dart-performance](https://github.com/objectbox/objectbox-dart-performance).
156158

159+
See [CONTRIBUTING.md](CONTRIBUTING.md) for a more detailed overview.
160+
157161
## Other languages/bindings
158162

159163
ObjectBox supports multiple platforms and languages:
@@ -166,7 +170,7 @@ ObjectBox supports multiple platforms and languages:
166170
## License
167171

168172
```text
169-
Copyright © 2019 ObjectBox Ltd. <https://objectbox.io/>
173+
Copyright © 2019-2025 ObjectBox Ltd. <https://objectbox.io/>
170174
171175
Licensed under the Apache License, Version 2.0 (the "License");
172176
you may not use this file except in compliance with the License.

flutter_libs/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Superfast NoSQL Flutter / Dart database. This package contains Flut
33
# Link to actual directory in repository so file links on pub.dev work.
44
repository: https://github.com/objectbox/objectbox-dart/tree/main/flutter_libs
55
homepage: https://objectbox.io
6-
version: 5.0.4
6+
version: 5.1.0-dev.0
77

88
environment:
99
sdk: ^3.7.0
@@ -14,7 +14,7 @@ dependencies:
1414
sdk: flutter
1515
# This is here just to ensure compatibility between objectbox-dart code and the libraries used
1616
# You should still depend on objectbox directly in your Flutter application.
17-
objectbox: 5.0.4
17+
objectbox: 5.1.0-dev.0
1818
path_provider: ^2.0.0
1919

2020
dev_dependencies:

generator/lib/src/code_chunks.dart

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,8 @@ class CodeChunks {
324324
offsets[p.id.id] = offsetVar; // see default case in the switch
325325

326326
var assignment = 'final $offsetVar = ';
327-
if (p.fieldIsNullable) {
327+
// Note: dynamic is always nullable (currently only used for Flex properties)
328+
if (p.fieldIsNullable || p.fieldType == 'dynamic') {
328329
assignment += '$fieldName == null ? null : ';
329330
fieldName += '!';
330331
}
@@ -346,6 +347,9 @@ class CodeChunks {
346347
return '$assignment fbb.writeListFloat32($fieldName);';
347348
case OBXPropertyType.DoubleVector:
348349
return '$assignment fbb.writeListFloat64($fieldName);';
350+
case OBXPropertyType.Flex:
351+
// Use toFlexBuffer() to serialize Map, List, or value types
352+
return '$assignment fbb.writeListInt8($obxInt.toFlexBuffer($fieldName));';
349353
default:
350354
offsets.remove(p.id.id);
351355
return null;
@@ -445,6 +449,26 @@ class CodeChunks {
445449
);
446450
}
447451

452+
/// Extracts the key and value types by removing "Map<" prefix and ">" suffix.
453+
static String _getMapKeyValueTypes(String typeString) {
454+
// This String operation is very fragile and should be replaced with info
455+
// from ModelProperty created by EntityResolver.
456+
return typeString.substring(
457+
4, // "Map<"
458+
typeString.length - 1, // ">"
459+
);
460+
}
461+
462+
/// Extracts the element type by removing "List<" prefix and ">" suffix.
463+
static String _getListElementType(String typeString) {
464+
// This String operation is very fragile and should be replaced with info
465+
// from ModelProperty created by EntityResolver.
466+
return typeString.substring(
467+
5, // "List<"
468+
typeString.length - 1, // ">"
469+
);
470+
}
471+
448472
static String objectFromFB(ModelEntity entity) {
449473
// collect code for the template at the end of this function
450474
final constructorLines = <String>[]; // used as constructor arguments
@@ -561,6 +585,78 @@ class CodeChunks {
561585
p,
562586
'fb.ListReader<String>(fb.StringReader(asciiOptimization: true), lazy: false)',
563587
);
588+
case OBXPropertyType.Flex:
589+
// Read as Uint8List and convert to Map, List, or value
590+
final offset = propertyFlatBuffersvTableOffset(p);
591+
// Use appropriate deserializer based on field type
592+
final isMap = p.fieldType.startsWith('Map');
593+
// dynamic is always nullable; Object requires nullable annotation
594+
final isValue =
595+
p.fieldType == 'dynamic' ||
596+
(p.fieldType == 'Object' && p.fieldIsNullable);
597+
// For List<Map<...>> types, use dedicated helper
598+
final isListOfMaps = p.fieldType.startsWith('List<Map');
599+
// Check if list needs casting (List<Object> or List<Object?>)
600+
final isListOfObject = p.fieldType.startsWith('List<Object');
601+
final String flexDeserializer;
602+
final bool skipNull;
603+
final String? defaultValue;
604+
final String castSuffix;
605+
if (isValue) {
606+
// dynamic or Object? - can be any FlexBuffer value
607+
flexDeserializer = 'fromFlexBuffer';
608+
skipNull = false;
609+
defaultValue = null; // nullable only, no default needed
610+
castSuffix = '';
611+
} else if (isMap) {
612+
flexDeserializer = 'flexBufferToMap';
613+
final keyValueTypes = _getMapKeyValueTypes(p.fieldType);
614+
final hasDynamicValueType = keyValueTypes.endsWith('dynamic');
615+
// For maps with non-null values skip nulls (so not
616+
// Map<String, dynamic> or Map<String, Object/List/Map?>).
617+
skipNull = !hasDynamicValueType && !keyValueTypes.endsWith('?');
618+
defaultValue = '<$keyValueTypes>{}';
619+
// Cast to the correct Map type if not Map<String, dynamic>
620+
if (hasDynamicValueType) {
621+
castSuffix = '';
622+
} else {
623+
castSuffix = '?.cast<$keyValueTypes>()';
624+
}
625+
} else if (isListOfMaps) {
626+
flexDeserializer = 'flexBufferToListOfMaps';
627+
final elementType = _getListElementType(p.fieldType);
628+
// The deserializer already skips nulls
629+
skipNull = false;
630+
defaultValue = '<$elementType>[]';
631+
// Cast needed for Map<String, Object?> and Map<String, Object>
632+
if (elementType == 'Map<String, dynamic>') {
633+
castSuffix = '';
634+
} else {
635+
castSuffix = '?.cast<$elementType>()';
636+
}
637+
} else if (isListOfObject) {
638+
flexDeserializer = 'flexBufferToList';
639+
final elementType = _getListElementType(p.fieldType);
640+
// For lists with non-null elements skip nulls
641+
skipNull = !elementType.endsWith('?');
642+
defaultValue = '<$elementType>[]';
643+
castSuffix = '?.cast<$elementType>()';
644+
} else {
645+
// List<dynamic>
646+
flexDeserializer = 'flexBufferToList';
647+
skipNull = false;
648+
defaultValue = '<dynamic>[]';
649+
castSuffix = '';
650+
}
651+
final skipNullArg = skipNull ? ', skipNull: true' : '';
652+
final deserializeExpr =
653+
'$obxInt.$flexDeserializer(buffer, rootOffset, $offset$skipNullArg)$castSuffix';
654+
if (p.fieldIsNullable || defaultValue == null) {
655+
// Nullable field or value type (dynamic/Object?) - no default
656+
return deserializeExpr;
657+
} else {
658+
return '$deserializeExpr ?? $defaultValue';
659+
}
564660
default:
565661
return readFieldCodeString(
566662
p,
@@ -778,6 +874,9 @@ class CodeChunks {
778874
case OBXPropertyType.StringVector:
779875
fieldType = 'StringVector';
780876
break;
877+
case OBXPropertyType.Flex:
878+
// Flex properties don't have query support yet, skip generating query property
879+
continue;
781880
default:
782881
throw InvalidGenerationSourceError(
783882
'Unsupported property type (${prop.type}): ${entity.name}.$name',

0 commit comments

Comments
 (0)