@@ -2,6 +2,7 @@ import 'dart:async';
22import 'dart:convert' ;
33
44import 'package:analyzer/dart/element/element.dart' ;
5+ import 'package:analyzer/dart/element/type.dart' ;
56import 'package:build/build.dart' ;
67import 'package:objectbox/objectbox.dart' as obx;
78import 'package:objectbox/src/bindings/bindings.dart' ;
@@ -22,6 +23,8 @@ class EntityResolver extends Builder {
2223 final _idChecker = const TypeChecker .fromRuntime (obx.Id );
2324 final _transientChecker = const TypeChecker .fromRuntime (obx.Transient );
2425 final _syncChecker = const TypeChecker .fromRuntime (obx.Sync );
26+ final _uniqueChecker = const TypeChecker .fromRuntime (obx.Unique );
27+ final _indexChecker = const TypeChecker .fromRuntime (obx.Index );
2528
2629 @override
2730 FutureOr <void > build (BuildStep buildStep) async {
@@ -140,13 +143,18 @@ class EntityResolver extends Builder {
140143 }
141144
142145 // create property (do not use readEntity.createProperty in order to avoid generating new ids)
143- final prop =
144- ModelProperty (IdUid .empty (), f.name, fieldType, flags, entity);
146+ final prop = ModelProperty (IdUid .empty (), f.name, fieldType,
147+ flags: flags, entity: entity);
148+
149+ // Index and unique annotation.
150+ final indexTypeStr =
151+ processAnnotationIndexUnique (f, fieldType, elementBare, prop);
152+
145153 if (propUid != null ) prop.id.uid = propUid;
146154 entity.properties.add (prop);
147155
148156 log.info (
149- ' property ${prop .name }(${prop .id }) type:${prop .type } flags:${prop .flags }' );
157+ ' property ${prop .name }(${prop .id }) type:${prop .type } flags:${prop .flags } ${ prop . hasIndexFlag () ? "index:${ indexTypeStr }" : "" } ' );
150158 }
151159
152160 // some checks on the entity's integrity
@@ -157,4 +165,84 @@ class EntityResolver extends Builder {
157165
158166 return entity;
159167 }
168+
169+ String processAnnotationIndexUnique (FieldElement f, int fieldType,
170+ Element elementBare, obx.ModelProperty prop) {
171+ obx.IndexType indexType;
172+
173+ final indexAnnotation = _indexChecker.firstAnnotationOfExact (f);
174+ final hasUniqueAnnotation = _uniqueChecker.hasAnnotationOfExact (f);
175+ if (indexAnnotation == null && ! hasUniqueAnnotation) return null ;
176+
177+ // Throw if property type does not support any index.
178+ if (fieldType == OBXPropertyType .Float ||
179+ fieldType == OBXPropertyType .Double ||
180+ fieldType == OBXPropertyType .ByteVector ) {
181+ throw InvalidGenerationSourceError (
182+ "in target ${elementBare .name }: @Index/@Unique is not supported for type '${f .type .toString ()}' of field '${f .name }'" );
183+ }
184+
185+ if (prop.hasFlag (OBXPropertyFlags .ID )) {
186+ throw InvalidGenerationSourceError (
187+ 'in target ${elementBare .name }: @Index/@Unique is not supported for ID field ${f .name }. IDs are unique by definition and automatically indexed' );
188+ }
189+
190+ // If available use index type from annotation.
191+ if (indexAnnotation != null && ! indexAnnotation.isNull) {
192+ // find out @Index(type:) value - its an enum IndexType
193+ final indexTypeField = indexAnnotation.getField ('type' );
194+ if (! indexTypeField.isNull) {
195+ final indexTypeEnumValues = (indexTypeField.type as InterfaceType )
196+ .element
197+ .fields
198+ .where ((f) => f.isEnumConstant)
199+ .toList ();
200+
201+ // Find the index of the matching enum constant.
202+ for (var i = 0 ; i < indexTypeEnumValues.length; i++ ) {
203+ if (indexTypeEnumValues[i].computeConstantValue () == indexTypeField) {
204+ indexType = obx.IndexType .values[i];
205+ break ;
206+ }
207+ }
208+ }
209+ }
210+
211+ // Fall back to index type based on property type.
212+ final supportsHashIndex = fieldType == OBXPropertyType .String ;
213+ if (indexType == null ) {
214+ if (supportsHashIndex) {
215+ indexType = obx.IndexType .hash;
216+ } else {
217+ indexType = obx.IndexType .value;
218+ }
219+ }
220+
221+ // Throw if HASH or HASH64 is not supported by property type.
222+ if (! supportsHashIndex &&
223+ (indexType == obx.IndexType .hash ||
224+ indexType == obx.IndexType .hash64)) {
225+ throw InvalidGenerationSourceError (
226+ "in target ${elementBare .name }: a hash index is not supported for type '${f .type .toString ()}' of field '${f .name }'" );
227+ }
228+
229+ if (hasUniqueAnnotation) {
230+ prop.flags | = OBXPropertyFlags .UNIQUE ;
231+ }
232+
233+ switch (indexType) {
234+ case obx.IndexType .value:
235+ prop.flags | = OBXPropertyFlags .INDEXED ;
236+ return 'value' ;
237+ case obx.IndexType .hash:
238+ prop.flags | = OBXPropertyFlags .INDEX_HASH ;
239+ return 'hash' ;
240+ case obx.IndexType .hash64:
241+ prop.flags | = OBXPropertyFlags .INDEX_HASH64 ;
242+ return 'hash64' ;
243+ default :
244+ throw InvalidGenerationSourceError (
245+ 'in target ${elementBare .name }: invalid index type: $indexType ' );
246+ }
247+ }
160248}
0 commit comments