Skip to content

Commit f63daed

Browse files
Merge branch '139-add-externaltype-annotation-for-properties-and-standalone-tomany' into 'main'
Add @ExternalType and @ExternalName annotations #139 See merge request objectbox/objectbox-dart!102
2 parents 2f3ca9d + 2d34f9b commit f63daed

32 files changed

+915
-75
lines changed

dev-doc/updating-c-library.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,35 @@ for the binding update script (see below) and
1919
for Flutter (`flutter_libs` and `sync_flutter_libs` plugins) on Linux and Windows:
2020

2121
```bash
22-
./tool/set-c-version.sh 4.1.0
22+
./tool/set-c-version.sh 4.2.0
2323
```
2424

2525
```text
26-
* Flutter for Linux/Windows, Dart Native: update to [objectbox-c 4.1.0](https://github.com/objectbox/objectbox-c/releases/tag/v4.1.0).
26+
* Update ObjectBox database for Flutter Linux/Windows, Dart Native apps to [4.2.0](https://github.com/objectbox/objectbox-c/releases/tag/v4.2.0).
2727
```
2828

2929
```text
30-
Update C library [4.0.2 -> 4.1.0]
30+
Update C library [4.1.0 -> 4.2.0]
3131
```
3232

3333
### Android
3434

3535
For the Flutter plugins on Android ([view releases](https://github.com/objectbox/objectbox-java/releases)):
3636

3737
```bash
38-
./tool/set-android-version.sh 4.1.0
38+
./tool/set-android-version.sh 4.2.0
3939
```
4040

4141
```text
42-
* Flutter for Android: update to [objectbox-android 4.1.0](https://github.com/objectbox/objectbox-java/releases/tag/V4.1.0).
43-
If your project is [using Admin](https://docs.objectbox.io/data-browser#admin-for-android), make sure to
44-
update to `io.objectbox:objectbox-android-objectbrowser:4.1.0` in `android/app/build.gradle`.
42+
* Update ObjectBox database for Flutter Android apps to 4.2.0.
43+
If your project is [using Admin](https://docs.objectbox.io/data-browser#admin-for-android), make
44+
sure to update to `io.objectbox:objectbox-android-objectbrowser:4.2.0` in `android/app/build.gradle`.
4545
```
4646

4747
```text
48-
Update objectbox-android [4.0.3 -> 4.1.0]
48+
Update objectbox-android [4.1.0 -> 4.2.0]
4949
50-
Bundled with C API 4.1.0 and ObjectBox 4.1.0-2025-01-28
50+
Bundled with C API 4.2.0 and ObjectBox 4.2.0-2025-03-04
5151
```
5252

5353
Note: the embedded C API and ObjectBox version can be looked up
@@ -58,18 +58,18 @@ from the relevant objectbox repository release tag (like `java-4.1.0`).
5858
For the Flutter plugins on iOS/macOS ([view releases](https://github.com/objectbox/objectbox-swift/releases))
5959

6060
```bash
61-
./tool/set-swift-version.sh 4.1.0
61+
./tool/set-swift-version.sh 4.2.0
6262
```
6363

6464
```text
65-
* Flutter for iOS/macOS: update to [objectbox-swift 4.1.0](https://github.com/objectbox/objectbox-swift/releases/tag/v4.1.0).
65+
* Update ObjectBox database for Flutter iOS/macOS apps to 4.2.0.
6666
For existing projects, run `pod repo update` and `pod update ObjectBox` in the `ios` or `macos` directories.
6767
```
6868

6969
```text
70-
Update ObjectBox Swift [4.0.0 -> 4.0.1]
70+
Update ObjectBox Swift [4.1.0 -> 4.2.0]
7171
72-
Bundled with C API 4.1.0 and ObjectBox 4.1.0-2025-01-30
72+
Bundled with C API 4.2.0 and ObjectBox 4.2.0-2025-03-04
7373
```
7474

7575
Note: the embedded C API and ObjectBox version can be looked up
@@ -96,5 +96,5 @@ Then manually:
9696
- Commit as
9797

9898
```text
99-
Update C-API [4.0.2 -> 4.1.0]
99+
Update C-API [4.1.0 -> 4.2.0]
100100
```

flutter_libs/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ android {
5252
// ObjectBox Android library that includes an ObjectBox C library version compatible with
5353
// the C API binding of the ObjectBox Dart package.
5454
// https://central.sonatype.com/search?q=g:io.objectbox%20objectbox-android
55-
implementation "io.objectbox:objectbox-android:4.1.0"
55+
implementation "io.objectbox:objectbox-android:4.2.0"
5656
}
5757
}

flutter_libs/ios/objectbox_flutter_libs.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
1818
s.source_files = 'Classes/**/*'
1919

2020
s.dependency 'Flutter'
21-
s.dependency 'ObjectBox', '4.1.0'
21+
s.dependency 'ObjectBox', '4.2.0'
2222

2323
# Flutter.framework does not contain a i386 slice.
2424
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }

flutter_libs/linux/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
4444
# ----------------------------------------------------------------------
4545
# Download and add objectbox-c prebuilt library.
4646

47-
set(OBJECTBOX_VERSION 4.1.0)
47+
set(OBJECTBOX_VERSION 4.2.0)
4848

4949
set(OBJECTBOX_ARCH ${CMAKE_SYSTEM_PROCESSOR})
5050
if (${OBJECTBOX_ARCH} MATCHES "x86_64")

flutter_libs/macos/objectbox_flutter_libs.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
1818
s.source_files = 'Classes/**/*'
1919

2020
s.dependency 'FlutterMacOS'
21-
s.dependency 'ObjectBox', '4.1.0'
21+
s.dependency 'ObjectBox', '4.2.0'
2222

2323
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
2424
s.swift_version = '5.3'

flutter_libs/windows/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ set(objectbox_flutter_libs_bundled_libraries
5050
# ----------------------------------------------------------------------
5151
# Download and add objectbox-c prebuilt library.
5252

53-
set(OBJECTBOX_VERSION 4.1.0)
53+
set(OBJECTBOX_VERSION 4.2.0)
5454

5555
set(OBJECTBOX_ARCH ${CMAKE_SYSTEM_PROCESSOR})
5656
if (${OBJECTBOX_ARCH} MATCHES "AMD64")

generator/lib/src/code_builder.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import 'dart:async';
2-
import 'dart:io';
32
import 'dart:convert';
3+
import 'dart:io';
44

55
import 'package:build/build.dart';
66
import 'package:collection/collection.dart';
7+
import 'package:dart_style/dart_style.dart';
78
import 'package:glob/glob.dart';
9+
import 'package:objectbox/internal.dart';
810
import 'package:objectbox_generator/src/analysis/analysis.dart';
911
import 'package:objectbox_generator/src/builder_dirs.dart';
1012
import 'package:path/path.dart' as path;
11-
import 'package:objectbox/internal.dart';
12-
import 'package:dart_style/dart_style.dart';
13-
import 'package:source_gen/source_gen.dart';
1413
import 'package:pubspec_parse/pubspec_parse.dart';
14+
import 'package:source_gen/source_gen.dart';
1515

16+
import 'code_chunks.dart';
1617
import 'config.dart';
1718
import 'entity_resolver.dart';
18-
import 'code_chunks.dart';
1919

2020
/// CodeBuilder collects all '.objectbox.info' files created by EntityResolver and generates objectbox-model.json and
2121
/// objectbox_model.dart
@@ -213,6 +213,8 @@ class CodeBuilder extends Builder {
213213
propInModel.dartFieldType = prop.dartFieldType;
214214
propInModel.relationTarget = prop.relationTarget;
215215
propInModel.hnswParams = prop.hnswParams;
216+
propInModel.externalType = prop.externalType;
217+
propInModel.externalName = prop.externalName;
216218

217219
if (!prop.hasIndexFlag()) {
218220
propInModel.removeIndex();
@@ -242,6 +244,8 @@ class CodeBuilder extends Builder {
242244

243245
relInModel.name = rel.name;
244246
relInModel.targetName = rel.targetName;
247+
relInModel.externalType = rel.externalType;
248+
relInModel.externalName = rel.externalName;
245249
}
246250

247251
IdUid mergeEntity(ModelInfo modelInfo, ModelEntity entity) {
@@ -267,6 +271,7 @@ class CodeBuilder extends Builder {
267271

268272
entityInModel.name = entity.name;
269273
entityInModel.flags = entity.flags;
274+
entityInModel.externalName = entity.externalName;
270275
entityInModel.constructorParams = entity.constructorParams;
271276

272277
// here, the entity was found already and entityInModel and entity might differ, i.e. conflicts need to be resolved, so merge all properties first

generator/lib/src/code_chunks.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,16 @@ class CodeChunks {
122122
}
123123

124124
static String createModelEntity(ModelEntity entity) {
125+
var additionalArgs = '';
126+
if (entity.externalName != null) {
127+
additionalArgs += " externalName: '${entity.externalName}',";
128+
}
125129
return '''
126130
$obxInt.ModelEntity(
127131
id: ${createIdUid(entity.id)},
128132
name: '${entity.name}',
129133
lastPropertyId: ${createIdUid(entity.lastPropertyId)},
130-
flags: ${entity.flags},
134+
flags: ${entity.flags},$additionalArgs
131135
properties: <$obxInt.ModelProperty>[
132136
${entity.properties.map(createModelProperty).join(',')}
133137
],
@@ -154,6 +158,12 @@ class CodeChunks {
154158
additionalArgs +=
155159
", hnswParams: ${property.hnswParams!.toCodeString(obxInt)}";
156160
}
161+
if (property.externalType != null) {
162+
additionalArgs += ", externalType: ${property.externalType!}";
163+
}
164+
if (property.externalName != null) {
165+
additionalArgs += ", externalName: '${property.externalName!}'";
166+
}
157167
return '''
158168
$obxInt.ModelProperty(
159169
id: ${createIdUid(property.id)},
@@ -166,11 +176,19 @@ class CodeChunks {
166176
}
167177

168178
static String createModelRelation(ModelRelation relation) {
179+
var additionalArgs = '';
180+
if (relation.externalType != null) {
181+
additionalArgs += ", externalType: ${relation.externalType!}";
182+
}
183+
if (relation.externalName != null) {
184+
additionalArgs += ", externalName: '${relation.externalName!}'";
185+
}
169186
return '''
170187
$obxInt.ModelRelation(
171188
id: ${createIdUid(relation.id)},
172189
name: '${relation.name}',
173190
targetId: ${createIdUid(relation.targetId)}
191+
$additionalArgs
174192
)
175193
''';
176194
}

generator/lib/src/entity_resolver.dart

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class EntityResolver extends Builder {
2828
final _indexChecker = const TypeChecker.fromRuntime(Index);
2929
final _backlinkChecker = const TypeChecker.fromRuntime(Backlink);
3030
final _hnswChecker = const TypeChecker.fromRuntime(HnswIndex);
31+
final _externalTypeChecker = const TypeChecker.fromRuntime(ExternalType);
32+
final _externalNameChecker = const TypeChecker.fromRuntime(ExternalName);
3133

3234
@override
3335
FutureOr<void> build(BuildStep buildStep) async {
@@ -68,6 +70,11 @@ class EntityResolver extends Builder {
6870
null,
6971
uidRequest: !entityUid.isNull && entityUid.intValue == 0);
7072

73+
// @ExternalName
74+
_externalNameChecker.runIfMatches(classElement, (annotation) {
75+
entity.externalName = _readExternalNameParams(annotation);
76+
});
77+
7178
// Sync: check if enabled and options
7279
_syncChecker.runIfMatches(classElement, (annotation) {
7380
entity.flags |= OBXEntityFlags.SYNC_ENABLED;
@@ -171,6 +178,7 @@ class EntityResolver extends Builder {
171178
final backlinkAnnotations =
172179
_backlinkChecker.annotationsOfExact(annotated);
173180
if (backlinkAnnotations.isNotEmpty) {
181+
// Handles ToMany based on other ToOne or ToMany relation (backlink)
174182
if (!isToManyRel) {
175183
log.severe(
176184
" Skipping property '${f.name}': @Backlink() may only be used with ToMany.");
@@ -183,14 +191,33 @@ class EntityResolver extends Builder {
183191
entity.backlinks.add(backlink);
184192
log.info(' $backlink');
185193
} else if (isToManyRel) {
194+
// Handles standalone (non backlink) ToMany relation
195+
196+
// @ExternalType
197+
int? externalType;
198+
_externalTypeChecker.runIfMatches(annotated, (annotation) {
199+
final externalTypeId = _readExternalTypeParams(annotation);
200+
externalType = externalTypeId;
201+
});
202+
203+
// @ExternalName
204+
String? externalName;
205+
_externalNameChecker.runIfMatches(annotated, (annotation) {
206+
externalName = _readExternalNameParams(annotation);
207+
});
208+
186209
// create relation
187210
final rel = ModelRelation.create(IdUid(0, propUid ?? 0), f.name,
188211
targetName: relTargetName,
189-
uidRequest: propUid != null && propUid == 0);
212+
uidRequest: propUid != null && propUid == 0,
213+
externalName: externalName,
214+
externalType: externalType);
215+
190216
entity.relations.add(rel);
191217

192218
log.info(' $rel');
193219
} else {
220+
// Handles regular properties
194221
// create property (do not use readEntity.createProperty in order to avoid generating new ids)
195222
final prop = ModelProperty.create(
196223
IdUid(0, propUid ?? 0), f.name, fieldType,
@@ -226,6 +253,17 @@ class EntityResolver extends Builder {
226253
_readHnswIndexParams(annotation, prop);
227254
});
228255

256+
// @ExternalType
257+
_externalTypeChecker.runIfMatches(annotated, (annotation) {
258+
final externalTypeId = _readExternalTypeParams(annotation);
259+
prop.externalType = externalTypeId;
260+
});
261+
262+
// @ExternalName
263+
_externalNameChecker.runIfMatches(annotated, (annotation) {
264+
prop.externalName = _readExternalNameParams(annotation);
265+
});
266+
229267
// for code generation
230268
prop.dartFieldType =
231269
f.type.element!.name! + (isNullable(f.type) ? '?' : '');
@@ -555,6 +593,27 @@ class EntityResolver extends Builder {
555593
annotation.getField('vectorCacheHintSizeKB')!.toIntValue());
556594
property.hnswParams = ModelHnswParams.fromAnnotation(hnswRestored);
557595
}
596+
597+
int _readExternalTypeParams(DartObject annotation) {
598+
final typeIndex =
599+
_enumValueIndex(annotation.getField('type')!, "ExternalType.type");
600+
final type =
601+
typeIndex != null ? ExternalPropertyType.values[typeIndex] : null;
602+
if (type == null) {
603+
throw InvalidGenerationSourceError(
604+
"'type' attribute not specified in @ExternalType annotation");
605+
}
606+
return externalTypeToOBXExternalType(type);
607+
}
608+
609+
String _readExternalNameParams(DartObject annotation) {
610+
final name = annotation.getField('name')!.toStringValue();
611+
if (name == null) {
612+
throw InvalidGenerationSourceError(
613+
"'name' attribute not specified in @ExternalName annotation");
614+
}
615+
return name;
616+
}
558617
}
559618

560619
extension _TypeCheckerExtensions on TypeChecker {

0 commit comments

Comments
 (0)