/*
* Copyright 2006-2012 Amazon Technologies, Inc. or its affiliates.
* Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
* of Amazon Technologies, Inc. or its affiliates. All rights reserved.
*
* 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.amazon.carbonado;
import com.amazon.carbonado.filter.Filter;
/**
* Access for a specific type of {@link Storable} from a {@link Repository}.
*
* <p>Storage instances are mutable, but they are thread-safe.
*
* @author Brian S O'Neill
*/
public interface Storage<S extends Storable> {
/**
* Returns the specific type of Storable managed by this object.
*/
Class<S> getStorableType();
/**
* Prepares a new object for loading, inserting, updating, or deleting.
*
* @return a new data access object
*/
S prepare();
/**
* Query for all Storable instances in this Storage.
*
* @see #query(String)
* @throws FetchException if storage layer throws an exception
*/
Query<S> query() throws FetchException;
/**
* Query for Storable instances against a filter expression. A filter tests
* if property values match against specific values specified by '?'
* placeholders. The simplest filter compares just one property, like
* {@code "ID = ?"}. Filters can also contain several kinds of relational
* operators, boolean logic operators, sub-properties, and parentheses. A
* more complex example might be {@code "income < ? | (name = ? & address.zipCode != ?)"}.
* <p>
* When querying for a single Storable instance by its primary key, it is
* generally more efficient to call {@link #prepare()}, set primary key
* properties, and then call {@link Storable#load()}. For example, consider
* an object with a primary key consisting only of the property "ID". It
* can be queried as:
* <pre>
* Storage<UserInfo> users;
* UserInfo user = users.query("ID = ?").with(123456).loadOne();
* </pre>
* The above code will likely open a Cursor in order to verify that just
* one object was loaded. Instead, do this:
* <pre>
* Storage<UserInfo> users;
* UserInfo user = users.prepare();
* user.setID(123456);
* user.load();
* </pre>
* The complete syntax for query filters follows. Note that:
* <ul>
* <li> literals are not allowed
* <li> logical 'and' operator has precedence over 'or'
* <li> logical 'not' operator has precedence over 'and'
* <li> '?' placeholders can only appear after relational operators
* </ul>
* <pre>
* Filter = OrFilter
* OrFilter = AndFilter { "|" AndFilter }
* AndFilter = NotFilter { "&" NotFilter }
* NotFilter = [ "!" ] EntityFilter
* EntityFilter = PropertyFilter
* | ChainedFilter
* | "(" Filter ")"
* PropertyFilter = ChainedProperty RelOp "?"
* RelOp = "=" | "!=" | "<" | ">=" | ">" | "<="
* ChainedFilter = ChainedProperty "(" [ Filter ] ")"
* ChainedProperty = Identifier
* | InnerJoin "." ChainedProperty
* | OuterJoin "." ChainedProperty
* InnerJoin = Identifier
* OuterJoin = "(" Identifier ")"
* </pre>
*
* @param filter query filter expression
* @throws FetchException if storage layer throws an exception
* @throws IllegalArgumentException if filter is null
* @throws MalformedFilterException if expression is malformed
* @throws UnsupportedOperationException if given filter is unsupported by repository
*/
Query<S> query(String filter) throws FetchException;
/**
* Query for Storable instances against an explicitly constructed filter
* object.
*
* @param filter query filter
* @throws FetchException if storage layer throws an exception
* @throws IllegalArgumentException if filter is null
* @throws UnsupportedOperationException if given filter is unsupported by repository
*/
Query<S> query(Filter<S> filter) throws FetchException;
/**
* Attempts to quickly delete all Storables instances in this
* Storage. Support for transactional truncation is not guaranteed.
*
* <p>If this Storage has any registered triggers which act on deletes, all
* Storables are deleted via {@code query().deleteAll()} instead to ensure
* these triggers get run.
*
* @since 1.2
*/
void truncate() throws PersistException;
/**
* Register a trigger which will be called for overridden methods in the given
* trigger implementation. The newly added trigger is invoked before and
* after all other triggers. In other words, it is added at the outermost
* nesting level.
*
* @return true if trigger was added, false if trigger was not added
* because an equal trigger is already registered
* @throws IllegalArgumentException if trigger is null
*/
boolean addTrigger(Trigger<? super S> trigger);
/**
* Remove a trigger which was registered earlier.
*
* @return true if trigger instance was removed, false if not registered
* @throws IllegalArgumentException if trigger is null
*/
boolean removeTrigger(Trigger<? super S> trigger);
}