Skip to content

Commit 16a241a

Browse files
authored
feat(java): add store implementation (#387)
1 parent 32bf3bf commit 16a241a

14 files changed

+1487
-9
lines changed

java/com/google/dotprompt/helpers/Helpers.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ public static Object json(Object context, Options options) throws IOException {
7777

7878
Integer indent = options.hash("indent", null);
7979
if (indent != null) {
80-
DefaultPrettyPrinter printer =
81-
new DefaultPrettyPrinter();
80+
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
8281
printer.indentObjectsWith(new DefaultIndenter(" ", "\n"));
8382

8483
localMapper =
@@ -90,16 +89,15 @@ public static Object json(Object context, Options options) throws IOException {
9089
public DefaultPrettyPrinter createInstance() {
9190
return new DefaultPrettyPrinter(this) {
9291
@Override
93-
public void writeObjectFieldValueSeparator(
94-
JsonGenerator g) throws IOException {
92+
public void writeObjectFieldValueSeparator(JsonGenerator g)
93+
throws IOException {
9594
g.writeRaw(": ");
9695
}
9796
};
9897
}
9998

10099
@Override
101-
public void writeObjectFieldValueSeparator(
102-
JsonGenerator g) throws IOException {
100+
public void writeObjectFieldValueSeparator(JsonGenerator g) throws IOException {
103101
g.writeRaw(": ");
104102
}
105103
})

java/com/google/dotprompt/resolvers/SchemaResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.util.Map;
2222
import java.util.concurrent.CompletableFuture;
23+
import java.util.function.Function;
2324

2425
/**
2526
* Resolves a provided schema name to an underlying JSON schema.
@@ -86,8 +87,7 @@ public interface SchemaResolver {
8687
* corresponding JSON Schema, or {@code null}.
8788
* @return An async {@link SchemaResolver} wrapping the synchronous function.
8889
*/
89-
static SchemaResolver fromSync(
90-
java.util.function.Function<String, Map<String, Object>> syncResolver) {
90+
static SchemaResolver fromSync(Function<String, Map<String, Object>> syncResolver) {
9191
return schemaName -> CompletableFuture.completedFuture(syncResolver.apply(schemaName));
9292
}
9393
}

java/com/google/dotprompt/store/BUILD.bazel

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,49 @@ load("@rules_java//java:defs.bzl", "java_library")
1919
java_library(
2020
name = "store",
2121
srcs = [
22+
"DirStore.java",
23+
"DirStoreOptions.java",
24+
"DirStoreSync.java",
2225
"PromptStore.java",
26+
"PromptStoreSync.java",
2327
"PromptStoreWritable.java",
28+
"PromptStoreWritableSync.java",
29+
"StoreUtils.java",
2430
],
2531
visibility = ["//visibility:public"],
2632
deps = [
2733
"//java/com/google/dotprompt/models",
2834
],
2935
)
36+
37+
java_test(
38+
name = "DirStoreSyncTest",
39+
srcs = ["DirStoreSyncTest.java"],
40+
deps = [
41+
":store",
42+
"//java/com/google/dotprompt/models",
43+
"@maven//:com_google_truth_truth",
44+
"@maven//:junit_junit",
45+
],
46+
)
47+
48+
java_test(
49+
name = "DirStoreTest",
50+
srcs = ["DirStoreTest.java"],
51+
deps = [
52+
":store",
53+
"//java/com/google/dotprompt/models",
54+
"@maven//:com_google_truth_truth",
55+
"@maven//:junit_junit",
56+
],
57+
)
58+
59+
java_test(
60+
name = "StoreUtilsTest",
61+
srcs = ["StoreUtilsTest.java"],
62+
deps = [
63+
":store",
64+
"@maven//:com_google_truth_truth",
65+
"@maven//:junit_junit",
66+
],
67+
)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
19+
package com.google.dotprompt.store;
20+
21+
import com.google.dotprompt.models.DeletePromptOrPartialOptions;
22+
import com.google.dotprompt.models.ListPartialsOptions;
23+
import com.google.dotprompt.models.ListPromptsOptions;
24+
import com.google.dotprompt.models.LoadPartialOptions;
25+
import com.google.dotprompt.models.LoadPromptOptions;
26+
import com.google.dotprompt.models.PaginatedPartials;
27+
import com.google.dotprompt.models.PaginatedPrompts;
28+
import com.google.dotprompt.models.PromptData;
29+
import java.util.concurrent.CompletableFuture;
30+
import java.util.concurrent.Executor;
31+
import java.util.concurrent.ForkJoinPool;
32+
33+
/**
34+
* Asynchronous filesystem-based prompt store implementation.
35+
*
36+
* <p>Reads and writes prompts and partials from/to the local file system within a specified
37+
* directory using asynchronous operations backed by {@link CompletableFuture}.
38+
*
39+
* <h2>File Naming Conventions</h2>
40+
*
41+
* <ul>
42+
* <li>Prompts: {@code [name][.variant].prompt}
43+
* <li>Partials: {@code _[name][.variant].prompt}
44+
* </ul>
45+
*
46+
* <h2>Usage Example</h2>
47+
*
48+
* <pre>{@code
49+
* DirStore store = new DirStore(DirStoreOptions.of("/path/to/prompts"));
50+
*
51+
* // List prompts asynchronously
52+
* store.list(null).thenAccept(prompts -> {
53+
* prompts.prompts().forEach(p -> System.out.println(p.name()));
54+
* });
55+
*
56+
* // Load a specific prompt
57+
* PromptData data = store.load("my_prompt", null).join();
58+
* }</pre>
59+
*
60+
* <p>This class wraps {@link DirStoreSync} to provide async operations. All operations are executed
61+
* on a configurable {@link Executor}.
62+
*/
63+
public class DirStore implements PromptStoreWritable {
64+
65+
private final DirStoreSync syncStore;
66+
private final Executor executor;
67+
68+
/**
69+
* Creates a new DirStore instance using the common ForkJoinPool.
70+
*
71+
* @param options Configuration options including the base directory.
72+
*/
73+
public DirStore(DirStoreOptions options) {
74+
this(options, ForkJoinPool.commonPool());
75+
}
76+
77+
/**
78+
* Creates a new DirStore instance with a custom executor.
79+
*
80+
* @param options Configuration options including the base directory.
81+
* @param executor The executor to use for async operations.
82+
*/
83+
public DirStore(DirStoreOptions options, Executor executor) {
84+
this.syncStore = new DirStoreSync(options);
85+
this.executor = executor;
86+
}
87+
88+
@Override
89+
public CompletableFuture<PaginatedPrompts> list(ListPromptsOptions options) {
90+
return CompletableFuture.supplyAsync(() -> syncStore.list(options), executor);
91+
}
92+
93+
@Override
94+
public CompletableFuture<PaginatedPartials> listPartials(ListPartialsOptions options) {
95+
return CompletableFuture.supplyAsync(() -> syncStore.listPartials(options), executor);
96+
}
97+
98+
@Override
99+
public CompletableFuture<PromptData> load(String name, LoadPromptOptions options) {
100+
return CompletableFuture.supplyAsync(() -> syncStore.load(name, options), executor);
101+
}
102+
103+
@Override
104+
public CompletableFuture<PromptData> loadPartial(String name, LoadPartialOptions options) {
105+
return CompletableFuture.supplyAsync(() -> syncStore.loadPartial(name, options), executor);
106+
}
107+
108+
@Override
109+
public CompletableFuture<Void> save(PromptData prompt) {
110+
return CompletableFuture.runAsync(() -> syncStore.save(prompt), executor);
111+
}
112+
113+
@Override
114+
public CompletableFuture<Void> delete(String name, DeletePromptOrPartialOptions options) {
115+
return CompletableFuture.runAsync(() -> syncStore.delete(name, options), executor);
116+
}
117+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
19+
package com.google.dotprompt.store;
20+
21+
import java.nio.file.Path;
22+
23+
/**
24+
* Configuration options for directory-based prompt stores.
25+
*
26+
* @param directory The base directory where prompt files are stored.
27+
*/
28+
public record DirStoreOptions(Path directory) {
29+
30+
/**
31+
* Creates options from a string path.
32+
*
33+
* @param directory The directory path as a string.
34+
* @return A new DirStoreOptions instance.
35+
*/
36+
public static DirStoreOptions of(String directory) {
37+
return new DirStoreOptions(Path.of(directory));
38+
}
39+
}

0 commit comments

Comments
 (0)