Ejemplo n.º 1
0
        public bool TryGet(string key, RealmObjectBase.Metadata metadata, Realm realm, out RealmValue value)
        {
            RealmValue keyValue = key;

            var(primitiveKey, keyHandles) = keyValue.ToNative();
            var containsValue = NativeMethods.try_get_value(this, primitiveKey, out var result, out var nativeException);

            keyHandles?.Dispose();
            nativeException.ThrowIfNecessary();

            if (!containsValue)
            {
                value = default;
                return(false);
            }

            if (result.Type != RealmValueType.Object)
            {
                value = new RealmValue(result);
            }
            else
            {
                var objectHandle = result.AsObject(Root);

                if (metadata == null)
                {
                    throw new NotImplementedException("Mixed objects are not supported yet.");
                }

                value = new RealmValue(realm.MakeObject(metadata, objectHandle));
            }

            return(true);
        }
        public T this[int index]
        {
            get
            {
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(index));
                }

                switch (_argumentType)
                {
                case PropertyType.Object | PropertyType.Nullable:
                    var objectPtr = Handle.Value.GetObjectAtIndex(index);
                    if (objectPtr == IntPtr.Zero)
                    {
                        throw new ArgumentOutOfRangeException(nameof(index));
                    }

                    return(Operator.Convert <RealmObject, T>(Realm.MakeObject(Metadata, objectPtr)));

                case PropertyType.String:
                case PropertyType.String | PropertyType.Nullable:
                    return(Operator.Convert <string, T>(Handle.Value.GetStringAtIndex(index)));

                case PropertyType.Data:
                case PropertyType.Data | PropertyType.Nullable:
                    return(Operator.Convert <byte[], T>(Handle.Value.GetByteArrayAtIndex(index)));

                default:
                    return(Handle.Value.GetPrimitiveAtIndex(index, _argumentType).Get <T>());
                }
            }
        }
Ejemplo n.º 3
0
        public T GetObject <T>(Realm realm, IntPtr propertyIndex, string objectType) where T : RealmObject
        {
            if (TryGetLink(propertyIndex, out var objectHandle))
            {
                return((T)realm.MakeObject(realm.Metadata[objectType], objectHandle));
            }

            return(null);
        }
Ejemplo n.º 4
0
        public T GetObject <T>(Realm realm, IntPtr propertyIndex, string objectType) where T : RealmObject
        {
            var linkedObjectPtr = this.GetLink(propertyIndex);

            if (linkedObjectPtr == IntPtr.Zero)
            {
                return(null);
            }

            return((T)realm.MakeObject(objectType, linkedObjectPtr));
        }
Ejemplo n.º 5
0
        internal T this[int index]
        {
            get
            {
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException();
                }

                var objectPtr = ResultsHandle.GetObject(index);
                return((T)(object)_realm.MakeObject(_targetMetadata, objectPtr));
            }
        }
        public RealmValue GetValueAtIndex(int index, RealmObjectBase.Metadata metadata, Realm realm)
        {
            GetValueAtIndexCore((IntPtr)index, out var result, out var nativeException);
            nativeException.ThrowIfNecessary();

            if (result.Type != RealmValueType.Object)
            {
                return(new RealmValue(result));
            }

            var objectHandle = result.AsObject(Root);

            return(new RealmValue(realm.MakeObject(metadata, objectHandle)));
        }
        protected RealmValue ToRealmValue(PrimitiveValue primitive, RealmObjectBase.Metadata metadata, Realm realm)
        {
            if (primitive.Type != RealmValueType.Object)
            {
                return(new RealmValue(primitive));
            }

            var objectHandle = primitive.AsObject(Root);

            if (metadata == null)
            {
                throw new NotImplementedException("Mixed objects are not supported yet.");
            }

            return(new RealmValue(realm.MakeObject(metadata, objectHandle)));
        }
Ejemplo n.º 8
0
        protected T GetObjectValue <T>(string propertyName) where T : RealmObject
        {
            Debug.Assert(IsManaged, "Object is not managed, but managed access was attempted");

            var linkedObjectPtr = _objectHandle.GetLink(_metadata.PropertyIndices[propertyName]);

            if (linkedObjectPtr == IntPtr.Zero)
            {
                return(null);
            }

            Schema.Property property;
            _metadata.Schema.TryFindProperty(propertyName, out property);
            var objectType = property.ObjectType;

            return((T)_realm.MakeObject(objectType, linkedObjectPtr));
        }
Ejemplo n.º 9
0
        public RealmValue GetValue(string propertyName, RealmObjectBase.Metadata metadata, Realm realm)
        {
            var propertyIndex = metadata.PropertyIndices[propertyName];

            NativeMethods.get_value(this, propertyIndex, out var result, out var nativeException);
            nativeException.ThrowIfNecessary();

            if (result.Type != RealmValueType.Object)
            {
                return(new RealmValue(result, this, propertyIndex));
            }

            var objectHandle = result.AsObject(Root);

            metadata.Schema.TryFindProperty(propertyName, out var property);
            return(new RealmValue(realm.MakeObject(realm.Metadata[property.ObjectType], objectHandle)));
        }
Ejemplo n.º 10
0
        public T this[int index]
        {
            get
            {
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException();
                }

                var linkedObjectPtr = _listHandle.Get((IntPtr)index, _realm.SharedRealmHandle);
                return((T)_realm.MakeObject(_targetMetadata, linkedObjectPtr));
            }

            set
            {
                throw new NotSupportedException("Setting items directly is not supported.");
            }
        }
Ejemplo n.º 11
0
        public T this[int index]
        {
            get
            {
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(index));
                }

                var objectPtr = Handle.Value.GetObjectAtIndex(index);
                if (objectPtr == IntPtr.Zero)
                {
                    throw new ArgumentOutOfRangeException(nameof(index));
                }

                return((T)(object)Realm.MakeObject(Metadata, objectPtr));
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        ///  Move the iterator to the next related object, starting "before" the first object.
        /// </summary>
        /// <remarks>
        /// Is a factory for RealmObjects, loading a new one and updating <c>Current</c>.
        /// </remarks>
        /// <returns>True only if can advance.</returns>
        public bool MoveNext()
        {
            if (_enumeratingResults == null)
            {
                return(false);
            }

            ++_index;
            var rowPtr = _enumeratingResults.GetObjectAtIndex(_index);

            if (rowPtr == IntPtr.Zero)
            {
                Current = (T)(object)null;
                return(false);
            }

            Current = (T)(object)_realm.MakeObject(_schema.Name, rowPtr);
            return(true);
        }
        internal override Expression VisitMethodCall(MethodCallExpression m)
        {
            if (m.Method.DeclaringType == typeof(Queryable))
            {
                if (m.Method.Name == nameof(Queryable.Where))
                {
                    Visit(m.Arguments[0]);
                    var lambda = (LambdaExpression)StripQuotes(m.Arguments[1]);
                    Visit(lambda.Body);
                    return(m);
                }

                if (m.Method.Name == nameof(Queryable.OrderBy))
                {
                    Visit(m.Arguments[0]);
                    AddSort((LambdaExpression)StripQuotes(m.Arguments[1]), true, true);
                    return(m);
                }

                if (m.Method.Name == nameof(Queryable.OrderByDescending))
                {
                    Visit(m.Arguments[0]);
                    AddSort((LambdaExpression)StripQuotes(m.Arguments[1]), true, false);
                    return(m);
                }

                if (m.Method.Name == nameof(Queryable.ThenBy))
                {
                    Visit(m.Arguments[0]);
                    AddSort((LambdaExpression)StripQuotes(m.Arguments[1]), false, true);
                    return(m);
                }

                if (m.Method.Name == nameof(Queryable.ThenByDescending))
                {
                    Visit(m.Arguments[0]);
                    AddSort((LambdaExpression)StripQuotes(m.Arguments[1]), false, false);
                    return(m);
                }

                if (m.Method.Name == nameof(Queryable.Count))
                {
                    RecurseToWhereOrRunLambda(m);
                    var foundCount = CoreQueryHandle.Count();
                    return(Expression.Constant(foundCount));
                }

                if (m.Method.Name == nameof(Queryable.Any))
                {
                    RecurseToWhereOrRunLambda(m);
                    var foundAny = CoreQueryHandle.FindDirect(_realm.SharedRealmHandle) != IntPtr.Zero;
                    return(Expression.Constant(foundAny));
                }

                if (m.Method.Name.StartsWith(nameof(Queryable.First)))
                {
                    RecurseToWhereOrRunLambda(m);
                    var firstObjectPtr = IntPtr.Zero;
                    if (OptionalSortDescriptorBuilder == null)
                    {
                        firstObjectPtr = CoreQueryHandle.FindDirect(_realm.SharedRealmHandle);
                    }
                    else
                    {
                        using (ResultsHandle rh = _realm.MakeResultsForQuery(CoreQueryHandle, OptionalSortDescriptorBuilder))
                        {
                            firstObjectPtr = rh.GetObjectAtIndex(0);
                        }
                    }

                    if (firstObjectPtr != IntPtr.Zero)
                    {
                        return(Expression.Constant(_realm.MakeObject(_metadata, firstObjectPtr)));
                    }

                    if (m.Method.Name == nameof(Queryable.First))
                    {
                        throw new InvalidOperationException("Sequence contains no matching element");
                    }

                    Debug.Assert(m.Method.Name == nameof(Queryable.FirstOrDefault), $"The method {m.Method.Name}  is not supported. We expected {nameof(Queryable.FirstOrDefault)}.");
                    return(Expression.Constant(null));
                }

                /*
                 * // FIXME: See discussion in the test DefaultIfEmptyReturnsDefault
                 * // kept because it shows part of what might be a viable implementation if can work out architectural issues
                 *
                 *              if (m.Method.Name == nameof(Queryable.DefaultIfEmpty))
                 *              {
                 *                  RecurseToWhereOrRunLambda(m);
                 *                  IntPtr firstObjectPtr = _coreQueryHandle.FindDirect(IntPtr.Zero);
                 *                  if (firstObjectPtr != IntPtr.Zero)
                 *                      return m;  // as if just a "Where"
                 *                  var innerType = m.Type.GetGenericArguments()[0];
                 *                  var listType = typeof(List<>).MakeGenericType(innerType);
                 *                  var singleNullItemList = Activator.CreateInstance(listType);
                 *                  ((IList)singleNullItemList).Add(null);
                 *                  return Expression.Constant(singleNullItemList);
                 *              }
                 */
                if (m.Method.Name.StartsWith(nameof(Queryable.Single)))  // same as unsorted First with extra checks
                {
                    RecurseToWhereOrRunLambda(m);
                    var firstObjectPtr = CoreQueryHandle.FindDirect(_realm.SharedRealmHandle);
                    if (firstObjectPtr == IntPtr.Zero)
                    {
                        if (m.Method.Name == nameof(Queryable.Single))
                        {
                            throw new InvalidOperationException("Sequence contains no matching element");
                        }

                        Debug.Assert(m.Method.Name == nameof(Queryable.SingleOrDefault), $"The method {m.Method.Name}  is not supported. We expected {nameof(Queryable.SingleOrDefault)}.");
                        return(Expression.Constant(null));
                    }

                    var firstObject   = Realm.CreateObjectHandle(firstObjectPtr, _realm.SharedRealmHandle);
                    var nextObjectPtr = CoreQueryHandle.FindNext(firstObject);
                    if (nextObjectPtr != IntPtr.Zero)
                    {
                        throw new InvalidOperationException("Sequence contains more than one matching element");
                    }

                    return(Expression.Constant(_realm.MakeObject(_metadata, firstObject)));
                }

                if (m.Method.Name.StartsWith(nameof(Queryable.Last)))
                {
                    RecurseToWhereOrRunLambda(m);

                    var lastObjectPtr = IntPtr.Zero;
                    using (ResultsHandle rh = _realm.MakeResultsForQuery(CoreQueryHandle, OptionalSortDescriptorBuilder))
                    {
                        var lastIndex = rh.Count() - 1;
                        if (lastIndex >= 0)
                        {
                            lastObjectPtr = rh.GetObjectAtIndex(lastIndex);
                        }
                    }

                    if (lastObjectPtr != IntPtr.Zero)
                    {
                        return(Expression.Constant(_realm.MakeObject(_metadata, lastObjectPtr)));
                    }

                    if (m.Method.Name == nameof(Queryable.Last))
                    {
                        throw new InvalidOperationException("Sequence contains no matching element");
                    }

                    Debug.Assert(m.Method.Name == nameof(Queryable.LastOrDefault), $"The method {m.Method.Name}  is not supported. We expected {nameof(Queryable.LastOrDefault)}.");
                    return(Expression.Constant(null));
                }

                if (m.Method.Name.StartsWith(nameof(Queryable.ElementAt)))
                {
                    Visit(m.Arguments.First());
                    object argument;
                    if (!TryExtractConstantValue(m.Arguments.Last(), out argument) || argument.GetType() != typeof(int))
                    {
                        throw new NotSupportedException($"The method '{m.Method}' has to be invoked with a single integer constant argument or closure variable");
                    }

                    IntPtr objectPtr;
                    var    index = (int)argument;
                    if (OptionalSortDescriptorBuilder == null)
                    {
                        objectPtr = CoreQueryHandle.FindDirect(_realm.SharedRealmHandle, (IntPtr)index);
                    }
                    else
                    {
                        using (var rh = _realm.MakeResultsForQuery(CoreQueryHandle, OptionalSortDescriptorBuilder))
                        {
                            objectPtr = rh.GetObjectAtIndex(index);
                        }
                    }

                    if (objectPtr != IntPtr.Zero)
                    {
                        var objectHandle = Realm.CreateObjectHandle(objectPtr, _realm.SharedRealmHandle);
                        return(Expression.Constant(_realm.MakeObject(_metadata, objectHandle)));
                    }

                    if (m.Method.Name == nameof(Queryable.ElementAt))
                    {
                        throw new ArgumentOutOfRangeException();
                    }

                    Debug.Assert(m.Method.Name == nameof(Queryable.ElementAtOrDefault), $"The method {m.Method.Name}  is not supported. We expected {nameof(Queryable.ElementAtOrDefault)}.");
                    return(Expression.Constant(null));
                }
            }

            if (m.Method.DeclaringType == typeof(string) ||
                m.Method.DeclaringType == typeof(StringExtensions))
            {
                QueryHandle.Operation <string> queryMethod = null;

                // For extension methods, member should be m.Arguments[0] as MemberExpression;
                MemberExpression member = null;

                // For extension methods, that should be 1
                var stringArgumentIndex = 0;

                if (m.Method == Methods.String.Contains.Value)
                {
                    queryMethod = (q, c, v) => q.StringContains(c, v, caseSensitive: true);
                }
                else if (m.Method == Methods.String.ContainsStringComparison.Value)
                {
                    member = m.Arguments[0] as MemberExpression;
                    stringArgumentIndex = 1;
                    queryMethod         = (q, c, v) => q.StringContains(c, v, GetComparisonCaseSensitive(m));
                }
                else if (m.Method == Methods.String.StartsWith.Value)
                {
                    queryMethod = (q, c, v) => q.StringStartsWith(c, v, caseSensitive: true);
                }
                else if (m.Method == Methods.String.StartsWithStringComparison.Value)
                {
                    queryMethod = (q, c, v) => q.StringStartsWith(c, v, GetComparisonCaseSensitive(m));
                }
                else if (m.Method == Methods.String.EndsWith.Value)
                {
                    queryMethod = (q, c, v) => q.StringEndsWith(c, v, caseSensitive: true);
                }
                else if (m.Method == Methods.String.EndsWithStringComparison.Value)
                {
                    queryMethod = (q, c, v) => q.StringEndsWith(c, v, GetComparisonCaseSensitive(m));
                }
                else if (m.Method == Methods.String.IsNullOrEmpty.Value)
                {
                    member = m.Arguments.SingleOrDefault() as MemberExpression;
                    if (member == null)
                    {
                        throw new NotSupportedException($"The method '{m.Method}' has to be invoked with a RealmObject member");
                    }

                    var columnIndex = CoreQueryHandle.GetColumnIndex(member.Member.Name);

                    CoreQueryHandle.GroupBegin();
                    CoreQueryHandle.NullEqual(columnIndex);
                    CoreQueryHandle.Or();
                    CoreQueryHandle.StringEqual(columnIndex, string.Empty, caseSensitive: true);
                    CoreQueryHandle.GroupEnd();
                    return(m);
                }
                else if (m.Method == Methods.String.EqualsMethod.Value)
                {
                    queryMethod = (q, c, v) => q.StringEqual(c, v, caseSensitive: true);
                }
                else if (m.Method == Methods.String.EqualsStringComparison.Value)
                {
                    queryMethod = (q, c, v) => q.StringEqual(c, v, GetComparisonCaseSensitive(m));
                }
                else if (m.Method == Methods.String.Like.Value)
                {
                    member = m.Arguments[0] as MemberExpression;
                    stringArgumentIndex = 1;
                    object caseSensitive;
                    if (!TryExtractConstantValue(m.Arguments.Last(), out caseSensitive) || !(caseSensitive is bool))
                    {
                        throw new NotSupportedException($"The method '{m.Method}' has to be invoked with a string and boolean constant arguments.");
                    }

                    queryMethod = (q, c, v) => q.StringLike(c, v, (bool)caseSensitive);
                }

                if (queryMethod != null)
                {
                    member = member ?? m.Object as MemberExpression;

                    if (member == null)
                    {
                        throw new NotSupportedException($"The method '{m.Method}' has to be invoked on a RealmObject member");
                    }

                    var columnIndex = CoreQueryHandle.GetColumnIndex(member.Member.Name);

                    object argument;
                    if (!TryExtractConstantValue(m.Arguments[stringArgumentIndex], out argument) ||
                        (argument != null && argument.GetType() != typeof(string)))
                    {
                        throw new NotSupportedException($"The method '{m.Method}' has to be invoked with a single string constant argument or closure variable");
                    }

                    queryMethod(CoreQueryHandle, columnIndex, (string)argument);
                    return(m);
                }
            }

            throw new NotSupportedException($"The method '{m.Method.Name}' is not supported");
        }