private void GetSchemaStruct()

in Services/DataX.Flow/DataX.Flow.SchemaInference/Engine.cs [196:284]


        private void GetSchemaStruct(JObject jObject, StructObject structObject, string keyPath)
        {
            if (structObject == null && string.IsNullOrEmpty(_errors.Where(e => e.Contains(keyPath)).FirstOrDefault()))
            {
                _errors.Add($"Error in generating schema for '{keyPath}'. Result holder is null");
                return;
            }

            foreach (KeyValuePair<string, JToken> child in jObject)
            {
                string childkeyPath = $"{keyPath}.{child.Key}";

                // This means the child is of type Struct object
                if (child.Value.GetType() == typeof(JObject))
                {
                    // Check if the field already exists. If not, create it. If it exists, ensure the type is as expected.
                    Field fKey = structObject.fields.Where(field => field.name == child.Key).FirstOrDefault();
                    StructObject childStructObject = null;
                    if (fKey == null)
                    {
                        childStructObject = new StructObject();
                        structObject.fields.Add(new Field(child.Key, childStructObject));
                    }
                    else if (fKey.type.GetType() == typeof(StructObject))
                    {
                        childStructObject = fKey.type as StructObject;
                    }
                    else 
                    {
                        if (string.IsNullOrEmpty(_errors.Where(e => e.Contains($"'{childkeyPath}'")).FirstOrDefault()))
                        {
                            _errors.Add($"Conflict in schema. Key with path '{childkeyPath}' has different types");
                        }
                        continue;
                    }

                    GetSchemaStruct(child.Value as JObject, childStructObject, childkeyPath);
                }

                // This means the child is of type Array
                if (child.Value.GetType() == typeof(JArray))
                {
                    // Check if the field already exists. If not, create it. If it exists, ensure the type is as expected.
                    Field fKey = structObject.fields.Where(f => f.name == child.Key).FirstOrDefault();
                    Type childType = null;
                    if (fKey == null)
                    {
                        childType = new Type();
                        structObject.fields.Add(new Field(child.Key, childType));
                    }
                    else if (fKey.type.GetType() == typeof(Type))
                    {
                        childType = fKey.type as Type;
                    }
                    else 
                    {
                        if (string.IsNullOrEmpty(_errors.Where(e => e.Contains($"'{childkeyPath}'")).FirstOrDefault()))
                        {
                            _errors.Add($"Conflict in schema. Key with path '{childkeyPath}' has different types");
                        }
                        continue;
                    }

                    GetSchemaArray(child.Value as JArray, childType, childkeyPath);
                }

                // This means the child is of simple type
                if (child.Value.GetType() == typeof(JValue))
                {
                    // Check if the field already exists. If not, create it. If it exists, ensure the type is as expected.
                    Field fKey = structObject.fields.Where(field => field.name == child.Key).FirstOrDefault();
                    string type = GetObjectType(child.Value);

                    if (fKey == null)
                    {
                        structObject.fields.Add(new Field(child.Key, type));
                    }
                    // If the key already exists, but is not of the same type then there is conflict in schema
                    else if (fKey.type.GetType() != type.GetType() || fKey.type.ToString() != type.ToString())
                    {
                        if (string.IsNullOrEmpty(_errors.Where(error => error.Contains($"'{childkeyPath}'")).FirstOrDefault()))
                        {
                            _errors.Add($"Conflict in schema. Key with path '{childkeyPath}' has different types");
                        }
                    }
                }

            }
        }