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); }
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; } }
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); } }
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); } }