Skip to content

Commit 36577a4

Browse files
Merge branch '130-flex-queries' into dev
2 parents bccfa0f + 8502aeb commit 36577a4

File tree

10 files changed

+239
-29
lines changed

10 files changed

+239
-29
lines changed

objectbox-java/src/main/java/io/objectbox/Property.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.objectbox.query.PropertyQueryConditionImpl.StringArrayCondition;
3232
import io.objectbox.query.PropertyQueryConditionImpl.StringCondition;
3333
import io.objectbox.query.PropertyQueryConditionImpl.StringCondition.Operation;
34+
import io.objectbox.query.PropertyQueryConditionImpl.StringStringCondition;
3435
import io.objectbox.query.QueryBuilder.StringOrder;
3536

3637
import javax.annotation.Nullable;
@@ -442,25 +443,36 @@ private void checkNotStringArray() {
442443
}
443444

444445
/**
445-
* For a String array property, matches if at least one element equals the given value
446+
* For a String array or String-key map property, matches if at least one element equals the given value
446447
* using {@link StringOrder#CASE_SENSITIVE StringOrder#CASE_SENSITIVE}.
447448
*
448449
* @see #containsElement(String, StringOrder)
449450
*/
450451
public PropertyQueryCondition<ENTITY> containsElement(String value) {
451-
checkIsStringArray();
452452
return new StringCondition<>(this, Operation.CONTAINS_ELEMENT, value);
453453
}
454454

455455
public PropertyQueryCondition<ENTITY> containsElement(String value, StringOrder order) {
456-
checkIsStringArray();
457456
return new StringCondition<>(this, Operation.CONTAINS_ELEMENT, value, order);
458457
}
459458

460-
private void checkIsStringArray() {
461-
if (String[].class != type) {
462-
throw new IllegalArgumentException("containsElement is only supported for String[] properties.");
463-
}
459+
/**
460+
* For a String-key map property, matches if at least one key and value combination equals the given values
461+
* using {@link StringOrder#CASE_SENSITIVE StringOrder#CASE_SENSITIVE}.
462+
*
463+
* @see #containsKeyValue(String, String, StringOrder)
464+
*/
465+
public PropertyQueryCondition<ENTITY> containsKeyValue(String key, String value) {
466+
return new StringStringCondition<>(this, StringStringCondition.Operation.CONTAINS_KEY_VALUE,
467+
key, value, StringOrder.CASE_SENSITIVE);
468+
}
469+
470+
/**
471+
* @see #containsKeyValue(String, String)
472+
*/
473+
public PropertyQueryCondition<ENTITY> containsKeyValue(String key, String value, StringOrder order) {
474+
return new StringStringCondition<>(this, StringStringCondition.Operation.CONTAINS_KEY_VALUE,
475+
key, value, order);
464476
}
465477

466478
/**

objectbox-java/src/main/java/io/objectbox/query/PropertyQueryConditionImpl.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,34 @@ void applyCondition(QueryBuilder<T> builder) {
343343
}
344344
}
345345

346+
public static class StringStringCondition<T> extends PropertyQueryConditionImpl<T> {
347+
private final Operation op;
348+
private final String leftValue;
349+
private final String rightValue;
350+
private final StringOrder order;
351+
352+
public enum Operation {
353+
CONTAINS_KEY_VALUE
354+
}
355+
356+
public StringStringCondition(Property<T> property, Operation op, String leftValue, String rightValue, StringOrder order) {
357+
super(property);
358+
this.op = op;
359+
this.leftValue = leftValue;
360+
this.rightValue = rightValue;
361+
this.order = order;
362+
}
363+
364+
@Override
365+
void applyCondition(QueryBuilder<T> builder) {
366+
if (op == Operation.CONTAINS_KEY_VALUE) {
367+
builder.containsKeyValue(property, leftValue, rightValue, order);
368+
} else {
369+
throw new UnsupportedOperationException(op + " is not supported with two String values");
370+
}
371+
}
372+
}
373+
346374
public static class StringArrayCondition<T> extends PropertyQueryConditionImpl<T> {
347375
private final Operation op;
348376
private final String[] value;

objectbox-java/src/main/java/io/objectbox/query/Query.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ public class Query<T> implements Closeable {
7474
native void nativeSetParameter(long handle, int entityId, int propertyId, @Nullable String parameterAlias,
7575
String value);
7676

77+
private native void nativeSetParameters(long handle, int entityId, int propertyId, @Nullable String parameterAlias,
78+
String value, String value2);
79+
7780
native void nativeSetParameter(long handle, int entityId, int propertyId, @Nullable String parameterAlias,
7881
long value);
7982

@@ -564,6 +567,24 @@ public Query<T> setParameters(String alias, String[] values) {
564567
return this;
565568
}
566569

570+
/**
571+
* Sets a parameter previously given to the {@link QueryBuilder} to new values.
572+
*/
573+
public Query<T> setParameters(Property<?> property, String key, String value) {
574+
nativeSetParameters(handle, property.getEntityId(), property.getId(), null, key, value);
575+
return this;
576+
}
577+
578+
/**
579+
* Sets a parameter previously given to the {@link QueryBuilder} to new values.
580+
*
581+
* @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
582+
*/
583+
public Query<T> setParameters(String alias, String key, String value) {
584+
nativeSetParameters(handle, 0, 0, alias, key, value);
585+
return this;
586+
}
587+
567588
/**
568589
* Sets a parameter previously given to the {@link QueryBuilder} to new values.
569590
*/

objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ private native long nativeLink(long handle, long storeHandle, int relationOwnerE
184184

185185
private native long nativeContainsElement(long handle, int propertyId, String value, boolean caseSensitive);
186186

187+
private native long nativeContainsKeyValue(long handle, int propertyId, String key, String value, boolean caseSensitive);
188+
187189
private native long nativeStartsWith(long handle, int propertyId, String value, boolean caseSensitive);
188190

189191
private native long nativeEndsWith(long handle, int propertyId, String value, boolean caseSensitive);
@@ -769,17 +771,23 @@ public QueryBuilder<T> contains(Property<T> property, String value, StringOrder
769771
}
770772

771773
/**
772-
* For a String array property, matches if at least one element equals the given value.
774+
* For a String array or String-key map property, matches if at least one element equals the given value.
773775
*/
774776
public QueryBuilder<T> containsElement(Property<T> property, String value, StringOrder order) {
775-
if (String[].class != property.type) {
776-
throw new IllegalArgumentException("containsElement is only supported for String[] properties.");
777-
}
778777
verifyHandle();
779778
checkCombineCondition(nativeContainsElement(handle, property.getId(), value, order == StringOrder.CASE_SENSITIVE));
780779
return this;
781780
}
782781

782+
/**
783+
* For a String-key map property, matches if at least one key and value combination equals the given values.
784+
*/
785+
public QueryBuilder<T> containsKeyValue(Property<T> property, String key, String value, StringOrder order) {
786+
verifyHandle();
787+
checkCombineCondition(nativeContainsKeyValue(handle, property.getId(), key, value, order == StringOrder.CASE_SENSITIVE));
788+
return this;
789+
}
790+
783791
public QueryBuilder<T> startsWith(Property<T> property, String value, StringOrder order) {
784792
verifyHandle();
785793
checkCombineCondition(nativeStartsWith(handle, property.getId(), value, order == StringOrder.CASE_SENSITIVE));

tests/objectbox-java-test/src/main/java/io/objectbox/TestEntity.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package io.objectbox;
1818

19+
import javax.annotation.Nullable;
1920
import java.util.Arrays;
2021
import java.util.List;
22+
import java.util.Map;
2123

2224
/** In "real" entity would be annotated with @Entity. */
2325
public class TestEntity {
@@ -37,7 +39,6 @@ public class TestEntity {
3739
private long simpleLong;
3840
private float simpleFloat;
3941
private double simpleDouble;
40-
/** Not-null value. */
4142
private String simpleString;
4243
/** Not-null value. */
4344
private byte[] simpleByteArray;
@@ -50,6 +51,7 @@ public class TestEntity {
5051
private int simpleIntU;
5152
/** In "real" entity would be annotated with @Unsigned. */
5253
private long simpleLongU;
54+
private Map<String, Object> stringObjectMap;
5355

5456
transient boolean noArgsConstructorCalled;
5557

@@ -61,7 +63,10 @@ public TestEntity(long id) {
6163
this.id = id;
6264
}
6365

64-
public TestEntity(long id, boolean simpleBoolean, byte simpleByte, short simpleShort, int simpleInt, long simpleLong, float simpleFloat, double simpleDouble, String simpleString, byte[] simpleByteArray, String[] simpleStringArray, List<String> simpleStringList, short simpleShortU, int simpleIntU, long simpleLongU) {
66+
public TestEntity(long id, boolean simpleBoolean, byte simpleByte, short simpleShort, int simpleInt,
67+
long simpleLong, float simpleFloat, double simpleDouble, String simpleString,
68+
byte[] simpleByteArray, String[] simpleStringArray, List<String> simpleStringList,
69+
short simpleShortU, int simpleIntU, long simpleLongU, Map<String, Object> stringObjectMap) {
6570
this.id = id;
6671
this.simpleBoolean = simpleBoolean;
6772
this.simpleByte = simpleByte;
@@ -77,6 +82,7 @@ public TestEntity(long id, boolean simpleBoolean, byte simpleByte, short simpleS
7782
this.simpleShortU = simpleShortU;
7883
this.simpleIntU = simpleIntU;
7984
this.simpleLongU = simpleLongU;
85+
this.stringObjectMap = stringObjectMap;
8086
if (STRING_VALUE_THROW_IN_CONSTRUCTOR.equals(simpleString)) {
8187
throw new RuntimeException(EXCEPTION_IN_CONSTRUCTOR_MESSAGE);
8288
}
@@ -146,13 +152,12 @@ public void setSimpleDouble(double simpleDouble) {
146152
this.simpleDouble = simpleDouble;
147153
}
148154

149-
/** Not-null value. */
155+
@Nullable
150156
public String getSimpleString() {
151157
return simpleString;
152158
}
153159

154-
/** Not-null value; ensure this value is available before it is saved to the database. */
155-
public void setSimpleString(String simpleString) {
160+
public void setSimpleString(@Nullable String simpleString) {
156161
this.simpleString = simpleString;
157162
}
158163

@@ -212,6 +217,15 @@ public TestEntity setSimpleLongU(long simpleLongU) {
212217
return this;
213218
}
214219

220+
public Map<String, Object> getStringObjectMap() {
221+
return stringObjectMap;
222+
}
223+
224+
public TestEntity setStringObjectMap(Map<String, Object> stringObjectMap) {
225+
this.stringObjectMap = stringObjectMap;
226+
return this;
227+
}
228+
215229
@Override
216230
public String toString() {
217231
return "TestEntity{" +
@@ -230,6 +244,7 @@ public String toString() {
230244
", simpleShortU=" + simpleShortU +
231245
", simpleIntU=" + simpleIntU +
232246
", simpleLongU=" + simpleLongU +
247+
", stringObjectMap=" + stringObjectMap +
233248
", noArgsConstructorCalled=" + noArgsConstructorCalled +
234249
'}';
235250
}

tests/objectbox-java-test/src/main/java/io/objectbox/TestEntityCursor.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
package io.objectbox;
1818

1919
import io.objectbox.annotation.apihint.Internal;
20+
import io.objectbox.converter.StringFlexMapConverter;
2021
import io.objectbox.internal.CursorFactory;
2122

23+
import java.util.Map;
24+
2225
// NOTE: Copied from a plugin project (& removed some unused Properties).
2326
// THIS CODE IS GENERATED BY ObjectBox, DO NOT EDIT.
2427

@@ -41,6 +44,7 @@ public Cursor<TestEntity> createCursor(io.objectbox.Transaction tx, long cursorH
4144

4245
private static final TestEntity_.TestEntityIdGetter ID_GETTER = TestEntity_.__ID_GETTER;
4346

47+
private final StringFlexMapConverter stringObjectMapConverter = new StringFlexMapConverter();
4448

4549
private final static int __ID_simpleBoolean = TestEntity_.simpleBoolean.id;
4650
private final static int __ID_simpleByte = TestEntity_.simpleByte.id;
@@ -56,6 +60,7 @@ public Cursor<TestEntity> createCursor(io.objectbox.Transaction tx, long cursorH
5660
private final static int __ID_simpleShortU = TestEntity_.simpleShortU.id;
5761
private final static int __ID_simpleIntU = TestEntity_.simpleIntU.id;
5862
private final static int __ID_simpleLongU = TestEntity_.simpleLongU.id;
63+
private final static int __ID_stringObjectMap = TestEntity_.stringObjectMap.id;
5964

6065
public TestEntityCursor(io.objectbox.Transaction tx, long cursor, BoxStore boxStore) {
6166
super(tx, cursor, TestEntity_.__INSTANCE, boxStore);
@@ -89,10 +94,18 @@ public final long put(TestEntity entity) {
8994
int __id8 = simpleString != null ? __ID_simpleString : 0;
9095
byte[] simpleByteArray = entity.getSimpleByteArray();
9196
int __id9 = simpleByteArray != null ? __ID_simpleByteArray : 0;
97+
Map stringObjectMap = entity.getStringObjectMap();
98+
int __id15 = stringObjectMap != null ? __ID_stringObjectMap : 0;
9299

93-
collect313311(cursor, 0, 0,
100+
collect430000(cursor, 0, 0,
94101
__id8, simpleString, 0, null,
95-
0, null, __id9, simpleByteArray,
102+
0, null, 0, null,
103+
__id9, simpleByteArray, __id15, __id15 != 0 ? stringObjectMapConverter.convertToDatabaseValue(stringObjectMap) : null,
104+
0, null);
105+
106+
collect313311(cursor, 0, 0,
107+
0, null, 0, null,
108+
0, null, 0, null,
96109
__ID_simpleLong, entity.getSimpleLong(), __ID_simpleLongU, entity.getSimpleLongU(),
97110
INT_NULL_HACK ? 0 : __ID_simpleInt, entity.getSimpleInt(), __ID_simpleIntU, entity.getSimpleIntU(),
98111
__ID_simpleShort, entity.getSimpleShort(), __ID_simpleShortU, entity.getSimpleShortU(),

tests/objectbox-java-test/src/main/java/io/objectbox/TestEntity_.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919

2020
import io.objectbox.TestEntityCursor.Factory;
2121
import io.objectbox.annotation.apihint.Internal;
22+
import io.objectbox.converter.StringFlexMapConverter;
2223
import io.objectbox.internal.CursorFactory;
2324
import io.objectbox.internal.IdGetter;
2425

26+
import java.util.Map;
27+
2528
// NOTE: Copied from a plugin project (& removed some unused Properties).
2629
// THIS CODE IS GENERATED BY ObjectBox, DO NOT EDIT.
2730

@@ -92,6 +95,9 @@ public final class TestEntity_ implements EntityInfo<TestEntity> {
9295
public final static io.objectbox.Property<TestEntity> simpleLongU =
9396
new io.objectbox.Property<>(__INSTANCE, 14, 14, long.class, "simpleLongU");
9497

98+
public final static io.objectbox.Property<TestEntity> stringObjectMap =
99+
new io.objectbox.Property<>(__INSTANCE, 15, 16, byte[].class, "stringObjectMap", false, "stringObjectMap", StringFlexMapConverter.class, Map.class);
100+
95101
@SuppressWarnings("unchecked")
96102
public final static io.objectbox.Property<TestEntity>[] __ALL_PROPERTIES = new io.objectbox.Property[]{
97103
id,
@@ -108,7 +114,8 @@ public final class TestEntity_ implements EntityInfo<TestEntity> {
108114
simpleStringList,
109115
simpleShortU,
110116
simpleIntU,
111-
simpleLongU
117+
simpleLongU,
118+
stringObjectMap
112119
};
113120

114121
public final static io.objectbox.Property<TestEntity> __ID_PROPERTY = id;

tests/objectbox-java-test/src/test/java/io/objectbox/AbstractObjectBoxTest.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,26 @@
1616

1717
package io.objectbox;
1818

19+
import io.objectbox.ModelBuilder.EntityBuilder;
20+
import io.objectbox.ModelBuilder.PropertyBuilder;
1921
import io.objectbox.annotation.IndexType;
22+
import io.objectbox.model.PropertyFlags;
23+
import io.objectbox.model.PropertyType;
2024
import org.junit.After;
2125
import org.junit.Before;
2226

27+
import javax.annotation.Nullable;
2328
import java.io.File;
2429
import java.io.IOException;
2530
import java.util.ArrayList;
2631
import java.util.Arrays;
32+
import java.util.HashMap;
2733
import java.util.List;
34+
import java.util.Map;
2835
import java.util.Random;
2936
import java.util.concurrent.CountDownLatch;
3037
import java.util.concurrent.TimeUnit;
3138

32-
import javax.annotation.Nullable;
33-
34-
import io.objectbox.ModelBuilder.EntityBuilder;
35-
import io.objectbox.ModelBuilder.PropertyBuilder;
36-
import io.objectbox.model.PropertyFlags;
37-
import io.objectbox.model.PropertyType;
38-
39-
4039
import static org.junit.Assert.assertArrayEquals;
4140
import static org.junit.Assert.assertEquals;
4241
import static org.junit.Assert.assertTrue;
@@ -252,7 +251,11 @@ private void addTestEntity(ModelBuilder modelBuilder, @Nullable IndexType simple
252251
entityBuilder.property("simpleLongU", PropertyType.Long).id(TestEntity_.simpleLongU.id, ++lastUid)
253252
.flags(PropertyFlags.UNSIGNED);
254253

255-
int lastId = TestEntity_.simpleLongU.id;
254+
// Flexible map
255+
entityBuilder.property("stringObjectMap", PropertyType.Flex)
256+
.id(TestEntity_.stringObjectMap.id, ++lastUid);
257+
258+
int lastId = TestEntity_.stringObjectMap.id;
256259
entityBuilder.lastPropertyId(lastId, lastUid);
257260
addOptionalFlagsToTestEntity(entityBuilder);
258261
entityBuilder.entityDone();
@@ -293,6 +296,11 @@ protected TestEntity createTestEntity(@Nullable String simpleString, int nr) {
293296
entity.setSimpleShortU((short) (100 + nr));
294297
entity.setSimpleIntU(nr);
295298
entity.setSimpleLongU(1000 + nr);
299+
Map<String, Object> stringObjectMap = new HashMap<>();
300+
if (simpleString != null) {
301+
stringObjectMap.put(simpleString, simpleString);
302+
}
303+
entity.setStringObjectMap(stringObjectMap);
296304
return entity;
297305
}
298306

@@ -316,6 +324,10 @@ protected void assertTestEntity(TestEntity actual, @Nullable String simpleString
316324
assertEquals((short) (100 + nr), actual.getSimpleShortU());
317325
assertEquals(nr, actual.getSimpleIntU());
318326
assertEquals(1000 + nr, actual.getSimpleLongU());
327+
if (simpleString != null) {
328+
assertEquals(1, actual.getStringObjectMap().size());
329+
assertEquals(simpleString, actual.getStringObjectMap().get(simpleString));
330+
}
319331
}
320332

321333
protected TestEntity putTestEntity(@Nullable String simpleString, int nr) {

0 commit comments

Comments
 (0)