public static void ValidateContextDesc( string contextName, ContextSpecHash hashedSpec, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { if (hashedSpec.Items.IsEmpty()) { throw new ExprValidationException("Empty list of hash items"); } foreach (var item in hashedSpec.Items) { Chainable chainable = item.Function; // determine type of hash to use var hashFuncName = chainable.GetRootNameOrEmptyString(); var hashFuncParams = chainable.GetParametersOrEmpty(); var hashFunction = HashFunctionEnumExtensions.Determine(contextName, hashFuncName); Pair<Type, ImportSingleRowDesc> hashSingleRowFunction = null; if (hashFunction == null) { try { hashSingleRowFunction = services.ImportServiceCompileTime.ResolveSingleRow( hashFuncName, services.ClassProvidedExtension); } catch (Exception) { // expected } if (hashSingleRowFunction == null) { throw new ExprValidationException( "For context '" + contextName + "' expected a hash function that is any of {" + HashFunctionEnumExtensions.GetStringList() + "} or a plug-in single-row function or script but received '" + hashFuncName + "'"); } } if (hashFuncParams.IsEmpty()) { throw new ExprValidationException( $"For context '{contextName}' expected one or more parameters to the hash function, but found no parameter list"); } // get first parameter var paramExpr = hashFuncParams[0]; var paramType = paramExpr.Forge.EvaluationType; EventPropertyValueGetterForge getter; if (hashFunction == HashFunctionEnum.CONSISTENT_HASH_CRC32) { if (hashFuncParams.Count > 1 || paramType != typeof(string)) { getter = new ContextControllerHashedGetterCRC32SerializedForge( hashFuncParams, hashedSpec.Granularity); } else { getter = new ContextControllerHashedGetterCRC32SingleForge( paramExpr, hashedSpec.Granularity); } } else if (hashFunction == HashFunctionEnum.HASH_CODE) { if (hashFuncParams.Count > 1) { getter = new ContextControllerHashedGetterHashMultiple( hashFuncParams, hashedSpec.Granularity); } else { getter = new ContextControllerHashedGetterHashSingleForge(paramExpr, hashedSpec.Granularity); } } else if (hashSingleRowFunction != null) { getter = new ContextControllerHashedGetterSingleRowForge( hashSingleRowFunction, hashFuncParams, hashedSpec.Granularity, item.FilterSpecCompiled.FilterForEventType, statementRawInfo, services); } else { throw new ArgumentException("Unrecognized hash code function '" + hashFuncName + "'"); } // create and register expression var expression = hashFuncName + "(" + ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(paramExpr) + ")"; var valueSerde = new DataInputOutputSerdeForgeSingleton(typeof(DIONullableIntegerSerde)); var eval = new ExprEventEvaluatorForgeFromProp(getter); var lookupable = new ExprFilterSpecLookupableForge(expression, eval, null, typeof(int), true, valueSerde); item.Lookupable = lookupable; } }
public static SerdeEventPropertyDesc ForgeForEventProperty( EventType eventTypeSerde, string propertyName, object propertyType, StatementRawInfo raw, SerdeCompileTimeResolver resolver) { DataInputOutputSerdeForge forge; if (propertyType == null) { return(new SerdeEventPropertyDesc(new DataInputOutputSerdeForgeSingleton(typeof(DIOSkipSerde)), EmptySet <EventType> .Instance)); } if (propertyType is Type propertyTypeType) { // handle special Json catch-all types if (eventTypeSerde is JsonEventType) { forge = null; if (propertyTypeType == typeof(IDictionary <string, object>)) { forge = new DataInputOutputSerdeForgeSingleton(typeof(DIOJsonObjectSerde)); } else if (propertyTypeType == typeof(object[])) { forge = new DataInputOutputSerdeForgeSingleton(typeof(DIOJsonArraySerde)); } else if (propertyTypeType == typeof(object)) { forge = new DataInputOutputSerdeForgeSingleton(typeof(DIOJsonAnyValueSerde)); } if (forge != null) { return(new SerdeEventPropertyDesc(forge, EmptySet <EventType> .Instance)); } } // handle all Class-type properties var typedProperty = (Type)propertyType; if (typedProperty == typeof(object) && propertyName.Equals(INTERNAL_RESERVED_PROPERTY)) { forge = new DataInputOutputSerdeForgeSingleton( typeof(DIOSkipSerde)); // for expression data window or others that include transient references in the field } else { forge = resolver.SerdeForEventProperty(typedProperty, eventTypeSerde.Name, propertyName, raw); } return(new SerdeEventPropertyDesc(forge, EmptySet <EventType> .Instance)); } if (propertyType is EventType) { var eventType = (EventType)propertyType; Func <DataInputOutputSerdeForgeParameterizedVars, CodegenExpression> func = vars => ResolveTypeCodegenGivenResolver(eventType, vars.OptionalEventTypeResolver); forge = new DataInputOutputSerdeForgeEventSerde("NullableEvent", func); return(new SerdeEventPropertyDesc(forge, Collections.SingletonSet(eventType))); } else if (propertyType is EventType[]) { var eventType = ((EventType[])propertyType)[0]; Func <DataInputOutputSerdeForgeParameterizedVars, CodegenExpression> func = vars => ResolveTypeCodegenGivenResolver(eventType, vars.OptionalEventTypeResolver); forge = new DataInputOutputSerdeForgeEventSerde("NullableEventArray", func); return(new SerdeEventPropertyDesc(forge, Collections.SingletonSet(eventType))); } else if (propertyType is TypeBeanOrUnderlying) { var eventType = ((TypeBeanOrUnderlying)propertyType).EventType; Func <DataInputOutputSerdeForgeParameterizedVars, CodegenExpression> func = vars => ResolveTypeCodegenGivenResolver(eventType, vars.OptionalEventTypeResolver); forge = new DataInputOutputSerdeForgeEventSerde("NullableEventOrUnderlying", func); return(new SerdeEventPropertyDesc(forge, Collections.SingletonSet(eventType))); } else if (propertyType is TypeBeanOrUnderlying[]) { var eventType = ((TypeBeanOrUnderlying[])propertyType)[0].EventType; Func <DataInputOutputSerdeForgeParameterizedVars, CodegenExpression> func = vars => ResolveTypeCodegenGivenResolver(eventType, vars.OptionalEventTypeResolver); forge = new DataInputOutputSerdeForgeEventSerde("NullableEventArrayOrUnderlying", func); return(new SerdeEventPropertyDesc(forge, Collections.SingletonSet(eventType))); } else if (propertyType is IDictionary <string, object> keyValueProperties) { var keys = new string[keyValueProperties.Count]; var serdes = new DataInputOutputSerdeForge[keyValueProperties.Count]; var index = 0; var nestedTypes = new LinkedHashSet <EventType>(); // Rewrite all properties where the value is a string. First, gather all instances that need // to be rewritten into the class that matches the type. keyValueProperties .Where(entry => entry.Value is string) .ToList() .ForEach( entry => { var value = entry.Value.ToString()?.Trim(); var clazz = TypeHelper.GetPrimitiveTypeForName(value); if (clazz != null) { keyValueProperties[entry.Key] = clazz; } }); foreach (var entry in keyValueProperties) { keys[index] = entry.Key; var desc = ForgeForEventProperty(eventTypeSerde, entry.Key, entry.Value, raw, resolver); nestedTypes.AddAll(desc.NestedTypes); serdes[index] = desc.Forge; index++; } var functions = new Func <DataInputOutputSerdeForgeParameterizedVars, CodegenExpression> [2]; functions[0] = vars => Constant(keys); functions[1] = vars => DataInputOutputSerdeForgeExtensions.CodegenArray(serdes, vars.Method, vars.Scope, vars.OptionalEventTypeResolver); forge = new DataInputOutputSerdeForgeParameterized(typeof(DIOMapPropertySerde).Name, functions); return(new SerdeEventPropertyDesc(forge, nestedTypes)); } else { throw new EPException( "Failed to determine serde for unrecognized property value type '" + propertyType + "' for property '" + propertyName + "' of type '" + eventTypeSerde.Name + "'"); } }