|
19 | 19 | import com.google.gcloud.datastore.DatastoreService; |
20 | 20 | import com.google.gcloud.datastore.DatastoreServiceFactory; |
21 | 21 | import com.google.gcloud.datastore.DatastoreServiceOptions; |
| 22 | +import com.google.gcloud.datastore.DateTime; |
22 | 23 | import com.google.gcloud.datastore.Entity; |
| 24 | +import com.google.gcloud.datastore.FullEntity; |
| 25 | +import com.google.gcloud.datastore.IncompleteKey; |
23 | 26 | import com.google.gcloud.datastore.Key; |
24 | 27 | import com.google.gcloud.datastore.KeyFactory; |
| 28 | +import com.google.gcloud.datastore.Query; |
| 29 | +import com.google.gcloud.datastore.Query.ResultType; |
| 30 | +import com.google.gcloud.datastore.QueryResults; |
| 31 | +import com.google.gcloud.datastore.StructuredQuery.PropertyFilter; |
| 32 | +import com.google.gcloud.datastore.Transaction; |
| 33 | + |
| 34 | +import java.util.Arrays; |
| 35 | +import java.util.HashMap; |
| 36 | +import java.util.Map; |
| 37 | +import java.util.TreeMap; |
25 | 38 |
|
26 | 39 | /** |
27 | 40 | * An example of using the Google Cloud Datastore. |
28 | 41 | * <p> |
| 42 | + * This example adds, display or clear comments for a given user. |
| 43 | + * <p> |
29 | 44 | * Steps needed for running the example:<ol> |
30 | 45 | * <li>login using gcloud SDK - {@code gcloud auth login}.</li> |
31 | 46 | * <li>compile using maven - {@code mvn compile}</li> |
32 | 47 | * <li>run using maven - {@code mvn exec:java |
33 | | - * -Dexec.mainClass="com.google.gcloud.examples.DatastoreExample" -Dexec.arguments="dataset"}</li> |
| 48 | + * -Dexec.mainClass="com.google.gcloud.examples.DatastoreExample" |
| 49 | + * -Dexec.args="dataset [user] [delete|display|add comment]"}</li> |
34 | 50 | * </ol> |
35 | 51 | */ |
36 | 52 | public class DatastoreExample { |
37 | 53 |
|
38 | | - public static void main(String[] args) { |
39 | | - if (args.length != 1) { |
40 | | - System.err.println("DatastoreExample requires one argument for dataset"); |
41 | | - return; |
| 54 | + private final static String USER_KIND = "_DS_EXAMPLE_USER"; |
| 55 | + private final static String COMMENT_KIND = "_DS_EXAMPLE_COMMENT"; |
| 56 | + private final static String NAMESPACE = "gcloud_java_example"; |
| 57 | + private final static String DEFAULT_ACTION = "display"; |
| 58 | + private final static Map<String, DatastoreAction> ACTIONS = new HashMap<>(); |
| 59 | + |
| 60 | + private interface DatastoreAction { |
| 61 | + void run(Transaction tx, Key userKey, String... args); |
| 62 | + String getRequiredParams(); |
| 63 | + } |
| 64 | + |
| 65 | + private static class DeleteAction implements DatastoreAction { |
| 66 | + @Override |
| 67 | + public void run(Transaction tx, Key userKey, String... args) { |
| 68 | + Entity user = tx.get(userKey); |
| 69 | + if (user == null) { |
| 70 | + System.out.println("Nothing to delete, user does not exists."); |
| 71 | + return; |
| 72 | + } |
| 73 | + Query<Key> query = Query.keyQueryBuilder() |
| 74 | + .namespace(NAMESPACE) |
| 75 | + .kind(COMMENT_KIND) |
| 76 | + .filter(PropertyFilter.hasAncestor(userKey)) |
| 77 | + .build(); |
| 78 | + QueryResults<Key> comments = tx.run(query); |
| 79 | + int count = 0; |
| 80 | + while (comments.hasNext()) { |
| 81 | + tx.delete(comments.next()); |
| 82 | + count++; |
| 83 | + } |
| 84 | + tx.delete(userKey); |
| 85 | + System.out.printf("Deleting user '%s' and %d comments.\n", userKey.name(), count); |
| 86 | + } |
| 87 | + |
| 88 | + @Override |
| 89 | + public String getRequiredParams() { |
| 90 | + return ""; |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + private static class DisplayAction implements DatastoreAction { |
| 95 | + @Override |
| 96 | + public void run(Transaction tx, Key userKey, String... args) { |
| 97 | + Entity user = tx.get(userKey); |
| 98 | + if (user == null) { |
| 99 | + System.out.println("No comments for '" + userKey.name() + "'."); |
| 100 | + return; |
| 101 | + } |
| 102 | + System.out.println("User: " + userKey.name()); |
| 103 | + // ORDER BY timestamp"; |
| 104 | + String gql = "SELECT * FROM " + COMMENT_KIND + " WHERE __key__ HAS ANCESTOR @1"; |
| 105 | + Query<Entity> query = Query.gqlQueryBuilder(ResultType.ENTITY, gql) |
| 106 | + .namespace(NAMESPACE) |
| 107 | + .addBinding(userKey) |
| 108 | + .build(); |
| 109 | + QueryResults<Entity> results = tx.run(query); |
| 110 | + // We could have added "ORDER BY timestamp" to the query to avoid the sorting bellow |
| 111 | + // but that would require adding an ancestor index for timestamp |
| 112 | + // see: https://cloud.google.com/datastore/docs/tools/indexconfig |
| 113 | + Map<DateTime, String> sortedComments = new TreeMap<>(); |
| 114 | + while (results.hasNext()) { |
| 115 | + Entity result = results.next(); |
| 116 | + sortedComments.put(result.getDateTime("timestamp"), result.getString("content")); |
| 117 | + } |
| 118 | + for (Map.Entry<DateTime, String> entry : sortedComments.entrySet()) { |
| 119 | + System.out.printf("\t%s: %s\n", entry.getKey(), entry.getValue()); |
| 120 | + } |
42 | 121 | } |
43 | | - String dataset = args[0]; |
44 | | - // If you want to access a local Datastore running via the gcd sdk, do |
45 | | - // DatastoreServiceOptions options = DatastoreServiceOptions.builder() |
46 | | - // .dataset(DATASET) |
47 | | - // .host("http://localhost:" + LocalGcdHelper.PORT) |
48 | | - // .build(); |
49 | | - DatastoreServiceOptions options = DatastoreServiceOptions.builder().dataset(dataset).build(); |
50 | | - DatastoreService datastore = DatastoreServiceFactory.getDefault(options); |
51 | | - KeyFactory keyFactory = datastore.newKeyFactory().kind("Person"); |
52 | | - Key key = keyFactory.newKey("Jimmy"); |
53 | 122 |
|
54 | | - System.out.println("Trying to get the entity by its key!"); |
55 | | - Entity entity = datastore.get(key); |
| 123 | + @Override |
| 124 | + public String getRequiredParams() { |
| 125 | + return ""; |
| 126 | + } |
| 127 | + } |
56 | 128 |
|
57 | | - if (entity == null) { |
58 | | - System.out.println("Entity not found! Creating it!"); |
59 | | - entity = Entity.builder(key) |
60 | | - .set("age", 30L) |
| 129 | + private static class AddAction implements DatastoreAction { |
| 130 | + @Override |
| 131 | + public void run(Transaction tx, Key userKey, String... args) { |
| 132 | + Entity user = tx.get(userKey); |
| 133 | + if (user == null) { |
| 134 | + System.out.println("Adding a new user."); |
| 135 | + user = Entity.builder(userKey) |
| 136 | + .set("count", 1L) |
| 137 | + .build(); |
| 138 | + tx.add(user); |
| 139 | + } |
| 140 | + String content = "No comment."; |
| 141 | + if (args.length > 0) { |
| 142 | + StringBuilder stBuilder = new StringBuilder(); |
| 143 | + for (String arg : args) { |
| 144 | + stBuilder.append(arg).append(' '); |
| 145 | + } |
| 146 | + stBuilder.setLength(stBuilder.length() - 1); |
| 147 | + content = stBuilder.toString(); |
| 148 | + } |
| 149 | + IncompleteKey commentKey = IncompleteKey.builder(userKey, COMMENT_KIND).build(); |
| 150 | + FullEntity<IncompleteKey> comment = FullEntity.builder(commentKey) |
| 151 | + .set("content", content) |
| 152 | + .set("timestamp", DateTime.now()) |
61 | 153 | .build(); |
62 | | - datastore.add(entity); |
| 154 | + tx.addWithDeferredIdAllocation(comment); |
| 155 | + System.out.println("Adding a comment to user '" + userKey.name() + "'."); |
63 | 156 | } |
64 | 157 |
|
65 | | - System.out.println("Going to modify entity: " + entity); |
66 | | - Entity.Builder builder = Entity.builder(entity); |
67 | | - builder.set("f", 30); |
68 | | - datastore.put(entity); |
| 158 | + @Override |
| 159 | + public String getRequiredParams() { |
| 160 | + return "comment"; |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + static { |
| 165 | + ACTIONS.put("delete", new DeleteAction()); |
| 166 | + ACTIONS.put("add", new AddAction()); |
| 167 | + ACTIONS.put("display", new DisplayAction()); |
| 168 | + } |
69 | 169 |
|
70 | | - System.out.println("Trying again to get the entity by its key!"); |
71 | | - key = Key.builder(dataset, "Person", "Jimmy").build(); |
72 | | - System.out.println("Got entity: " + entity); |
| 170 | + public static void main(String... args) { |
| 171 | + DatastoreAction action = null; |
| 172 | + DatastoreService datastore = null; |
| 173 | + Key key = null; |
| 174 | + if (args.length > 0) { |
| 175 | + String dataset = args[0]; |
| 176 | + // If you want to access a local Datastore running via the gcd sdk, do |
| 177 | + // DatastoreServiceOptions options = DatastoreServiceOptions.builder() |
| 178 | + // .dataset(dataset) |
| 179 | + // .namespace(NAMESPACE) |
| 180 | + // .host("http://localhost:8080") |
| 181 | + // .build(); |
| 182 | + DatastoreServiceOptions options = DatastoreServiceOptions.builder() |
| 183 | + .dataset(dataset) |
| 184 | + .namespace(NAMESPACE) |
| 185 | + .build(); |
| 186 | + String name = args.length > 1 ? args[1] : System.getProperty("user.name"); |
| 187 | + datastore = DatastoreServiceFactory.getDefault(options); |
| 188 | + KeyFactory keyFactory = datastore.newKeyFactory().kind(USER_KIND); |
| 189 | + key = keyFactory.newKey(name); |
| 190 | + String actionName = args.length > 2 ? args[2].toLowerCase() : DEFAULT_ACTION; |
| 191 | + action = ACTIONS.get(actionName); |
| 192 | + } |
| 193 | + if (action == null) { |
| 194 | + StringBuilder actionAndParams = new StringBuilder(); |
| 195 | + for (Map.Entry<String, DatastoreAction> entry : ACTIONS.entrySet()) { |
| 196 | + actionAndParams.append(entry.getKey()); |
| 197 | + String param = entry.getValue().getRequiredParams(); |
| 198 | + if (param != null && !param.isEmpty()) { |
| 199 | + actionAndParams.append(' ').append(param); |
| 200 | + } |
| 201 | + actionAndParams.append('|'); |
| 202 | + } |
| 203 | + actionAndParams.setLength(actionAndParams.length() - 1); |
| 204 | + System.out.printf("Usage: %s dataset [user] [%s]\n", |
| 205 | + DatastoreExample.class.getSimpleName(), actionAndParams); |
| 206 | + return; |
| 207 | + } |
| 208 | + args = args.length > 3 ? Arrays.copyOfRange(args, 3, args.length): new String []{}; |
| 209 | + Transaction tx = datastore.newTransaction(); |
| 210 | + try { |
| 211 | + action.run(tx, key, args); |
| 212 | + tx.commit(); |
| 213 | + } finally { |
| 214 | + if (tx.active()) { |
| 215 | + tx.rollback(); |
| 216 | + } |
| 217 | + } |
73 | 218 | } |
74 | 219 | } |
0 commit comments