Rename OptionsObject to Dictionary
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBObjectStore.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBObjectStore.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMStringList.h"
32 #include "IDBAny.h"
33 #include "IDBDatabaseException.h"
34 #include "IDBIndex.h"
35 #include "IDBKey.h"
36 #include "IDBKeyPath.h"
37 #include "IDBKeyRange.h"
38 #include "IDBTracing.h"
39 #include "IDBTransaction.h"
40 #include "SerializedScriptValue.h"
41 #include <wtf/UnusedParam.h>
42
43 namespace WebCore {
44
45 static const unsigned short defaultDirection = IDBCursor::NEXT;
46
47 IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
48     : m_backend(idbObjectStore)
49     , m_transaction(transaction)
50 {
51     ASSERT(m_backend);
52     ASSERT(m_transaction);
53     // We pass a reference to this object before it can be adopted.
54     relaxAdoptionRequirement();
55 }
56
57 String IDBObjectStore::name() const
58 {
59     IDB_TRACE("IDBObjectStore::name");
60     return m_backend->name();
61 }
62
63 String IDBObjectStore::keyPath() const
64 {
65     IDB_TRACE("IDBObjectStore::keyPath");
66     return m_backend->keyPath();
67 }
68
69 PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
70 {
71     IDB_TRACE("IDBObjectStore::indexNames");
72     return m_backend->indexNames();
73 }
74
75 IDBTransaction* IDBObjectStore::transaction() const
76 {
77     IDB_TRACE("IDBObjectStore::transaction");
78     return m_transaction.get();
79 }
80
81 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
82 {
83     IDB_TRACE("IDBObjectStore::get");
84     if (key && (key->type() == IDBKey::InvalidType)) {
85         ec = IDBDatabaseException::DATA_ERR;
86         return 0;
87     }
88
89     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
90     m_backend->get(key, request, m_transaction->backend(), ec);
91     if (ec) {
92         request->markEarlyDeath();
93         return 0;
94     }
95     return request.release();
96 }
97
98 PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
99 {
100     IDB_TRACE("IDBObjectStore::add");
101     if (key && (key->type() == IDBKey::InvalidType)) {
102         ec = IDBDatabaseException::DATA_ERR;
103         return 0;
104     }
105
106     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
107     m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOnly, request, m_transaction->backend(), ec);
108     if (ec) {
109         request->markEarlyDeath();
110         return 0;
111     }
112     return request.release();
113 }
114
115 PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
116 {
117     IDB_TRACE("IDBObjectStore::put");
118     if (key && (key->type() == IDBKey::InvalidType)) {
119         ec = IDBDatabaseException::DATA_ERR;
120         return 0;
121     }
122
123     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
124     m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOrUpdate, request, m_transaction->backend(), ec);
125     if (ec) {
126         request->markEarlyDeath();
127         return 0;
128     }
129     return request.release();
130 }
131
132 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
133 {
134     IDB_TRACE("IDBObjectStore::delete");
135     if (!keyRange) {
136         ec = IDBDatabaseException::DATA_ERR;
137         return 0;
138     }
139
140     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
141     m_backend->deleteFunction(keyRange, request, m_transaction->backend(), ec);
142     if (ec) {
143         request->markEarlyDeath();
144         return 0;
145     }
146     return request.release();
147 }
148
149 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
150 {
151     IDB_TRACE("IDBObjectStore::delete");
152     if (!key || !key->valid()) {
153         ec = IDBDatabaseException::DATA_ERR;
154         return 0;
155     }
156
157     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
158     m_backend->deleteFunction(key, request, m_transaction->backend(), ec);
159     if (ec) {
160         request->markEarlyDeath();
161         return 0;
162     }
163     return request.release();
164 }
165
166 PassRefPtr<IDBRequest> IDBObjectStore::clear(ScriptExecutionContext* context, ExceptionCode& ec)
167 {
168     IDB_TRACE("IDBObjectStore::clear");
169     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
170     m_backend->clear(request, m_transaction->backend(), ec);
171     if (ec) {
172         request->markEarlyDeath();
173         return 0;
174     }
175     return request.release();
176 }
177
178 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, const Dictionary& options, ExceptionCode& ec)
179 {
180     IDB_TRACE("IDBObjectStore::createIndex");
181     if (!IDBIsValidKeyPath(keyPath)) {
182         ec = IDBDatabaseException::NON_TRANSIENT_ERR;
183         return 0;
184     }
185
186     bool unique = false;
187     options.get("unique", unique);
188
189     bool multiEntry = false;
190     options.get("multiEntry", multiEntry);
191
192     // FIXME: When Array-type keyPaths are supported, throw exception if keyPath is Array and multiEntry is true.
193
194     RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->createIndex(name, keyPath, unique, multiEntry, m_transaction->backend(), ec);
195     ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
196     if (!indexBackend)
197         return 0;
198     RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
199     m_indexMap.set(name, index);
200     return index.release();
201 }
202
203 PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec)
204 {
205     IDB_TRACE("IDBObjectStore::index");
206     if (m_transaction->finished()) {
207         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
208         return 0;
209     }
210
211     IDBIndexMap::iterator it = m_indexMap.find(name);
212     if (it != m_indexMap.end())
213         return it->second;
214
215     RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->index(name, ec);
216     ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
217     if (!indexBackend)
218         return 0;
219
220     RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
221     m_indexMap.set(name, index);
222     return index.release();
223 }
224
225 void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec)
226 {
227     m_backend->deleteIndex(name, m_transaction->backend(), ec);
228 }
229
230 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction, ExceptionCode& ec)
231 {
232     IDB_TRACE("IDBObjectStore::openCursor");
233     if (direction != IDBCursor::NEXT && direction != IDBCursor::NEXT_NO_DUPLICATE && direction != IDBCursor::PREV && direction != IDBCursor::PREV_NO_DUPLICATE) {
234         // FIXME: May need to change when specced: http://www.w3.org/Bugs/Public/show_bug.cgi?id=11406
235         ec = IDBDatabaseException::CONSTRAINT_ERR;
236         return 0;
237     }
238
239     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
240     request->setCursorType(IDBCursorBackendInterface::ObjectStoreCursor);
241     m_backend->openCursor(range, direction, request, m_transaction->backend(), ec);
242     if (ec) {
243         request->markEarlyDeath();
244         return 0;
245     }
246     return request.release();
247 }
248
249 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, ExceptionCode& ec)
250 {
251     IDB_TRACE("IDBObjectStore::count");
252     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
253     m_backend->count(range, request, m_transaction->backend(), ec);
254     if (ec) {
255         request->markEarlyDeath();
256         return 0;
257     }
258     return request.release();
259 }
260
261 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
262 {
263     IDB_TRACE("IDBObjectStore::count");
264     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
265     if (ec)
266         return 0;
267     return count(context, keyRange.release(), ec);
268 }
269
270 void IDBObjectStore::transactionFinished()
271 {
272     ASSERT(m_transaction->finished());
273
274     // Break reference cycles.
275     m_indexMap.clear();
276 }
277
278
279 } // namespace WebCore
280
281 #endif // ENABLE(INDEXED_DATABASE)