Skip to content

Commit a11f702

Browse files
In-memory: add option to store builder, test #194
1 parent 34a0686 commit a11f702

File tree

3 files changed

+121
-35
lines changed

3 files changed

+121
-35
lines changed

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

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public class BoxStoreBuilder {
7878
/** Ignored by BoxStore */
7979
private String name;
8080

81+
/** If non-null, using an in-memory database with this identifier. */
82+
private String inMemory;
83+
8184
/** Defaults to {@link #DEFAULT_MAX_DB_SIZE_KBYTE}. */
8285
long maxSizeInKByte = DEFAULT_MAX_DB_SIZE_KBYTE;
8386

@@ -145,14 +148,15 @@ public BoxStoreBuilder(byte[] model) {
145148
}
146149

147150
/**
148-
* Name of the database, which will be used as a directory for DB files.
151+
* Name of the database, which will be used as a directory for database files.
149152
* You can also specify a base directory for this one using {@link #baseDirectory(File)}.
150-
* Cannot be used in combination with {@link #directory(File)}.
153+
* Cannot be used in combination with {@link #directory(File)} and {@link #inMemory(String)}.
151154
* <p>
152155
* Default: "objectbox", {@link #DEFAULT_NAME} (unless {@link #directory(File)} is used)
153156
*/
154157
public BoxStoreBuilder name(String name) {
155158
checkIsNull(directory, "Already has directory, cannot assign name");
159+
checkIsNull(inMemory, "Already set to in-memory database, cannot assign name");
156160
if (name.contains("/") || name.contains("\\")) {
157161
throw new IllegalArgumentException("Name may not contain (back) slashes. " +
158162
"Use baseDirectory() or directory() to configure alternative directories");
@@ -175,11 +179,14 @@ public BoxStoreBuilder name(String name) {
175179
* .directory(BoxStore.IN_MEMORY_PREFIX + "notes-db")
176180
* .build();
177181
* }</pre>
182+
* Alternatively, use {@link #inMemory(String)}.
178183
* <p>
179-
* Can not be used in combination with {@link #name(String)} or {@link #baseDirectory(File)}.
184+
* Can not be used in combination with {@link #name(String)}, {@link #baseDirectory(File)}
185+
* or {@link #inMemory(String)}.
180186
*/
181187
public BoxStoreBuilder directory(File directory) {
182188
checkIsNull(name, "Already has name, cannot assign directory");
189+
checkIsNull(inMemory, "Already set to in-memory database, cannot assign directory");
183190
if (!android) {
184191
checkIsNull(baseDirectory, "Already has base directory, cannot assign directory");
185192
}
@@ -190,14 +197,29 @@ public BoxStoreBuilder directory(File directory) {
190197
/**
191198
* In combination with {@link #name(String)}, this lets you specify the location of where the DB files should be
192199
* stored.
193-
* Cannot be used in combination with {@link #directory(File)}.
200+
* Cannot be used in combination with {@link #directory(File)} or {@link #inMemory(String)}.
194201
*/
195202
public BoxStoreBuilder baseDirectory(File baseDirectory) {
196203
checkIsNull(directory, "Already has directory, cannot assign base directory");
204+
checkIsNull(inMemory, "Already set to in-memory database, cannot assign base directory");
197205
this.baseDirectory = baseDirectory;
198206
return this;
199207
}
200208

209+
/**
210+
* Switches to an in-memory database using the given name as its identifier.
211+
* <p>
212+
* Can not be used in combination with {@link #name(String)}, {@link #directory(File)}
213+
* or {@link #baseDirectory(File)}.
214+
*/
215+
public BoxStoreBuilder inMemory(String identifier) {
216+
checkIsNull(name, "Already has name, cannot switch to in-memory database");
217+
checkIsNull(directory, "Already has directory, cannot switch to in-memory database");
218+
checkIsNull(baseDirectory, "Already has base directory, cannot switch to in-memory database");
219+
inMemory = identifier;
220+
return this;
221+
}
222+
201223
/**
202224
* Use to check conflicting properties are not set.
203225
* If not null, throws {@link IllegalStateException} with the given message.
@@ -209,17 +231,18 @@ private static void checkIsNull(@Nullable Object value, String errorMessage) {
209231
}
210232

211233
/**
212-
* On Android, you can pass a Context to set the base directory using this method.
213-
* This will conveniently configure the storage location to be in the files directory of your app.
234+
* Use on Android to pass a <a href="https://developer.android.com/reference/android/content/Context">Context</a>
235+
* for loading the native library and, if {@link #inMemory(String)} was not called before, creating the base
236+
* directory for database files in the
237+
* <a href="https://developer.android.com/reference/android/content/Context#getFilesDir()">files directory of the app</a>.
214238
* <p>
215239
* In more detail, this assigns the base directory (see {@link #baseDirectory}) to
216240
* {@code context.getFilesDir() + "/objectbox/"}.
217-
* Thus, when using the default name (also "objectbox" unless overwritten using {@link #name(String)}), the default
218-
* location of DB files will be "objectbox/objectbox/" inside the app files directory.
219-
* If you specify a custom name, for example with {@code name("foobar")}, it would become
220-
* "objectbox/foobar/".
241+
* Thus, when using the default name (also "objectbox", unless overwritten using {@link #name(String)}), the default
242+
* location of database files will be "objectbox/objectbox/" inside the app's files directory.
243+
* If a custom name is specified, for example with {@code name("foobar")}, it would become "objectbox/foobar/".
221244
* <p>
222-
* Alternatively, you can also use {@link #baseDirectory} or {@link #directory(File)} instead.
245+
* Alternatively, use {@link #baseDirectory(File)} or {@link #directory(File)}.
223246
*/
224247
public BoxStoreBuilder androidContext(Object context) {
225248
//noinspection ConstantConditions Annotation does not enforce non-null.
@@ -228,17 +251,21 @@ public BoxStoreBuilder androidContext(Object context) {
228251
}
229252
this.context = getApplicationContext(context);
230253

231-
File baseDir = getAndroidBaseDir(context);
232-
if (!baseDir.exists()) {
233-
baseDir.mkdir();
234-
if (!baseDir.exists()) { // check baseDir.exists() because of potential concurrent processes
235-
throw new RuntimeException("Could not init Android base dir at " + baseDir.getAbsolutePath());
254+
// Only create directories if not already an in-memory database.
255+
// Note: this will still create directories if this is called before switching to an in-memory database.
256+
if (inMemory == null) {
257+
File baseDir = getAndroidBaseDir(context);
258+
if (!baseDir.exists()) {
259+
baseDir.mkdir();
260+
if (!baseDir.exists()) { // check baseDir.exists() because of potential concurrent processes
261+
throw new RuntimeException("Could not init Android base dir at " + baseDir.getAbsolutePath());
262+
}
236263
}
264+
if (!baseDir.isDirectory()) {
265+
throw new RuntimeException("Android base dir is not a dir: " + baseDir.getAbsolutePath());
266+
}
267+
baseDirectory = baseDir;
237268
}
238-
if (!baseDir.isDirectory()) {
239-
throw new RuntimeException("Android base dir is not a dir: " + baseDir.getAbsolutePath());
240-
}
241-
baseDirectory = baseDir;
242269
android = true;
243270
return this;
244271
}
@@ -524,7 +551,7 @@ public BoxStoreBuilder debugRelations() {
524551
* {@link DbException} are thrown during query execution).
525552
*
526553
* @param queryAttempts number of attempts a query find operation will be executed before failing.
527-
* Recommended values are in the range of 2 to 5, e.g. a value of 3 as a starting point.
554+
* Recommended values are in the range of 2 to 5, e.g. a value of 3 as a starting point.
528555
*/
529556
@Experimental
530557
public BoxStoreBuilder queryAttempts(int queryAttempts) {
@@ -603,11 +630,15 @@ byte[] buildFlatStoreOptions(String canonicalPath) {
603630
* Builds a {@link BoxStore} using any given configuration.
604631
*/
605632
public BoxStore build() {
633+
if (inMemory != null) {
634+
directory = new File(BoxStore.IN_MEMORY_PREFIX + inMemory);
635+
}
606636
if (directory == null) {
607-
name = dbName(name);
608637
directory = getDbDir(baseDirectory, name);
609638
}
610-
checkProvisionInitialDbFile();
639+
if (inMemory == null) {
640+
checkProvisionInitialDbFile();
641+
}
611642
return new BoxStore(this);
612643
}
613644

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535

3636
import static org.junit.Assert.assertEquals;
37+
import static org.junit.Assert.assertFalse;
3738
import static org.junit.Assert.assertSame;
3839
import static org.junit.Assert.assertThrows;
3940
import static org.junit.Assert.assertTrue;
@@ -122,6 +123,72 @@ public void directoryUnicodePath() throws IOException {
122123
deleteAllFiles(parentTestDir);
123124
}
124125

126+
@Test
127+
public void directoryConflictingOptionsError() {
128+
// using conflicting option after directory option
129+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
130+
.directory(boxStoreDir)
131+
.name("options-test")
132+
);
133+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
134+
.directory(boxStoreDir)
135+
.baseDirectory(boxStoreDir)
136+
);
137+
138+
// using directory option after conflicting option
139+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
140+
.name("options-test")
141+
.directory(boxStoreDir)
142+
);
143+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
144+
.baseDirectory(boxStoreDir)
145+
.directory(boxStoreDir)
146+
);
147+
}
148+
149+
@Test
150+
public void inMemoryConflictingOptionsError() {
151+
// directory-based option after switching to in-memory
152+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
153+
.inMemory("options-test")
154+
.name("options-test")
155+
);
156+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
157+
.inMemory("options-test")
158+
.directory(boxStoreDir)
159+
);
160+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
161+
.inMemory("options-test")
162+
.baseDirectory(boxStoreDir)
163+
);
164+
165+
// in-memory after specifying directory-based option
166+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
167+
.name("options-test")
168+
.inMemory("options-test")
169+
);
170+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
171+
.directory(boxStoreDir)
172+
.inMemory("options-test")
173+
);
174+
assertThrows(IllegalStateException.class, () -> createBuilderWithTestModel()
175+
.baseDirectory(boxStoreDir)
176+
.inMemory("options-test")
177+
);
178+
}
179+
180+
@Test
181+
public void inMemoryCreatesNoFiles() {
182+
// let base class clean up store in tearDown method
183+
store = createBuilderWithTestModel().inMemory("in-memory-test").build();
184+
185+
assertFalse(boxStoreDir.exists());
186+
assertFalse(new File("memory").exists());
187+
assertFalse(new File("memory:").exists());
188+
String identifierPart = boxStoreDir.getPath().substring("memory:".length());
189+
assertFalse(new File(identifierPart).exists());
190+
}
191+
125192
@Test
126193
public void testMaxReaders() {
127194
builder = createBoxStoreBuilder(null);

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import static org.junit.Assert.assertTrue;
3636
import static org.junit.Assert.fail;
3737
import static org.junit.Assume.assumeFalse;
38-
import static org.junit.Assume.assumeTrue;
3938

4039
public class BoxStoreTest extends AbstractObjectBoxTest {
4140

@@ -315,17 +314,6 @@ public void testSizeOnDisk() {
315314
assertTrue(size >= 8192);
316315
}
317316

318-
@Test
319-
public void testInMemory_createsNoFiles() {
320-
assumeTrue(IN_MEMORY);
321-
322-
assertFalse(boxStoreDir.exists());
323-
assertFalse(new File("memory").exists());
324-
assertFalse(new File("memory:").exists());
325-
String identifierPart = boxStoreDir.getPath().substring("memory:".length());
326-
assertFalse(new File(identifierPart).exists());
327-
}
328-
329317
@Test
330318
public void validate() {
331319
putTestEntities(100);

0 commit comments

Comments
 (0)