// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gwtorm.client;

/**
 * Data access interface for an entity type.
 * <p>
 * Applications should extend this interface for each entity type they need to
 * access. At runtime the application extension will be automatically
 * implemented with a generated class, providing concrete implementations for
 * all methods.
 * <p>
 * Instances should be acquired through the application's extension interface of
 * {@link Schema}.
 * <p>
 * Applications should implement a query method using the {@link PrimaryKey}
 * annotation, for example:
 * 
 * <pre>
 * public interface FooAccess extends Access&lt;Foo, Foo.Key&gt; {
 *   &#064;PrimaryKey(&quot;key&quot;)
 *   Foo byKey(Foo.Key k) throws OrmException;
 * }
 *</pre>
 *<p>
 * otherwise the primaryKey, get, update and delete operations declared by this
 * interface will be unsupported.
 * 
 * @param <T> type of the entity. Any object type is suitable, so long as at
 *        least one field uses a {@link Column} annotation.
 * @param <K> type of the primary key of entity. If the primary key is a
 *        primitive type then use Key directly, otherwise use a Key
 *        implementation. Entity specific key subclasses are recommended.
 */
public interface Access<T extends Object, K extends Key<?>> {
  /**
   * Obtain the primary key of an entity instance.
   * 
   * @param entity the entity to get the key of; must not be null.
   * @return the primary key. Null if this entity has no primary key declared,
   *         or if the primary key does not implement the Key interface.
   */
  K primaryKey(T entity);

  /**
   * Lookup a single entity via its primary key.
   * <p>
   * This method is only implemented if the entity's primary key is defined to
   * be an implementation of the {@link Key} interface. Otherwise the method
   * throws {@link UnsupportedOperationException}.
   * 
   * @param key the primary key instance; must not be null.
   * @return the entity; null if no entity has this key.
   * @throws OrmException the data lookup failed.
   * @throws UnsupportedOperationException the key type doesn't implement Key.
   */
  T get(K key) throws OrmException;

  /**
   * Lookup multiple entities via their primary key.
   * <p>
   * This method is only implemented if the entity's primary key is defined to
   * be an implementation of the {@link Key} interface. Otherwise the method
   * throws {@link UnsupportedOperationException}.
   * <p>
   * This method is a batch form of {@link #get(Key)} and may be optimized to
   * reduce round-trips to the data store.
   * 
   * @param keys collection of zero or more keys to perform lookup with.
   * @return collection of all matching entities; this may be a smaller result
   *         than the keys supplied if one or more of the keys does not match an
   *         existing entity.
   * @throws OrmException the data lookup failed.
   * @throws UnsupportedOperationException the key type doesn't implement Key.
   */
  ResultSet<T> get(Iterable<K> keys) throws OrmException;

  /**
   * Immediately insert new entities into the data store.
   * 
   * @param instances the instances to insert. The iteration occurs only once.
   * @throws OrmException data insertion failed.
   */
  void insert(Iterable<T> instances) throws OrmException;

  /**
   * Insert new entities into the data store.
   * 
   * @param instances the instances to insert. The iteration occurs only once.
   * @param txn transaction to batch the operation into. If not null the data
   *        store changes will be delayed to {@link Transaction#commit()} is
   *        invoked; if null the operation occurs immediately.
   * @throws OrmException data insertion failed.
   */
  void insert(Iterable<T> instances, Transaction txn) throws OrmException;

  /**
   * Immediately update existing entities in the data store.
   * 
   * @param instances the instances to update. The iteration occurs only once.
   * @throws OrmException data modification failed.
   * @throws UnsupportedOperationException no PrimaryKey was declared.
   */
  void update(Iterable<T> instances) throws OrmException;

  /**
   * Update existing entities in the data store.
   * 
   * @param instances the instances to update. The iteration occurs only once.
   * @param txn transaction to batch the operation into. If not null the data
   *        store changes will be delayed to {@link Transaction#commit()} is
   *        invoked; if null the operation occurs immediately.
   * @throws OrmException data modification failed.
   * @throws UnsupportedOperationException no PrimaryKey was declared.
   */
  void update(Iterable<T> instances, Transaction txn) throws OrmException;

  /**
   * Immediately delete existing entities from the data store.
   * 
   * @param instances the instances to delete. The iteration occurs only once.
   * @throws OrmException data removal failed.
   * @throws UnsupportedOperationException no PrimaryKey was declared.
   */
  void delete(Iterable<T> instances) throws OrmException;

  /**
   * Delete existing entities from the data store.
   * 
   * @param instances the instances to delete. The iteration occurs only once.
   * @param txn transaction to batch the operation into. If not null the data
   *        store changes will be delayed to {@link Transaction#commit()} is
   *        invoked; if null the operation occurs immediately.
   * @throws OrmException data removal failed.
   * @throws UnsupportedOperationException no PrimaryKey was declared.
   */
  void delete(Iterable<T> instances, Transaction txn) throws OrmException;
}
