| // Copyright 2016 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package io.v.syncbase; |
| |
| import io.v.v23.VFutures; |
| import io.v.v23.security.access.Permissions; |
| import io.v.v23.verror.ExistException; |
| import io.v.v23.verror.VException; |
| |
| /** |
| * Represents an ordered set of key-value pairs. |
| * To get a Collection handle, call {@code Database.collection}. |
| */ |
| public class Collection { |
| private final io.v.v23.syncbase.Collection mVCollection; |
| private final DatabaseHandle mDatabaseHandle; |
| |
| protected void createIfMissing() { |
| try { |
| VFutures.sync(mVCollection.create(Syncbase.getVContext(), Syncbase.defaultPerms())); |
| } catch (ExistException e) { |
| // Collection already exists. |
| } catch (VException e) { |
| throw new RuntimeException("Failed to create collection", e); |
| } |
| } |
| |
| protected Collection(io.v.v23.syncbase.Collection vCollection, DatabaseHandle databaseHandle) { |
| mVCollection = vCollection; |
| mDatabaseHandle = databaseHandle; |
| } |
| |
| /** |
| * Returns the id of this collection. |
| */ |
| public Id getId() { |
| return new Id(mVCollection.id()); |
| } |
| |
| /** |
| * Shortcut for {@code Database.getSyncgroup(collection.getId())}, helpful for the common case |
| * of one syncgroup per collection. |
| */ |
| public Syncgroup getSyncgroup() { |
| if (mDatabaseHandle instanceof BatchDatabase) { |
| throw new RuntimeException("Must not call getSyncgroup within batch"); |
| } |
| return ((Database) mDatabaseHandle).getSyncgroup(getId()); |
| } |
| |
| // TODO(sadovsky): Maybe add scan API, if developers aren't satisfied with watch. |
| |
| // TODO(sadovsky): Revisit the get API: |
| // - Is the Class<T> argument necessary? |
| // - What does it do if there is no value for the given key? |
| |
| /** |
| * Returns the value associated with {@code key}. |
| */ |
| public <T> T get(String key, Class<T> cls) { |
| try { |
| return VFutures.sync(mVCollection.getRow(key).get(Syncbase.getVContext(), cls)); |
| } catch (VException e) { |
| throw new RuntimeException("get failed: " + key, e); |
| } |
| } |
| |
| /** |
| * Returns true if there is a value associated with {@code key}. |
| */ |
| public boolean exists(String key) { |
| try { |
| return VFutures.sync(mVCollection.getRow(key).exists(Syncbase.getVContext())); |
| } catch (VException e) { |
| throw new RuntimeException("exists failed: " + key, e); |
| } |
| } |
| |
| /** |
| * Puts {@code value} for {@code key}, overwriting any existing value. Idempotent. |
| */ |
| public <T> void put(String key, T value) { |
| try { |
| VFutures.sync(mVCollection.put(Syncbase.getVContext(), key, value)); |
| } catch (VException e) { |
| throw new RuntimeException("put failed: " + key, e); |
| } |
| } |
| |
| /** |
| * Deletes the value associated with {@code key}. Idempotent. |
| */ |
| public void delete(String key) { |
| try { |
| VFutures.sync(mVCollection.getRow(key).delete(Syncbase.getVContext())); |
| } catch (VException e) { |
| throw new RuntimeException("delete failed: " + key, e); |
| } |
| } |
| |
| /** |
| * FOR ADVANCED USERS. Returns the {@code AccessList} for this collection. Users should |
| * typically manipulate access lists via {@code collection.getSyncgroup()}. |
| */ |
| public AccessList getAccessList() { |
| try { |
| return new AccessList(VFutures.sync(mVCollection.getPermissions(Syncbase.getVContext()))); |
| } catch (VException e) { |
| throw new RuntimeException("getPermissions failed", e); |
| } |
| } |
| |
| /** |
| * FOR ADVANCED USERS. Updates the {@code AccessList} for this collection. Users should |
| * typically manipulate access lists via {@code collection.getSyncgroup()}. |
| */ |
| public void updateAccessList(final AccessList delta) { |
| final Id id = this.getId(); |
| Database.BatchOperation op = new Database.BatchOperation() { |
| @Override |
| public void run(BatchDatabase db) { |
| io.v.v23.syncbase.Collection vCx = db.getCollection(id).mVCollection; |
| Permissions perms; |
| try { |
| perms = VFutures.sync(vCx.getPermissions(Syncbase.getVContext())); |
| } catch (VException e) { |
| throw new RuntimeException("getPermissions failed", e); |
| } |
| AccessList.applyDelta(perms, delta); |
| try { |
| VFutures.sync(vCx.setPermissions(Syncbase.getVContext(), perms)); |
| } catch (VException e) { |
| throw new RuntimeException("setPermissions failed", e); |
| } |
| } |
| }; |
| // Create a batch if we're not already in a batch. |
| if (mDatabaseHandle instanceof BatchDatabase) { |
| op.run((BatchDatabase) mDatabaseHandle); |
| } else { |
| ((Database) mDatabaseHandle).runInBatch(op, new Database.BatchOptions()); |
| } |
| } |
| } |