public static string MakeCursorFromJsonElement()

in src/Core/Resolvers/SqlPaginationUtil.cs [206:290]


        public static string MakeCursorFromJsonElement(
            JsonElement element,
            List<string> primaryKey,
            List<OrderByColumn>? orderByColumns,
            string entityName = "",
            string schemaName = "",
            string tableName = "",
            ISqlMetadataProvider? sqlMetadataProvider = null,
            bool isGroupByQuery = false)
        {
            List<NextLinkField> cursorJson = new();
            JsonSerializerOptions options = new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
            // Hash set is used here to maintain linear runtime
            // in the worst case for this function. If list is used
            // we will have in the worst case quadratic runtime.
            HashSet<string> remainingKeys = new();

            if (!isGroupByQuery)
            {
                foreach (string key in primaryKey)
                {
                    remainingKeys.Add(key);
                }
            }

            // must include all orderByColumns to maintain
            // correct pagination with sorting
            if (orderByColumns is not null)
            {
                foreach (OrderByColumn column in orderByColumns)
                {
                    string? exposedColumnName = GetExposedColumnName(entityName, column.ColumnName, sqlMetadataProvider);
                    if (TryResolveJsonElementToScalarVariable(element.GetProperty(exposedColumnName), out object? value))
                    {
                        cursorJson.Add(new NextLinkField(
                            entityName: entityName,
                            fieldName: exposedColumnName,
                            fieldValue: value,
                            direction: column.Direction));
                    }
                    else
                    {
                        throw new DataApiBuilderException(
                            message: "Incompatible data to create pagination cursor.",
                            statusCode: HttpStatusCode.BadRequest,
                            subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorProcessingData);
                    }

                    remainingKeys.Remove(column.ColumnName);
                }
            }

            // Primary key columns must be included in the orderBy query parameter in the nextLink cursor to break ties between result set records.
            // Iterate through list of (composite) primary key(s) and when a primary key column exists in the remaining keys collection:
            // 1.) Add that column as one of the pagination columns in the orderBy query parameter in the generated nextLink cursor.
            // 2.) Remove the column from the remaining keys collection.
            // This loop enables consistent iteration over the list of primary key columns which:
            // - Maintains the order of the primary key columns as they exist in the database.
            // - Ensures all primary key columns have been added to the nextLink cursor.
            foreach (string column in primaryKey)
            {
                if (remainingKeys.Contains(column))
                {
                    string? exposedColumnName = GetExposedColumnName(entityName, column, sqlMetadataProvider);
                    if (TryResolveJsonElementToScalarVariable(element.GetProperty(exposedColumnName), out object? value))
                    {
                        cursorJson.Add(new NextLinkField(
                            entityName: entityName,
                            fieldName: exposedColumnName,
                            fieldValue: value));
                    }
                    else
                    {
                        throw new DataApiBuilderException(
                           message: "Incompatible data to create pagination cursor.",
                           statusCode: HttpStatusCode.BadRequest,
                           subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorProcessingData);
                    }

                    remainingKeys.Remove(column);
                }
            }

            return Base64Encode(JsonSerializer.Serialize(cursorJson, options));
        }