Bumping manifests a=b2g-bump
[gecko.git] / dom / indexedDB / IDBKeyRange.cpp
blob7c69077a01a600ceff9dd116cf7def1971a196b0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "IDBKeyRange.h"
11 #include "nsIXPConnect.h"
13 #include "nsJSUtils.h"
14 #include "nsThreadUtils.h"
15 #include "nsContentUtils.h"
16 #include "nsDOMClassInfoID.h"
17 #include "Key.h"
19 #include "mozilla/dom/IDBKeyRangeBinding.h"
20 #include "mozilla/dom/indexedDB/PIndexedDBIndex.h"
21 #include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h"
23 using namespace mozilla;
24 using namespace mozilla::dom;
25 USING_INDEXEDDB_NAMESPACE
26 using namespace mozilla::dom::indexedDB::ipc;
28 namespace {
30 inline nsresult
31 GetKeyFromJSVal(JSContext* aCx,
32 JS::Handle<JS::Value> aVal,
33 Key& aKey,
34 bool aAllowUnset = false)
36 nsresult rv = aKey.SetFromJSVal(aCx, aVal);
37 if (NS_FAILED(rv)) {
38 NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
39 "Bad error code!");
40 return rv;
43 if (aKey.IsUnset() && !aAllowUnset) {
44 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
47 return NS_OK;
50 } // anonymous namespace
52 // static
53 nsresult
54 IDBKeyRange::FromJSVal(JSContext* aCx,
55 JS::Handle<JS::Value> aVal,
56 IDBKeyRange** aKeyRange)
58 nsRefPtr<IDBKeyRange> keyRange;
60 if (aVal.isNullOrUndefined()) {
61 // undefined and null returns no IDBKeyRange.
62 keyRange.forget(aKeyRange);
63 return NS_OK;
66 JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
67 if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) ||
68 JS_ObjectIsDate(aCx, obj)) {
69 // A valid key returns an 'only' IDBKeyRange.
70 keyRange = new IDBKeyRange(nullptr, false, false, true);
72 nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
73 if (NS_FAILED(rv)) {
74 return rv;
77 else {
78 MOZ_ASSERT(aVal.isObject());
79 // An object is not permitted unless it's another IDBKeyRange.
80 if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) {
81 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
85 keyRange.forget(aKeyRange);
86 return NS_OK;
89 // static
90 template <class T>
91 already_AddRefed<IDBKeyRange>
92 IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange)
94 nsRefPtr<IDBKeyRange> keyRange =
95 new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
96 aKeyRange.isOnly());
97 keyRange->Lower() = aKeyRange.lower();
98 if (!keyRange->IsOnly()) {
99 keyRange->Upper() = aKeyRange.upper();
101 return keyRange.forget();
104 template <class T>
105 void
106 IDBKeyRange::ToSerializedKeyRange(T& aKeyRange)
108 aKeyRange.lowerOpen() = IsLowerOpen();
109 aKeyRange.upperOpen() = IsUpperOpen();
110 aKeyRange.isOnly() = IsOnly();
112 aKeyRange.lower() = Lower();
113 if (!IsOnly()) {
114 aKeyRange.upper() = Upper();
118 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
120 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
121 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
122 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
123 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
125 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
126 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal)
127 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal)
128 NS_IMPL_CYCLE_COLLECTION_TRACE_END
130 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
131 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
132 tmp->DropJSObjects();
133 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
135 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
136 NS_INTERFACE_MAP_ENTRY(nsISupports)
137 NS_INTERFACE_MAP_END
139 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
140 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
142 void
143 IDBKeyRange::DropJSObjects()
145 if (!mRooted) {
146 return;
148 mCachedLowerVal = JS::UndefinedValue();
149 mCachedUpperVal = JS::UndefinedValue();
150 mHaveCachedLowerVal = false;
151 mHaveCachedUpperVal = false;
152 mRooted = false;
153 mozilla::DropJSObjects(this);
156 IDBKeyRange::~IDBKeyRange()
158 DropJSObjects();
161 JSObject*
162 IDBKeyRange::WrapObject(JSContext* aCx)
164 return IDBKeyRangeBinding::Wrap(aCx, this);
167 void
168 IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
169 ErrorResult& aRv)
171 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
173 if (!mHaveCachedLowerVal) {
174 if (!mRooted) {
175 mozilla::HoldJSObjects(this);
176 mRooted = true;
179 aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
180 if (aRv.Failed()) {
181 return;
184 mHaveCachedLowerVal = true;
187 JS::ExposeValueToActiveJS(mCachedLowerVal);
188 aResult.set(mCachedLowerVal);
191 void
192 IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
193 ErrorResult& aRv)
195 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
197 if (!mHaveCachedUpperVal) {
198 if (!mRooted) {
199 mozilla::HoldJSObjects(this);
200 mRooted = true;
203 aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
204 if (aRv.Failed()) {
205 return;
208 mHaveCachedUpperVal = true;
211 JS::ExposeValueToActiveJS(mCachedUpperVal);
212 aResult.set(mCachedUpperVal);
215 // static
216 already_AddRefed<IDBKeyRange>
217 IDBKeyRange::Only(const GlobalObject& aGlobal,
218 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
220 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
222 nsRefPtr<IDBKeyRange> keyRange =
223 new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
225 aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
226 if (aRv.Failed()) {
227 return nullptr;
230 return keyRange.forget();
233 // static
234 already_AddRefed<IDBKeyRange>
235 IDBKeyRange::LowerBound(const GlobalObject& aGlobal,
236 JS::Handle<JS::Value> aValue, bool aOpen,
237 ErrorResult& aRv)
239 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
241 nsRefPtr<IDBKeyRange> keyRange =
242 new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
244 aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
245 if (aRv.Failed()) {
246 return nullptr;
249 return keyRange.forget();
252 // static
253 already_AddRefed<IDBKeyRange>
254 IDBKeyRange::UpperBound(const GlobalObject& aGlobal,
255 JS::Handle<JS::Value> aValue, bool aOpen,
256 ErrorResult& aRv)
258 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
260 nsRefPtr<IDBKeyRange> keyRange =
261 new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
263 aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Upper());
264 if (aRv.Failed()) {
265 return nullptr;
268 return keyRange.forget();
271 // static
272 already_AddRefed<IDBKeyRange>
273 IDBKeyRange::Bound(const GlobalObject& aGlobal,
274 JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper,
275 bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv)
277 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
279 nsRefPtr<IDBKeyRange> keyRange =
280 new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
282 aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower());
283 if (aRv.Failed()) {
284 return nullptr;
287 aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper());
288 if (aRv.Failed()) {
289 return nullptr;
292 if (keyRange->Lower() > keyRange->Upper() ||
293 (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
294 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
295 return nullptr;
298 return keyRange.forget();
301 // Explicitly instantiate for all our key range types... Grumble.
302 template already_AddRefed<IDBKeyRange>
303 IDBKeyRange::FromSerializedKeyRange<KeyRange> (const KeyRange& aKeyRange);
305 template void
306 IDBKeyRange::ToSerializedKeyRange<KeyRange> (KeyRange& aKeyRange);