private static List <ListDataAsStreamProperty> TransformRowData(JsonElement row, IFieldCollection fields, Dictionary <string, IField> fieldLookupCache)
        {
            List <ListDataAsStreamProperty> properties = new List <ListDataAsStreamProperty>();

            foreach (var property in row.EnumerateObject())
            {
                // Doing the field lookup is expensive given it happens per field/row, caching drastically improves performance when reading large sets of items
                if (!fieldLookupCache.TryGetValue(property.Name, out IField field))
                {
                    field = fields.AsRequested().FirstOrDefault(p => p.InternalName == property.Name);
                    fieldLookupCache.Add(property.Name, field);
                }

                if (field != null)
                {
                    var streamProperty = new ListDataAsStreamProperty()
                    {
                        Field = field,
                        Type  = field.FieldTypeKind,
                        Name  = property.Name
                    };

                    // Is this a field that needs to be wrapped into a special field type?
                    var specialField = DetectSpecialFieldType(streamProperty.Name, field);
                    if (specialField != null)
                    {
                        streamProperty.IsArray = specialField.Item2;

                        if (property.Value.ValueKind == JsonValueKind.Array)
                        {
                            #region Sample json responses

                            /*
                             * "PersonSingle": [
                             *  {
                             *      "id": "15",
                             *      "title": "Kevin Cook",
                             *      "email": "*****@*****.**",
                             *      "sip": "*****@*****.**",
                             *      "picture": ""
                             *  }
                             * ],
                             *
                             * "PersonMultiple": [
                             *  {
                             *      "id": "14",
                             *      "value": "Anna Lidman",
                             *      "title": "Anna Lidman",
                             *      "email": "*****@*****.**",
                             *      "sip": "*****@*****.**",
                             *      "picture": ""
                             *  },
                             *  {
                             *      "id": "6",
                             *      "value": "Bert Jansen (Cloud)",
                             *      "title": "Bert Jansen (Cloud)",
                             *      "email": "*****@*****.**",
                             *      "sip": "*****@*****.**",
                             *      "picture": ""
                             *  }
                             * ],
                             *
                             * "MMSingle": {
                             *  "__type": "TaxonomyFieldValue:#Microsoft.SharePoint.Taxonomy",
                             *  "Label": "LBI",
                             *  "TermID": "ed5449ec-4a4f-4102-8f07-5a207c438571"
                             * },
                             *
                             * "MMMultiple": [
                             *  {
                             *      "Label": "LBI",
                             *      "TermID": "ed5449ec-4a4f-4102-8f07-5a207c438571"
                             *  },
                             *  {
                             *      "Label": "MBI",
                             *      "TermID": "1824510b-00e1-40ac-8294-528b1c9421e0"
                             *  },
                             *  {
                             *      "Label": "HBI",
                             *      "TermID": "0b709a34-a74e-4d07-b493-48041424a917"
                             *  }
                             * ],
                             *
                             * "LookupSingle": [
                             *  {
                             *      "lookupId": 71,
                             *      "lookupValue": "Sample Document 01",
                             *      "isSecretFieldValue": false
                             *  }
                             * ],
                             *
                             * "LookupMultiple": [
                             *  {
                             *      "lookupId": 1,
                             *      "lookupValue": "General",
                             *      "isSecretFieldValue": false
                             *  },
                             *  {
                             *      "lookupId": 71,
                             *      "lookupValue": "Sample Document 01",
                             *      "isSecretFieldValue": false
                             *  }
                             * ],
                             *
                             * "Location": {
                             *  "DisplayName": null,
                             *  "LocationUri": "https://www.bingapis.com/api/v6/addresses/QWRkcmVzcy83MDA5ODMwODI3MTUyMzc1ODA5JTdjMT9h%3d%3d?setLang=en",
                             *  "EntityType": null,
                             *  "Address": {
                             *      "Street": "Somewhere",
                             *      "City": "XYZ",
                             *      "State": "Vlaanderen",
                             *      "CountryOrRegion": "Belgium",
                             *      "PostalCode": "9999"
                             *  },
                             *  "Coordinates": {
                             *      "Latitude": null,
                             *      "Longitude": null
                             *  }
                             * },
                             */
                            #endregion

                            // Add values that will become part of a FieldValueCollection later on
                            foreach (var streamPropertyElement in property.Value.EnumerateArray())
                            {
                                (var fieldValue, var isArray) = DetectSpecialFieldType(streamProperty.Name, field);
                                var listDataAsStreamPropertyValue = new ListDataAsStreamPropertyValue()
                                {
                                    FieldValue = fieldValue
                                };

                                foreach (var streamPropertyElementValue in streamPropertyElement.EnumerateObject())
                                {
                                    listDataAsStreamPropertyValue.Properties.Add(streamPropertyElementValue.Name, GetJsonPropertyValueAsString(streamPropertyElementValue.Value));
                                }

                                streamProperty.Values.Add(listDataAsStreamPropertyValue);
                            }
                        }
                        else
                        {
                            /*
                             * "Url": "https:\u002f\u002fpnp.com\u002f3",
                             * "Url.desc": "something3",
                             *
                             * "LookupSingleField1": "",
                             * "LookupSingleField1.": "",
                             */

                            var listDataAsStreamPropertyValue = new ListDataAsStreamPropertyValue()
                            {
                                FieldValue = specialField.Item1
                            };

                            if (property.Value.ValueKind == JsonValueKind.Object)
                            {
                                foreach (var streamPropertyElementValue in property.Value.EnumerateObject())
                                {
                                    if (streamPropertyElementValue.Value.ValueKind == JsonValueKind.Object)
                                    {
                                        foreach (var streamPropertyElementValueLevel2 in streamPropertyElementValue.Value.EnumerateObject())
                                        {
                                            listDataAsStreamPropertyValue.Properties.Add(streamPropertyElementValueLevel2.Name, GetJsonPropertyValueAsString(streamPropertyElementValueLevel2.Value));
                                        }
                                    }
                                    else
                                    {
                                        listDataAsStreamPropertyValue.Properties.Add(streamPropertyElementValue.Name, GetJsonPropertyValueAsString(streamPropertyElementValue.Value));
                                    }
                                }
                            }
                            else
                            {
                                listDataAsStreamPropertyValue.Properties.Add(property.Name, GetJsonPropertyValueAsString(property.Value));
                            }

                            streamProperty.Values.Add(listDataAsStreamPropertyValue);
                        }
                    }
                    else
                    {
                        // Add as single property or simple choice collection

                        /*
                         * "Title": "Item1",
                         *
                         * "ChoiceMultiple": [
                         *  "Choice 1",
                         *  "Choice 3",
                         *  "Choice 4"
                         * ],
                         */
                        streamProperty.Value = property.Value;
                    }

                    properties.Add(streamProperty);
                }
                else
                {
                    /*
                     * "Url.desc": "something3",
                     * "DateTime1.": "2020-12-04T11:15:15Z",
                     */

                    if (property.Name.Contains("."))
                    {
                        string[] nameParts = property.Name.Split(new char[] { '.' });

                        var propertyToUpdate = properties.FirstOrDefault(p => p.Name == nameParts[0]);
                        if (propertyToUpdate != null && propertyToUpdate.Values.Count == 1 && !string.IsNullOrEmpty(nameParts[1]))
                        {
                            var valueToUpdate = propertyToUpdate.Values.FirstOrDefault();
                            if (valueToUpdate == null)
                            {
                                valueToUpdate = new ListDataAsStreamPropertyValue();
                                propertyToUpdate.Values.Add(valueToUpdate);
                            }
                            if (!valueToUpdate.Properties.ContainsKey(nameParts[1]))
                            {
                                valueToUpdate.Properties.Add(nameParts[1], GetJsonPropertyValueAsString(property.Value));
                            }
                        }
                        else if (propertyToUpdate != null && !string.IsNullOrEmpty(nameParts[1]))
                        {
                            //"Bool1.value": "1",

                            if (!fieldLookupCache.TryGetValue(nameParts[0], out IField field2))
                            {
                                field2 = fields.AsRequested().FirstOrDefault(p => p.InternalName == nameParts[0]);
                                fieldLookupCache.Add(nameParts[0], field2);
                            }

                            // Extra properties on "regular" fields
                            if (field2 != null && field2.FieldTypeKind == FieldType.Boolean && nameParts[1] == "value")
                            {
                                propertyToUpdate.Value = property.Value;
                            }
                        }
                        else if (propertyToUpdate != null && string.IsNullOrEmpty(nameParts[1]))
                        {
                            // override the set Value
                            propertyToUpdate.Value = property.Value;
                        }
                    }
                }
            }

            return(properties);
        }