summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/Storage.java
blob: 8bcd6bca891d8979ae177cb3d08db3ed4d12030a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * Copyright 2006 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&lt;UserInfo&gt; 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&lt;UserInfo&gt; 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           = "=" | "!=" | "&lt;" | "&gt;=" | "&gt;" | "&lt;="
     * 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);
}