dom/indexedDB/IDBKeyRange.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/indexedDB/IDBKeyRange.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,306 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "base/basictypes.h"
    1.11 +
    1.12 +#include "IDBKeyRange.h"
    1.13 +
    1.14 +#include "nsIXPConnect.h"
    1.15 +
    1.16 +#include "nsJSUtils.h"
    1.17 +#include "nsThreadUtils.h"
    1.18 +#include "nsContentUtils.h"
    1.19 +#include "nsDOMClassInfoID.h"
    1.20 +#include "Key.h"
    1.21 +
    1.22 +#include "mozilla/dom/IDBKeyRangeBinding.h"
    1.23 +#include "mozilla/dom/indexedDB/PIndexedDBIndex.h"
    1.24 +#include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h"
    1.25 +
    1.26 +using namespace mozilla;
    1.27 +using namespace mozilla::dom;
    1.28 +USING_INDEXEDDB_NAMESPACE
    1.29 +using namespace mozilla::dom::indexedDB::ipc;
    1.30 +
    1.31 +namespace {
    1.32 +
    1.33 +inline nsresult
    1.34 +GetKeyFromJSVal(JSContext* aCx,
    1.35 +                JS::Handle<JS::Value> aVal,
    1.36 +                Key& aKey,
    1.37 +                bool aAllowUnset = false)
    1.38 +{
    1.39 +  nsresult rv = aKey.SetFromJSVal(aCx, aVal);
    1.40 +  if (NS_FAILED(rv)) {
    1.41 +    NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
    1.42 +                 "Bad error code!");
    1.43 +    return rv;
    1.44 +  }
    1.45 +
    1.46 +  if (aKey.IsUnset() && !aAllowUnset) {
    1.47 +    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1.48 +  }
    1.49 +
    1.50 +  return NS_OK;
    1.51 +}
    1.52 +
    1.53 +} // anonymous namespace
    1.54 +
    1.55 +// static
    1.56 +nsresult
    1.57 +IDBKeyRange::FromJSVal(JSContext* aCx,
    1.58 +                       JS::Handle<JS::Value> aVal,
    1.59 +                       IDBKeyRange** aKeyRange)
    1.60 +{
    1.61 +  nsRefPtr<IDBKeyRange> keyRange;
    1.62 +
    1.63 +  if (aVal.isNullOrUndefined()) {
    1.64 +    // undefined and null returns no IDBKeyRange.
    1.65 +    keyRange.forget(aKeyRange);
    1.66 +    return NS_OK;
    1.67 +  }
    1.68 +
    1.69 +  JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
    1.70 +  if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) ||
    1.71 +      JS_ObjectIsDate(aCx, obj)) {
    1.72 +    // A valid key returns an 'only' IDBKeyRange.
    1.73 +    keyRange = new IDBKeyRange(nullptr, false, false, true);
    1.74 +
    1.75 +    nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
    1.76 +    if (NS_FAILED(rv)) {
    1.77 +      return rv;
    1.78 +    }
    1.79 +  }
    1.80 +  else {
    1.81 +    MOZ_ASSERT(aVal.isObject());
    1.82 +    // An object is not permitted unless it's another IDBKeyRange.
    1.83 +    if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) {
    1.84 +      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1.85 +    }
    1.86 +  }
    1.87 +
    1.88 +  keyRange.forget(aKeyRange);
    1.89 +  return NS_OK;
    1.90 +}
    1.91 +
    1.92 +// static
    1.93 +template <class T>
    1.94 +already_AddRefed<IDBKeyRange>
    1.95 +IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange)
    1.96 +{
    1.97 +  nsRefPtr<IDBKeyRange> keyRange =
    1.98 +    new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
    1.99 +                    aKeyRange.isOnly());
   1.100 +  keyRange->Lower() = aKeyRange.lower();
   1.101 +  if (!keyRange->IsOnly()) {
   1.102 +    keyRange->Upper() = aKeyRange.upper();
   1.103 +  }
   1.104 +  return keyRange.forget();
   1.105 +}
   1.106 +
   1.107 +template <class T>
   1.108 +void
   1.109 +IDBKeyRange::ToSerializedKeyRange(T& aKeyRange)
   1.110 +{
   1.111 +  aKeyRange.lowerOpen() = IsLowerOpen();
   1.112 +  aKeyRange.upperOpen() = IsUpperOpen();
   1.113 +  aKeyRange.isOnly() = IsOnly();
   1.114 +
   1.115 +  aKeyRange.lower() = Lower();
   1.116 +  if (!IsOnly()) {
   1.117 +    aKeyRange.upper() = Upper();
   1.118 +  }
   1.119 +}
   1.120 +
   1.121 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
   1.122 +
   1.123 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
   1.124 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
   1.125 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   1.126 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.127 +
   1.128 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
   1.129 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal)
   1.130 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal)
   1.131 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1.132 +
   1.133 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
   1.134 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
   1.135 +  tmp->DropJSObjects();
   1.136 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.137 +
   1.138 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
   1.139 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.140 +NS_INTERFACE_MAP_END
   1.141 +
   1.142 +NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
   1.143 +NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
   1.144 +
   1.145 +void
   1.146 +IDBKeyRange::DropJSObjects()
   1.147 +{
   1.148 +  if (!mRooted) {
   1.149 +    return;
   1.150 +  }
   1.151 +  mCachedLowerVal = JS::UndefinedValue();
   1.152 +  mCachedUpperVal = JS::UndefinedValue();
   1.153 +  mHaveCachedLowerVal = false;
   1.154 +  mHaveCachedUpperVal = false;
   1.155 +  mRooted = false;
   1.156 +  mozilla::DropJSObjects(this);
   1.157 +}
   1.158 +
   1.159 +IDBKeyRange::~IDBKeyRange()
   1.160 +{
   1.161 +  DropJSObjects();
   1.162 +}
   1.163 +
   1.164 +JSObject*
   1.165 +IDBKeyRange::WrapObject(JSContext* aCx)
   1.166 +{
   1.167 +  return IDBKeyRangeBinding::Wrap(aCx, this);
   1.168 +}
   1.169 +
   1.170 +void
   1.171 +IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.172 +                      ErrorResult& aRv)
   1.173 +{
   1.174 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.175 +
   1.176 +  if (!mHaveCachedLowerVal) {
   1.177 +    if (!mRooted) {
   1.178 +      mozilla::HoldJSObjects(this);
   1.179 +      mRooted = true;
   1.180 +    }
   1.181 +
   1.182 +    aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
   1.183 +    if (aRv.Failed()) {
   1.184 +      return;
   1.185 +    }
   1.186 +
   1.187 +    mHaveCachedLowerVal = true;
   1.188 +  }
   1.189 +
   1.190 +  JS::ExposeValueToActiveJS(mCachedLowerVal);
   1.191 +  aResult.set(mCachedLowerVal);
   1.192 +}
   1.193 +
   1.194 +void
   1.195 +IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.196 +                      ErrorResult& aRv)
   1.197 +{
   1.198 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.199 +
   1.200 +  if (!mHaveCachedUpperVal) {
   1.201 +    if (!mRooted) {
   1.202 +      mozilla::HoldJSObjects(this);
   1.203 +      mRooted = true;
   1.204 +    }
   1.205 +
   1.206 +    aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
   1.207 +    if (aRv.Failed()) {
   1.208 +      return;
   1.209 +    }
   1.210 +
   1.211 +    mHaveCachedUpperVal = true;
   1.212 +  }
   1.213 +
   1.214 +  JS::ExposeValueToActiveJS(mCachedUpperVal);
   1.215 +  aResult.set(mCachedUpperVal);
   1.216 +}
   1.217 +
   1.218 +// static
   1.219 +already_AddRefed<IDBKeyRange>
   1.220 +IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
   1.221 +                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
   1.222 +{
   1.223 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.224 +
   1.225 +  nsRefPtr<IDBKeyRange> keyRange =
   1.226 +    new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
   1.227 +
   1.228 +  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
   1.229 +  if (aRv.Failed()) {
   1.230 +    return nullptr;
   1.231 +  }
   1.232 +
   1.233 +  return keyRange.forget();
   1.234 +}
   1.235 +
   1.236 +// static
   1.237 +already_AddRefed<IDBKeyRange>
   1.238 +IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
   1.239 +                        JS::Handle<JS::Value> aValue, bool aOpen,
   1.240 +                        ErrorResult& aRv)
   1.241 +{
   1.242 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.243 +
   1.244 +  nsRefPtr<IDBKeyRange> keyRange =
   1.245 +    new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
   1.246 +
   1.247 +  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
   1.248 +  if (aRv.Failed()) {
   1.249 +    return nullptr;
   1.250 +  }
   1.251 +
   1.252 +  return keyRange.forget();
   1.253 +}
   1.254 +
   1.255 +// static
   1.256 +already_AddRefed<IDBKeyRange>
   1.257 +IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
   1.258 +                        JS::Handle<JS::Value> aValue, bool aOpen,
   1.259 +                        ErrorResult& aRv)
   1.260 +{
   1.261 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.262 +
   1.263 +  nsRefPtr<IDBKeyRange> keyRange =
   1.264 +    new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
   1.265 +
   1.266 +  aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper());
   1.267 +  if (aRv.Failed()) {
   1.268 +    return nullptr;
   1.269 +  }
   1.270 +
   1.271 +  return keyRange.forget();
   1.272 +}
   1.273 +
   1.274 +// static
   1.275 +already_AddRefed<IDBKeyRange>
   1.276 +IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx,
   1.277 +                   JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper,
   1.278 +                   bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv)
   1.279 +{
   1.280 +  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   1.281 +
   1.282 +  nsRefPtr<IDBKeyRange> keyRange =
   1.283 +    new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
   1.284 +
   1.285 +  aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower());
   1.286 +  if (aRv.Failed()) {
   1.287 +    return nullptr;
   1.288 +  }
   1.289 +
   1.290 +  aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper());
   1.291 +  if (aRv.Failed()) {
   1.292 +    return nullptr;
   1.293 +  }
   1.294 +
   1.295 +  if (keyRange->Lower() > keyRange->Upper() ||
   1.296 +      (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
   1.297 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   1.298 +    return nullptr;
   1.299 +  }
   1.300 +
   1.301 +  return keyRange.forget();
   1.302 +}
   1.303 +
   1.304 +// Explicitly instantiate for all our key range types... Grumble.
   1.305 +template already_AddRefed<IDBKeyRange>
   1.306 +IDBKeyRange::FromSerializedKeyRange<KeyRange> (const KeyRange& aKeyRange);
   1.307 +
   1.308 +template void
   1.309 +IDBKeyRange::ToSerializedKeyRange<KeyRange> (KeyRange& aKeyRange);

mercurial