Example #1
0
        private JsValue LoadDocument(JsValue self, JsValue[] args)
        {
            if (args.Length != 2)
            {
                throw new ArgumentException("The load(id, collection) method expects two arguments, but got: " + args.Length);
            }

            if (args[0].IsNull() || args[0].IsUndefined())
            {
                return(JsValue.Undefined);
            }

            if (args[0].IsString() == false ||
                args[1].IsString() == false)
            {
                throw new ArgumentException($"The load(id, collection) method expects two string arguments, but got: load({args[0]}, {args[1]})");
            }

            object doc = CurrentIndexingScope.Current.LoadDocument(null, args[0].AsString(), args[1].AsString());

            if (JavaScriptIndexUtils.GetValue(_engine, doc, out var item))
            {
                return(item);
            }

            return(JsValue.Undefined);
        }
        public IEnumerable IndexingFunction(IEnumerable <object> items)
        {
            try
            {
                foreach (var item in items)
                {
                    _engine.ResetCallStack();
                    _engine.ResetStatementsCount();
                    _engine.ResetTimeoutTicks();

                    if (JavaScriptIndexUtils.GetValue(_engine, item, out JsValue jsItem) == false)
                    {
                        continue;
                    }
                    {
                        _oneItemArray[0] = jsItem;
                        try
                        {
                            jsItem = MapFunc.Call(JsValue.Null, _oneItemArray);
                        }catch (JavaScriptException jse)
                        {
                            var(message, success) = JavaScriptIndexFuncException.PrepareErrorMessageForJavaScriptIndexFuncException(MapString, jse);
                            if (success == false)
                            {
                                throw new JavaScriptIndexFuncException($"Failed to execute {MapString}", jse);
                            }
                            throw new JavaScriptIndexFuncException($"Failed to execute map script, {message}", jse);
                        } catch (Exception e)
                        {
                            throw new JavaScriptIndexFuncException($"Failed to execute {MapString}", e);
                        }
                        if (jsItem.IsArray())
                        {
                            var array = jsItem.AsArray();
                            foreach (var(prop, val) in array.GetOwnProperties())
                            {
                                if (prop == "length")
                                {
                                    continue;
                                }
                                yield return(val.Value);
                            }
                        }
                        else if (jsItem.IsObject())
                        {
                            yield return(jsItem.AsObject());
                        }
                        // we ignore everything else by design, we support only
                        // objects and arrays, anything else is discarded
                    }

                    _resolver.ExplodeArgsOn(null, null);
                }
            }
            finally
            {
                _oneItemArray[0] = null;
            }
        }
        public void Analyze(Engine engine)
        {
            HasDynamicReturns = false;

            if (!(MapFunc is ScriptFunctionInstance sfi))
            {
                return;
            }

            var theFuncAst = sfi.GetFunctionAst();

            var res = CheckIfSimpleMapExpression(engine, theFuncAst);

            if (res != null)
            {
                MapFunc    = res.Value.Function;
                theFuncAst = res.Value.FunctionAst;
            }
            var loadSearcher = new EsprimaReferencedCollectionVisitor();

            loadSearcher.VisitFunctionExpression(theFuncAst);
            ReferencedCollections.UnionWith(loadSearcher.ReferencedCollection);

            foreach (var returnStatement in JavaScriptIndexUtils.GetReturnStatements(theFuncAst.Body))
            {
                if (returnStatement.Argument == null) // return;
                {
                    continue;
                }

                if (!(returnStatement.Argument is ObjectExpression oe))
                {
                    HasDynamicReturns = true;
                    continue;
                }
                //If we got here we must validate that all return statements have the same structure.
                //Having zero fields means its the first return statements we encounter that has a structure.
                if (Fields.Count == 0)
                {
                    foreach (var prop in oe.Properties)
                    {
                        var fieldName = prop.Key.GetKey();
                        if (fieldName == "_")
                        {
                            HasDynamicReturns = true;
                        }

                        Fields.Add(fieldName);
                    }
                }
                else if (CompareFields(oe) == false)
                {
                    throw new InvalidOperationException($"Index {IndexName} contains different return structure from different code paths," +
                                                        $" expected properties: {string.Join(", ", Fields)} but also got:{string.Join(", ", oe.Properties.Select(x => x.Key.GetKey()))}");
                }
            }
        }
        private JsValue ConstructValues(List <BlittableJsonReaderObject> values)
        {
            var items = new PropertyDescriptor[values.Count];

            for (int j = 0; j < values.Count; j++)
            {
                var val = values[j];

                if (JavaScriptIndexUtils.GetValue(Engine, val, out JsValue jsValue, true) == false)
                {
                    continue;
                }
                items[j] = new PropertyDescriptor(jsValue, true, true, true);
            }
            var jsArray = new ArrayInstance(Engine, items);

            jsArray.Prototype  = Engine.Array.PrototypeObject;
            jsArray.Extensible = false;

            var result = new ObjectInstance(Engine)
            {
                Extensible = true
            };

            result.Put("values", jsArray, false);
            if (_singleField)
            {
                var index = values[0].GetPropertyIndex(_groupByFields[0]);
                if (index != -1)
                {
                    BlittableJsonReaderObject.PropertyDetails prop = default;
                    values[0].GetPropertyByIndex(index, ref prop, addObjectToCache: false);
                    result.Put("key", JsValue.FromObject(Engine, prop.Value), false);
                }
            }
            else
            {
                var key = new ObjectInstance(Engine)
                {
                    Extensible = true
                };
                result.Put("key", key, false);
                for (int i = 0; i < _groupByFields.Length; i++)
                {
                    var index = values[0].GetPropertyIndex(_groupByFields[i]);
                    if (index != -1)
                    {
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values[0].GetPropertyByIndex(index, ref prop, addObjectToCache: false);
                        key.Put(_groupByFields[i], JsValue.FromObject(Engine, prop.Value), false);
                    }
                }
            }
            return(result);
        }
Example #5
0
        public void Analyze(Engine engine)
        {
            HasDynamicReturns = false;
            HasBoostedFields  = false;

            IFunction theFuncAst;

            switch (MapFunc)
            {
            case ArrowFunctionInstance afi:
                theFuncAst = afi.FunctionDeclaration;
                break;

            case ScriptFunctionInstance sfi:
                theFuncAst = sfi.FunctionDeclaration;
                break;

            default:
                return;
            }

            var res = CheckIfSimpleMapExpression(engine, theFuncAst);

            if (res != null)
            {
                MapFunc    = res.Value.Function;
                theFuncAst = res.Value.FunctionAst;
            }

            foreach (var returnStatement in JavaScriptIndexUtils.GetReturnStatements(theFuncAst))
            {
                if (returnStatement.Argument == null) // return;
                {
                    continue;
                }

                switch (returnStatement.Argument)
                {
                case ObjectExpression oe:

                    //If we got here we must validate that all return statements have the same structure.
                    //Having zero fields means its the first return statements we encounter that has a structure.
                    if (Fields.Count == 0)
                    {
                        foreach (var prop in oe.Properties)
                        {
                            if (prop is Property property)
                            {
                                var fieldName         = property.GetKey(engine);
                                var fieldNameAsString = fieldName.AsString();
                                if (fieldName == "_")
                                {
                                    HasDynamicReturns = true;
                                }

                                Fields.Add(fieldNameAsString);

                                var fieldValue = property.Value;
                                if (IsBoostExpression(fieldValue))
                                {
                                    HasBoostedFields = true;
                                }
                            }
                        }
                    }
                    else if (CompareFields(oe) == false)
                    {
                        throw new InvalidOperationException($"Index {IndexName} contains different return structure from different code paths," +
                                                            $" expected properties: {string.Join(", ", Fields)} but also got:{string.Join(", ", oe.Properties.Select(x => x.GetKey(engine)))}");
                    }

                    break;

                case CallExpression ce:

                    if (IsBoostExpression(ce))
                    {
                        HasBoostedFields = true;
                    }
                    else
                    {
                        HasDynamicReturns = true;
                    }

                    break;

                default:
                    HasDynamicReturns = true;
                    break;
                }
            }
Example #6
0
        private JsValue ConstructGrouping(List <BlittableJsonReaderObject> values)
        {
            var jsValues = ConstructValues();
            var jsKey    = ConstructKey();

            var result = new ObjectInstance(Engine)
            {
                Extensible = true
            };

            result.Put("values", jsValues, false);
            result.Put("key", jsKey, false);

            return(result);

            JsValue ConstructKey()
            {
                if (_singleField)
                {
                    var index = values[0].GetPropertyIndex(_groupByFields[0].Name);
                    if (index != -1)
                    {
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values[0].GetPropertyByIndex(index, ref prop);

                        return(JsValue.FromObject(Engine, prop.Value));
                    }

                    return(JsValue.Null);
                }

                var key = new ObjectInstance(Engine)
                {
                    Extensible = true
                };

                foreach (var groupByField in _groupByFields)
                {
                    var index = values[0].GetPropertyIndex(groupByField.Name);
                    if (index != -1)
                    {
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values[0].GetPropertyByIndex(index, ref prop);

                        var propertyName = groupByField.Name;
                        if (groupByField is JsNestedField jsnf)
                        {
                            propertyName = jsnf.PropertyName;
                        }

                        var value = groupByField.GetValue(null, prop.Value);

                        key.Put(propertyName, JsValue.FromObject(Engine, value), throwOnError: false);
                    }
                }

                return(key);
            }

            ArrayInstance ConstructValues()
            {
                var items = new PropertyDescriptor[values.Count];

                for (var i = 0; i < values.Count; i++)
                {
                    var val = values[i];

                    if (JavaScriptIndexUtils.GetValue(Engine, val, out var jsValue, isMapReduce: true) == false)
                    {
                        continue;
                    }

                    items[i] = new PropertyDescriptor(jsValue, true, true, true);
                }

                var jsArray = new ArrayInstance(Engine, items)
                {
                    Prototype  = Engine.Array.PrototypeObject,
                    Extensible = false
                };

                return(jsArray);
            }
        }
Example #7
0
        private JsValue ConstructGrouping(List <BlittableJsonReaderObject> values)
        {
            var jsValues = ConstructValues();
            var jsKey    = ConstructKey();

            var result = new ObjectInstance(Engine)
            {
                Extensible = true
            };

            result.Put("values", jsValues, false);
            result.Put("key", jsKey, false);

            return(result);

            JsValue ConstructKey()
            {
                if (_singleField)
                {
                    var index = values[0].GetPropertyIndex(_groupByFields[0].Name);
                    if (index != -1)
                    {
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values[0].GetPropertyByIndex(index, ref prop);

                        return(JsValue.FromObject(Engine, prop.Value));
                    }

                    return(JsValue.Null);
                }

                var key = new ObjectInstance(Engine)
                {
                    Extensible = true
                };

                foreach (var groupByField in _groupByFields)
                {
                    var index = values[0].GetPropertyIndex(groupByField.Name);
                    if (index != -1)
                    {
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values[0].GetPropertyByIndex(index, ref prop);

                        var propertyName = groupByField.Name;
                        if (groupByField is JsNestedField jsnf)
                        {
                            propertyName = jsnf.PropertyName;
                        }

                        var value = groupByField.GetValue(null, prop.Value);

                        JsValue jsValue = value switch
                        {
                            BlittableJsonReaderObject bjro => new BlittableObjectInstance(Engine, null, bjro, null, null, null),
                            Document doc => new BlittableObjectInstance(Engine, null, doc.Data, doc),
                            LazyStringValue lsv => new JsString(lsv.ToString()),
                            LazyCompressedStringValue lcsv => new JsString(lcsv.ToString()),
                            LazyNumberValue lnv => new JsNumber(lnv.ToDouble(CultureInfo.InvariantCulture)),
                            _ => JsValue.FromObject(Engine, value)
                        };

                        key.Put(propertyName, jsValue, throwOnError: false);
                    }
                }

                return(key);
            }

            ArrayInstance ConstructValues()
            {
                var items = new PropertyDescriptor[values.Count];

                for (var i = 0; i < values.Count; i++)
                {
                    var val = values[i];

                    if (JavaScriptIndexUtils.GetValue(Engine, val, out var jsValue, isMapReduce: true) == false)
                    {
                        continue;
                    }

                    items[i] = new PropertyDescriptor(jsValue, true, true, true);
                }

                var jsArray = new ArrayInstance(Engine, items)
                {
                    Prototype  = Engine.Array.PrototypeObject,
                    Extensible = false
                };

                return(jsArray);
            }
        }