### ListField String Example Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Example of creating a ListField for string elements. ```csharp // List of strings new ListField("tags", typeof(string)); ``` -------------------------------- ### StructField Example Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Example of creating a StructField to represent a nested address structure. ```csharp new StructField("address", new DataField("street"), new DataField("city"), new DataField("zipcode")); ``` -------------------------------- ### ListField Struct Example Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Example of creating a ListField containing struct elements. ```csharp // List of structs new ListField("addresses", new StructField("address", new DataField("street"), new DataField("city"))); ``` -------------------------------- ### ListField Primitive Example Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Example of creating a ListField for primitive integer IDs. ```csharp // List of primitives new ListField("ids", new DataField("id")); ``` -------------------------------- ### Define MovementHistory with List of Integers Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Example of a C# class with a nullable list of integers, demonstrating native support for list of atoms. ```csharp class MovementHistory { public int? PersonId { get; set; } public List? ParentIds { get; set; } } ``` -------------------------------- ### Schema Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets the Parquet schema describing the file structure. ```APIDOC ## Schema ### Description Gets the Parquet schema describing the file structure. ### Property `ParquetSchema Schema { get; }` ### Type `ParquetSchema` ### Example ```csharp ParquetSchema schema = reader.Schema; DataField[] dataFields = schema.GetDataFields(); ``` ``` -------------------------------- ### Generate Fake Data for Parquet Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Create a list of objects conforming to the defined data structure. This example generates one million records with varying timestamps, event names, and meter values. ```csharp List data = Enumerable.Range(0, 1_000_000).Select(i => new Event { Timestamp = DateTime.UtcNow.AddSeconds(i), EventName = i % 2 == 0 ? "on" : "off", MeterValue = i }).ToList(); ``` -------------------------------- ### Define MovementHistory with List of Structures Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Example of a C# class containing a list of custom structures (Address), showcasing support for lists of complex types. ```csharp class Address { public string? Country { get; set; } public string? City { get; set; } } class MovementHistory { public int? PersonId { get; set; } public string? Comments { get; set; } public List
? Addresses { get; set; } } ``` -------------------------------- ### FieldPath Class Definition and Example Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/types.md Represents an immutable path to a field within the schema hierarchy. An example demonstrates its creation and string representation. ```csharp public class FieldPath { // Example: // var path = new FieldPath("user", "address", "city"); // // toString(): "user.address.city" } ``` -------------------------------- ### Configure Per-Column Encodings Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Set specific encoding strategies for individual columns to optimize storage and performance. For example, use Dictionary encoding for categorical strings and Delta encoding for sorted integers. ```csharp var options = new ParquetOptions(); // Dictionary encoding for strings (good for categorical data) options.ColumnEncodingHints["name"] = EncodingHint.Dictionary; // Delta encoding for sorted integers options.ColumnEncodingHints["id"] = EncodingHint.DeltaBinaryPacked; // Byte-split for floating-point data options.ColumnEncodingHints["latitude"] = EncodingHint.ByteSplitStream; options.ColumnEncodingHints["longitude"] = EncodingHint.ByteSplitStream; await ParquetSerializer.SerializeAsync(data, "output.parquet", options); ``` -------------------------------- ### Write Data for List of Structs Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Writes data to a Parquet file according to the defined schema, including handling repetition levels for list elements. This example demonstrates writing name, line1, and postcode fields. ```C# await using(ParquetWriter w = await ParquetWriter.CreateAsync(schema, ms)) { using ParquetRowGroupWriter gw = w.CreateRowGroup(); await gw.WriteAsync(nameField, new string[] { "Joe", "Bob" }); await gw.WriteAsync(line1Field, new[] { "Amazonland", "Disneyland", "Cryptoland" }, new[] { 0, 1, 0 }); await gw.WriteAsync(postcodeField, new[] { "AAABBB", "CCCDDD", "EEEFFF" }, new[] { 0, 1, 0 }); } ``` -------------------------------- ### Parquet Writer with Custom Metadata and Compression Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md Demonstrates configuring custom metadata and compression settings for the Parquet writer. Compression options like Snappy with the smallest size level can be specified. ```csharp var schema = new ParquetSchema(new DataField("id")); var options = new ParquetOptions { CompressionMethod = CompressionMethod.Snappy, CompressionLevel = CompressionLevel.SmallestSize }; await using var fs = File.Create("data.parquet"); await using ParquetWriter writer = await ParquetWriter.CreateAsync(schema, fs, options); writer.CustomMetadata = new Dictionary { { "version", "1.0" }, { "environment", "production" } }; using ParquetRowGroupWriter rg = writer.CreateRowGroup(); await rg.WriteAsync(schema.DataFields[0], new[] { 1, 2, 3 }); ``` -------------------------------- ### CreateAsync (from file path) Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Opens a Parquet file from disk and initializes a ParquetReader. The file handle is automatically closed when the reader is disposed. ```APIDOC ## CreateAsync (from file path) ### Description Opens a Parquet file from disk and initializes a ParquetReader. The file handle is automatically closed when the reader is disposed. ### Method `static async Task CreateAsync(string filePath, ParquetOptions? parquetOptions = null, CancellationToken cancellationToken = default)` ### Parameters #### Path Parameters - **filePath** (string) - Required - Path to the Parquet file on disk #### Optional Parameters - **parquetOptions** (ParquetOptions?) - Optional - Reader configuration options - **cancellationToken** (CancellationToken) - Optional - Cancellation token ### Returns `Task` — Initialized reader instance ### Throws - `ArgumentNullException` — If filePath is null - `IOException` — If file is not a valid Parquet file or size is too small - `FileNotFoundException` — If file does not exist ### Example ```csharp await using ParquetReader reader = await ParquetReader.CreateAsync("data.parquet"); int rowGroupCount = reader.RowGroupCount; ParquetSchema schema = reader.Schema; ``` ``` -------------------------------- ### Basic Column Writing Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Demonstrates writing basic integer, string, and double columns to a Parquet row group. Ensure the ParquetSchema and ParquetWriter are set up correctly. ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name"), new DataField("salary")); await using ParquetWriter writer = await ParquetWriter.CreateAsync(schema, fs); using ParquetRowGroupWriter groupWriter = writer.CreateRowGroup(); int[] ids = { 1, 2, 3 }; string[] names = { "Alice", "Bob", "Carol" }; double[] salaries = { 50000, 60000, 70000 }; await groupWriter.WriteAsync(schema.DataFields[0], ids); await groupWriter.WriteAsync(schema.DataFields[1], names); await groupWriter.WriteAsync(schema.DataFields[2], salaries); ``` -------------------------------- ### RowGroupCount Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets the number of row groups in the file. ```APIDOC ## RowGroupCount ### Description Gets the number of row groups in the file. ### Property `int RowGroupCount { get; }` ### Type `int` ### Example ```csharp for(int i = 0; i < reader.RowGroupCount; i++) { using var groupReader = reader.OpenRowGroupReader(i); Console.WriteLine($"Row group {i}: {groupReader.RowCount} rows"); } ``` ``` -------------------------------- ### Configuration Reference Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Detailed reference for `ParquetOptions`, covering configuration settings for compression, type conversion, encoding, memory management, and serialization. ```APIDOC ## Configuration Reference ### Description Provides a complete reference for `ParquetOptions` used to configure Parquet.Net behavior. ### Compression - `CompressionMethod`: Specifies the compression algorithm. - `CompressionLevel`: Sets the compression level. ### Type Conversion - Includes 5 boolean flags for controlling type handling. ### Encoding - `ColumnEncodingHints`: Provides hints for column encoding. - Thresholds and sampling options for encoding. ### Memory Management - `PoolSize`: Configures memory pool size. ### Serialization - `Append`: Enables append mode for writers. - `RowGroupSize`: Sets the size of row groups. - `PropertyNameCaseInsensitive`: Configures case-insensitive property name matching. ``` -------------------------------- ### CustomMetadata Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets custom key-value metadata pairs stored in the file. ```APIDOC ## CustomMetadata ### Description Gets custom key-value metadata pairs stored in the file. ### Property `Dictionary CustomMetadata { get; }` ### Type `Dictionary` ### Example ```csharp foreach(var kvp in reader.CustomMetadata) { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); } ``` ``` -------------------------------- ### Conversion from Collections Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Demonstrates writing data from common .NET collections like List and arrays to Parquet columns. Also shows attaching metadata during conversion. ```csharp List idList = new List { 1, 2, 3, 4, 5 }; await groupWriter.WriteAsync( idField, idList.ToArray().AsMemory()); Dictionary metadata = new Dictionary { { "source", "list" } }; await groupWriter.WriteAsync( stringField, new[] { "a", "b", "c" }, customMetadata: metadata); ``` -------------------------------- ### Create a FieldPath Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Instantiate a FieldPath by providing a sequence of string parts representing the path components. ```csharp var path = new FieldPath("user", "address", "city"); // Represents: user.address.city ``` -------------------------------- ### Metadata Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets raw Parquet file metadata (internal representation). ```APIDOC ## Metadata ### Description Gets raw Parquet file metadata (internal representation). ### Property `FileMetaData? Metadata { get; }` ### Type `FileMetaData?` ``` -------------------------------- ### RowGroups Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets a collection of all row group readers for fast random access. ```APIDOC ## RowGroups ### Description Gets a collection of all row group readers for fast random access. ### Property `IReadOnlyList RowGroups { get; }` ### Type `IReadOnlyList` ### Example ```csharp foreach(var rgReader in reader.RowGroups) { Console.WriteLine($"Row count: {rgReader.RowCount}"); } ``` ``` -------------------------------- ### Create Parquet Writer Instance Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md Use the CreateAsync factory method to initialize a ParquetWriter on a stream with a given schema. Ensure the output stream is writeable and seekable. The append parameter controls whether to add to an existing file or create a new one. ```csharp public static async Task CreateAsync( ParquetSchema schema, Stream output, ParquetOptions? options = null, bool append = false, CancellationToken cancellationToken = default) ``` ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name")); var fs = File.Create("output.parquet"); await using ParquetWriter writer = await ParquetWriter.CreateAsync(schema, fs); using ParquetRowGroupWriter groupWriter = writer.CreateRowGroup(); await groupWriter.WriteAsync(schema.DataFields[0], new[] { 1, 2, 3 }); await groupWriter.WriteAsync(schema.DataFields[1], new[] { "Alice", "Bob", "Carol" }); ``` -------------------------------- ### Define Simple Repeatable Field Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Example of using `[ParquetSimpleRepeatable]` attribute for reading primitive values stored in a legacy repeatable field (array). ```csharp class Primitives { [ParquetSimpleRepeatable] public List? Booleans { get; set; } } ``` -------------------------------- ### High Performance Parquet Configuration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure ParquetOptions for high performance using Snappy compression and fastest compression level. ```csharp var options = new ParquetOptions { CompressionMethod = CompressionMethod.Snappy, CompressionLevel = CompressionLevel.Fastest, DictionaryEncodingThreshold = 0.9, DictionaryEncodingSampleSize = 5000, RowGroupSize = 1_000_000 }; ``` -------------------------------- ### Handle Type Incompatibility Error Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/errors.md Shows an example where reading data into a buffer of an incompatible type (e.g., int[] for a string field) results in an ArgumentException when using ParquetRowGroupReader.ReadAsync. ```csharp var stringField = new DataField("name"); int[] values = new int[10]; await groupReader.ReadAsync(stringField, values); // ArgumentException ``` -------------------------------- ### Define a Simple Schema Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Create a basic schema with primitive data fields for ID, name, and creation timestamp. ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name"), new DataField("created")); ``` -------------------------------- ### CustomMetadata Property Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md Gets or sets custom key-value metadata pairs to include in the Parquet file. This property allows for the addition of arbitrary metadata that can be useful for tracking or identifying the file. ```APIDOC ## CustomMetadata Property ### Description Gets or sets custom key-value metadata pairs to include in the file. ### Type `IReadOnlyDictionary` (getter), `IEnumerable>` (setter) ### Example ```csharp writer.CustomMetadata = new Dictionary { { "version", "1.0" }, { "created_by", "MyApp" } }; ``` ``` -------------------------------- ### Create ParquetSchema with Fields Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Instantiate a ParquetSchema by providing an array or enumerable collection of Field objects. At least one field is required. ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name"), new DataField("salary")); ``` -------------------------------- ### Access Row Group Readers Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Gets a read-only list of all row group readers, allowing for fast random access to individual row groups within the Parquet file. ```csharp foreach(var rgReader in reader.RowGroups) { Console.WriteLine($"Row count: {rgReader.RowCount}"); } ``` -------------------------------- ### Iterate Through Row Groups and Get Row Count Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Iterates through each row group in a Parquet file and prints the number of rows in each group. Requires opening a reader for the file first. ```csharp for(int i = 0; i < reader.RowGroupCount; i++) { using var groupReader = reader.OpenRowGroupReader(i); Console.WriteLine($"Row group {i}: {groupReader.RowCount} rows"); } ``` -------------------------------- ### Handle Small File Size Error Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/errors.md Demonstrates how to catch an IOException specifically for files that are too small to be valid Parquet files when using ParquetReader.CreateAsync. ```csharp try { var reader = await ParquetReader.CreateAsync(stream); } catch(IOException ex) when(ex.Message.Contains("size too small")) { Console.WriteLine("Invalid file"); } ``` -------------------------------- ### Set Compression Method Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure the compression algorithm applied to column data. Use this when you need to specify a particular compression codec like Zstd. ```csharp var options = new ParquetOptions { CompressionMethod = CompressionMethod.Zstd }; await ParquetSerializer.SerializeAsync(data, stream, options); ``` -------------------------------- ### Writing with Repetition Levels (Arrays) Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Demonstrates writing array data using flat values and corresponding repetition levels. This is used for fields that represent collections within a row. ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField>("values")); using ParquetRowGroupWriter groupWriter = writer.CreateRowGroup(); // Data: [1, 2, 3], [4, 5], [6] int[] flatValues = { 1, 2, 3, 4, 5, 6 }; int[] repetitionLevels = { 0, 1, 1, 0, 1, 0 }; await groupWriter.WriteAsync(schema.DataFields[1], flatValues, repetitionLevels); ``` -------------------------------- ### Handle Buffer Too Small Error Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/errors.md Illustrates how to avoid an ArgumentException by ensuring the pre-allocated buffer for reading data is large enough to accommodate the row count or required levels. ```csharp long rowCount = groupReader.RowCount; int[] values = new int[rowCount - 1]; // Too small! await groupReader.ReadAsync(field, values); // Throws ArgumentException // Correct: values = new int[rowCount]; await groupReader.ReadAsync(field, values); ``` -------------------------------- ### Get Row Count of a Row Group Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-reader.md Access the RowCount property to determine the number of rows in a row group. This count includes null values and represents the row count, not the value count for repeated columns. ```csharp using ParquetRowGroupReader groupReader = reader.OpenRowGroupReader(0); long rows = groupReader.RowCount; int[] values = new int[rows]; ``` -------------------------------- ### Writing Nullable Columns Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Shows how to write columns that can contain null values using nullable types (e.g., int?, string?). ```csharp int?[] ids = { 1, null, 3 }; string?[] comments = { "good", null, "excellent" }; await groupWriter.WriteAsync(idField, ids); await groupWriter.WriteAsync(commentField, comments); ``` -------------------------------- ### Set Column Encoding Hints Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure specific encoding types for columns to optimize storage and performance. Use this when you have specific knowledge about the data distribution in your columns. ```csharp var options = new ParquetOptions(); options.ColumnEncodingHints["id"] = EncodingHint.DeltaBinaryPacked; options.ColumnEncodingHints["name"] = EncodingHint.Dictionary; options.ColumnEncodingHints["salary"] = EncodingHint.ByteSplitStream; await ParquetSerializer.SerializeAsync(data, stream, options); ``` -------------------------------- ### Create ParquetReader from File Path Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Opens a Parquet file from disk using its file path. The file handle is automatically closed when the reader is disposed. Use this when you have the Parquet file stored locally. ```csharp await using ParquetReader reader = await ParquetReader.CreateAsync("data.parquet"); int rowGroupCount = reader.RowGroupCount; ParquetSchema schema = reader.Schema; ``` -------------------------------- ### Writing with Custom Column Metadata Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Shows how to attach custom metadata to a column during the writing process. This metadata can be used for storing additional information about the column. ```csharp var metadata = new Dictionary { { "statistics_checked", "true" }, { "encoding", "PLAIN" } }; await groupWriter.WriteAsync( field, values, customMetadata: metadata); ``` -------------------------------- ### CreateAsync (from stream) Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Creates a ParquetReader from an input stream. The stream must be readable and seekable. ```APIDOC ## CreateAsync (from stream) ### Description Creates a reader from an input stream. Stream must be readable and seekable. ### Method `static async Task CreateAsync(Stream input, ParquetOptions? parquetOptions = null, bool leaveStreamOpen = true, CancellationToken cancellationToken = default)` ### Parameters #### Path Parameters - **input** (Stream) - Required - Readable, seekable stream containing Parquet data #### Optional Parameters - **parquetOptions** (ParquetOptions?) - Optional - Reader configuration options - **leaveStreamOpen** (bool) - Optional - When true, leaves stream open after reader disposal (default: true) - **cancellationToken** (CancellationToken) - Optional - Cancellation token ### Returns `Task` — Initialized reader instance ### Throws - `ArgumentNullException` — If input is null - `ArgumentException` — If stream is not readable or seekable - `IOException` — If stream size is too small to be a valid Parquet file ### Example ```csharp using var fs = File.OpenRead("data.parquet"); await using ParquetReader reader = await ParquetReader.CreateAsync(fs, leaveStreamOpen: false); ``` ``` -------------------------------- ### Define a List of Primitives Schema Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Create a schema with a list containing primitive integer values. ```csharp var schema = new ParquetSchema( new DataField("record_id"), new ListField("values", typeof(int))); ``` -------------------------------- ### Write Binary Column using Convenience Overload Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md This convenience overload is for writing binary columns. It automatically converts the input to ReadOnlyMemory. ```csharp byte?[] binaryData = { new byte[] { 1, 2, 3 }, null, new byte[] { 4, 5 } }; await groupWriter.WriteAsync(binaryField, binaryData); ``` -------------------------------- ### Parquet.Serialization Namespace Coverage Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Details the completeness of documentation for the Parquet.Serialization namespace, focusing on serializers and deserialization results. ```text Parquet.Serialization ✓ Complete ├── ParquetSerializer ✓ All methods ├── DeserializationResult ✓ Complete └── Attributes ✓ All documented ``` -------------------------------- ### Low-Level Writing of Nested Structure Data Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Demonstrates writing data for a nested structure at a low level, mapping flat data arrays to schema fields. ```csharp DataField[] fields = schema.GetDataFields(); await groupWriter.WriteAsync(fields[0], new[] { 1, 2 }); await groupWriter.WriteAsync(fields[1], new[] { "John", "Jane" }); await groupWriter.WriteAsync(fields[2], new[] { "Doe", "Smith" }); await groupWriter.WriteAsync(fields[3], new[] { 30, 28 }); ``` -------------------------------- ### Read Basic Columns from Row Group Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-reader.md Demonstrates how to read data for multiple columns (int, string, double) from a single row group. Ensure the Parquet file and row group exist. ```csharp await using ParquetReader reader = await ParquetReader.CreateAsync("data.parquet"); using ParquetRowGroupReader groupReader = reader.OpenRowGroupReader(0); DataField[] fields = reader.Schema.GetDataFields(); int[] ids = new int[groupReader.RowCount]; string[] names = new string[groupReader.RowCount]; double[] values = new double[groupReader.RowCount]; await groupReader.ReadAsync(fields[0], ids); await groupReader.ReadAsync(fields[1], names); await groupReader.ReadAsync(fields[2], values); for(int i = 0; i < ids.Length; i++) { Console.WriteLine($"{ids[i]}, {names[i]}, {values[i]}"); } ``` -------------------------------- ### Configure Hardware Acceleration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Control the use of hardware acceleration for performance. It is enabled by default but can be disabled for compatibility reasons. ```csharp // Enable globally (default: true) ParquetOptions.UseHardwareAcceleration = true; // Disable for compatibility ParquetOptions.UseHardwareAcceleration = false; ``` -------------------------------- ### Parquet.Utils Namespace Coverage Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Details the completeness of documentation for the Parquet.Utils namespace, focusing on essential utilities like FileMerger. ```text Parquet.Utils ✓ Essential utilities └── FileMerger ✓ Pattern documented ``` -------------------------------- ### Append to Existing Parquet File Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md Shows how to append new data to an existing Parquet file. Ensure the schema is compatible with the existing file. ```csharp var schema = new ParquetSchema(new DataField("id")); await using var fs = File.Open("data.parquet", FileMode.Open, FileAccess.ReadWrite); await using ParquetWriter writer = await ParquetWriter.CreateAsync(schema, fs, append: true); using ParquetRowGroupWriter rg = writer.CreateRowGroup(); await rg.WriteAsync(schema.DataFields[0], new[] { 7, 8, 9 }); ``` -------------------------------- ### WriteAllPartsAsync Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md Advanced method for writing columns with explicit definition and repetition levels. This is intended for low-level, high-performance operations. ```APIDOC ## WriteAllPartsAsync ### Description Advanced method for writing columns with explicit definition and repetition levels. For low-level, high-performance operations only. ### Method Signature ```csharp public async Task WriteAllPartsAsync( DataField field, ReadOnlyMemory values, ReadOnlyMemory? definitionValues, ReadOnlyMemory? repetitionLevels, CancellationToken cancellationToken) where T : struct ``` ### Parameters #### Method Parameters - **field** (DataField) - Required - Field to write - **values** (ReadOnlyMemory) - Required - Values buffer - **definitionValues** (ReadOnlyMemory?) - Optional - Definition levels (required for nullable fields) - **repetitionLevels** (ReadOnlyMemory?) - Optional - Repetition levels (required for array fields) - **cancellationToken** (CancellationToken) - Optional - Cancellation token ### Returns `Task` — Completes when write finishes ### Remarks Only use this method if you understand definition and repetition levels. Use `WriteAsync` overloads for simpler cases. ``` -------------------------------- ### ParquetOptions Class Definition Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/types.md Defines the configuration options for reading, writing, and serializing Parquet data. Refer to configuration.md for a complete reference. ```csharp public class ParquetOptions ``` -------------------------------- ### Custom Parquet Serialization Configuration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/README.md Configure serialization options such as compression method, compression level, row group size, and case sensitivity for property names. ```csharp var options = new ParquetOptions { CompressionMethod = CompressionMethod.Zstd, CompressionLevel = CompressionLevel.SmallestSize, RowGroupSize = 5_000_000, PropertyNameCaseInsensitive = true }; await ParquetSerializer.SerializeAsync(data, "output.parquet", options); ``` -------------------------------- ### Default Compression Method Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/README.md Specifies the default compression method used for Parquet files. ```csharp CompressionMethod.Snappy ``` -------------------------------- ### Parquet Namespace Coverage Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Details the completeness of documentation for the main Parquet namespace, including readers, writers, and options. ```text Parquet ✓ Complete ├── ParquetReader ✓ Full signature + examples ├── ParquetWriter ✓ Full signature + examples ├── ParquetRowGroupReader ✓ Full signature + examples ├── ParquetRowGroupWriter ✓ Full signature + examples ├── ParquetOptions ✓ All properties + examples ├── ParquetException ✓ Error conditions ├── CompressionMethod ✓ All values └── EncodingHint ✓ All values ``` -------------------------------- ### Create a MapField Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Instantiate a MapField to represent a dictionary or key-value pair column. Ensure the key field is non-nullable. ```csharp new MapField("attributes", new DataField("key"), new DataField("value")); ``` -------------------------------- ### Create a DecimalDataField Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Configure a DecimalDataField with specific precision and scale for custom decimal storage. Optionally force byte array encoding. ```csharp new DecimalDataField("price", precision: 10, scale: 2); ``` -------------------------------- ### Set Dictionary Encoding Threshold and Sample Size Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Configure the threshold for using dictionary encoding and the sample size for determining uniqueness. This helps optimize storage for columns with repeating values. ```csharp var options = new ParquetOptions { DictionaryEncodingThreshold = 0.7, // Use dict if ≤70% unique DictionaryEncodingSampleSize = 10000 // Sample first 10k before full scan }; ``` -------------------------------- ### Define Schema with List of Structures Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Defines a Parquet schema for a list of 'item' structures, where each item has product ID, quantity, and price. ```csharp var schema = new ParquetSchema( new DataField("order_id"), new ListField("items", new StructField("item", new DataField("product_id"), new DataField("quantity"), new DataField("price")))); ``` -------------------------------- ### Best Compression Parquet Configuration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure ParquetOptions for best compression using Zstd compression and smallest size compression level. ```csharp var options = new ParquetOptions { CompressionMethod = CompressionMethod.Zstd, CompressionLevel = CompressionLevel.SmallestSize, DictionaryEncodingThreshold = 0.5, RowGroupSize = 5_000_000 }; ``` -------------------------------- ### Type Conversion Configuration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure type conversions for dates, time, and byte arrays during Parquet operations. ```csharp var options = new ParquetOptions { UseDateOnlyTypeForDates = true, UseTimeOnlyTypeForTimeMillis = true, TreatByteArrayAsString = true, UseBigDecimal = false }; ``` -------------------------------- ### Default Nullability for List of Structures Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Illustrates the default low-level Parquet schema generated for a nullable list of structures, where both the list and its elements are optional. ```csharp class MovementHistory { public List
? Addresses { get; set; } } ``` ```plaintext OPTIONAL group Addresses (LIST) { repeated group list { OPTIONAL group element { OPTIONAL binary Country (UTF8); OPTIONAL binary City (UTF8); } } } ``` -------------------------------- ### Read Raw Column Data with Definition and Repetition Levels Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-reader.md Use this advanced method for direct access to definition and repetition levels when working with complex nested types. Ensure required buffers are provided and correctly sized. ```csharp public async ValueTask ReadRawAsync( DataField field, Memory values, Memory? definitionLevels, Memory? repetitionLevels, CancellationToken cancellationToken = default) where T : struct ``` ```csharp DataField listField = reader.Schema.FindDataField("items"); int[] values = new int[100]; // Estimated capacity int[] definitionLevels = new int[100]; int[] repetitionLevels = new int[100]; await groupReader.ReadRawAsync( listField, values.AsMemory(), definitionLevels.AsMemory(), repetitionLevels.AsMemory()); ``` -------------------------------- ### WriteAsync (byte array convenience overload) Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md A convenience overload for writing binary columns. It automatically converts the input collection to ReadOnlyMemory. ```APIDOC ## WriteAsync (byte array convenience overload) ### Description A convenience overload for writing binary columns. It automatically converts the input collection to ReadOnlyMemory. ### Method `public async Task WriteAsync( DataField field, IReadOnlyCollection values, ReadOnlyMemory? repetitionLevels = null)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | field | DataField | Yes | — | Binary field from schema | | values | IReadOnlyCollection | Yes | — | Binary values | | repetitionLevels | ReadOnlyMemory? | No | null | Repetition levels | ### Returns `Task` — Completes when write finishes ### Example ```csharp byte?[] binaryData = { new byte[] { 1, 2, 3 }, null, new byte[] { 4, 5 } }; await groupWriter.WriteAsync(binaryField, binaryData); ``` ``` -------------------------------- ### Define C# Class for List of Structures Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Defines a C# 'Order' class with a 'List' to represent a list of structured items. ```csharp class Order { public int OrderId { get; set; } class Item { public int ProductId { get; set; } public int Quantity { get; set; } public decimal Price { get; set; } } public List Items { get; set; } } ``` -------------------------------- ### Instantiate DataField Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Create a DataField instance specifying its name, .NET type, and optional nullability or array properties. Use this when the .NET type cannot be inferred directly or when overriding default behavior. ```csharp new DataField("id"); new DataField("name", typeof(string)); new DataField("optional_value", typeof(int?)); new DataField("tags", typeof(List)); ``` -------------------------------- ### WriteAsync (string convenience overload) Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-writer.md A convenience overload for writing string columns. It automatically converts the input collection to ReadOnlyMemory. ```APIDOC ## WriteAsync (string convenience overload) ### Description A convenience overload for writing string columns. It automatically converts the input collection to ReadOnlyMemory. ### Method `public async Task WriteAsync( DataField field, IReadOnlyCollection values, ReadOnlyMemory? repetitionLevels = null)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | field | DataField | Yes | — | String field from schema | | values | IReadOnlyCollection | Yes | — | String values | | repetitionLevels | ReadOnlyMemory? | No | null | Repetition levels | ### Returns `Task` — Completes when write finishes ### Example ```csharp string[] names = { "Alice", "Bob", "Carol" }; await groupWriter.WriteAsync(nameField, names); ``` ``` -------------------------------- ### ParquetException Constructors Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/errors.md Provides standard constructors for creating ParquetException instances, allowing for default exceptions, messages, and inner exceptions. ```csharp public ParquetException() public ParquetException(string message) public ParquetException(string message, Exception inner) ``` -------------------------------- ### Parquet Writer API Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Documentation for writing Parquet files and streams using Parquet.Net. Includes factory methods, metadata handling, row group creation, and append mode. ```APIDOC ## Parquet Writer API ### Description Provides methods for writing Parquet files and streams. ### Factory Method - `CreateAsync()`: Asynchronously creates a Parquet writer. ### Properties - `CustomMetadata`: Gets or sets custom metadata for the file. ### Methods - `CreateRowGroup()`: Creates a new row group for writing data. ### Features - Append mode handling for adding data to existing files. ``` -------------------------------- ### Control List Element Nullability Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Illustrates how to control nullability for both the list container and its elements using Parquet attributes. ```csharp class Container { [ParquetRequired] public List
Addresses { get; set; } // List container required [ParquetRequired, ParquetListElementRequired] public List
Addresses2 { get; set; } // Elements also required } ``` -------------------------------- ### Serialize C# Objects with List of Structures Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Serializes a list of 'Order' objects, each containing a list of 'Item' objects, to a Parquet file. ```csharp var orders = new List { new Order { OrderId = 1, Items = new List { new Order.Item { ProductId = 100, Quantity = 2, Price = 29.99m }, new Order.Item { ProductId = 101, Quantity = 1, Price = 49.99m } } } }; await ParquetSerializer.SerializeAsync(orders, "orders.parquet"); ``` -------------------------------- ### Append with Schema Check Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md This code demonstrates appending data to an existing Parquet file. It will throw a ParquetException if the new schema does not exactly match the existing file's schema. ```csharp // This will throw ParquetException if schemas don't match await using ParquetWriter writer = await ParquetWriter.CreateAsync(newSchema, fs, append: true); ``` -------------------------------- ### ParquetWriter.CreateAsync Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-writer.md Factory method to create a new ParquetWriter instance. It initializes the writer on a given stream with a specified schema and optional configurations. ```APIDOC ## ParquetWriter.CreateAsync ### Description Creates a Parquet writer on top of a stream. This method initializes the file structure, allowing for subsequent writing of row groups and metadata. ### Method `static async Task CreateAsync` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### Parameters - **schema** (ParquetSchema) - Required - Schema defining the file structure - **output** (Stream) - Required - Writeable, seekable stream for output - **options** (ParquetOptions?) - Optional - Writer configuration options - **append** (bool) - Optional - When true, appends to existing file; must be false for new files (default: false) - **cancellationToken** (CancellationToken) - Optional - Cancellation token (default: default) ### Request Example ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name")); var fs = File.Create("output.parquet"); await using ParquetWriter writer = await ParquetWriter.CreateAsync(schema, fs); using ParquetRowGroupWriter groupWriter = writer.CreateRowGroup(); await groupWriter.WriteAsync(schema.DataFields[0], new[] { 1, 2, 3 }); await groupWriter.WriteAsync(schema.DataFields[1], new[] { "Alice", "Bob", "Carol" }); ``` ### Response #### Success Response - **ParquetWriter** - Initialized writer instance #### Response Example (Instance of ParquetWriter) ### Throws - `ArgumentNullException` — If schema or output is null - `ArgumentException` — If output stream is not writeable - `IOException` — If append is true but stream is empty or not seekable ``` -------------------------------- ### Advanced Usage Patterns Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Explores complex usage scenarios in Parquet.Net, including nested types, definition/repetition levels, custom serialization, metadata operations, and performance optimization. ```APIDOC ## Advanced Usage Patterns ### Description Covers advanced techniques and complex usage patterns for Parquet.Net. ### Key Topics - **Nested Type Handling**: Structures, lists (primitives, structures), maps. - **Definition and Repetition Levels**: Explanation and examples. - **Nullable Types**: Handling of nullable fields and attributes. - **Custom Type Serialization**: Dates, decimals, TimeSpans. - **Metadata Operations**: Writing, reading, per-column metadata. - **Row Group Management**: Multiple row groups, parallel reading. - **Encoding Configuration**: Per-column hints, thresholds. - **Property Mapping**: Custom names, case-insensitivity, reordering. - **Large Decimal Handling**. - **Untyped Serialization**. - **File Merging Utility**. - **Performance Optimization Patterns**. - **Schema Evolution Techniques**. ``` -------------------------------- ### Parquet.Schema Namespace Coverage Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Details the completeness of documentation for the Parquet.Schema namespace, covering schema representation and field types. ```text Parquet.Schema ✓ Complete ├── ParquetSchema ✓ Full API ├── Field ✓ Base + derived ├── DataField ✓ Full coverage ├── ListField ✓ Full coverage ├── StructField ✓ Full coverage ├── MapField ✓ Full coverage ├── DateTimeDataField ✓ Covered ├── DecimalDataField ✓ Covered ├── TimeSpanDataField ✓ Covered ├── BigDecimalDataField ✓ Covered ├── FieldPath ✓ Covered └── SchemaType ✓ All values ``` -------------------------------- ### Serialize Data to Parquet File Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Use the ParquetSerializer to asynchronously write the generated data to a Parquet file. Ensure the file path is accessible. ```csharp await ParquetSerializer.SerializeAsync(data, "/mnt/storage/data.parquet"); ``` -------------------------------- ### Process Data from Multiple Row Groups Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-reader.md Demonstrates iterating through all row groups in a Parquet file, opening a reader for each, and reading data for a specific field. Replace `field` and `ProcessData` with your actual field and processing logic. ```csharp for(int rgIdx = 0; rgIdx < reader.RowGroupCount; rgIdx++) { using ParquetRowGroupReader groupReader = reader.OpenRowGroupReader(rgIdx); var data = new int[groupReader.RowCount]; await groupReader.ReadAsync(field, data); ProcessData(data); } ``` -------------------------------- ### Read Raw Column Data with Pre-allocated Buffers Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-row-group-reader.md This method pre-allocates necessary buffers for raw column data. The returned RawColumnData must be disposed to return buffers to the pool. ```csharp internal async ValueTask> ReadRawColumnDataAsync( DataField field, CancellationToken cancellationToken = default) where T : struct ``` ```csharp using RawColumnData raw = await groupReader.ReadRawColumnDataAsync(field); int[] values = raw.Values.Memory.ToArray(); int[]? defLevels = raw.DefinitionLevels?.Memory.ToArray(); int[]? repLevels = raw.RepetitionLevels?.Memory.ToArray(); ``` -------------------------------- ### Parquet Reader API Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/INDEX.md Documentation for reading Parquet files and streams using Parquet.Net. Covers factory methods, schema access, row group reading, and asynchronous operations. ```APIDOC ## Parquet Reader API ### Description Provides methods for reading Parquet files and streams. ### Factory Methods - `CreateAsync()`: Asynchronously creates a Parquet reader. ### Properties - `Schema`: Gets the schema of the Parquet file. - `RowGroupCount`: Gets the number of row groups in the file. - `CustomMetadata`: Gets the custom metadata associated with the file. ### Methods - `OpenRowGroupReader()`: Opens a reader for a specific row group. - `ReadSchemaAsync()`: Asynchronously reads the schema of the Parquet file. ``` -------------------------------- ### Serialize C# Objects with Maps Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/advanced-patterns.md Serializes a list of 'Item' objects, each containing a dictionary of string attributes, to a Parquet file. ```csharp var items = new List { new Item { Id = 1, Attributes = new Dictionary { { "color", "red" }, { "size", "large" } } } }; await ParquetSerializer.SerializeAsync(items, "items.parquet"); ``` -------------------------------- ### Write and Read DataFrame to/from Parquet Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Use extension methods to write a DataFrame to a stream or read from a stream into a DataFrame. Only atomic columns are supported. ```C# DataFrame df; await df.WriteAsync(stream); DataFrame dfr = await stream.ReadParquetAsDataFrameAsync(); ``` -------------------------------- ### Safe Parquet Serialization Pattern Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/errors.md Demonstrates safe deserialization of a Parquet file into a C# object using ParquetSerializer. It includes exception handling for ArgumentNullException, FileNotFoundException, ParquetException, and ApplicationException related to serialization issues. ```csharp try { var result = await ParquetSerializer.DeserializeAsync("file.parquet"); Console.WriteLine($"Loaded {result.Data.Count} records"); } catch(ArgumentNullException ex) { Console.WriteLine($"Missing parameter: {ex.ParamName}"); } catch(FileNotFoundException) { Console.WriteLine("File not found"); } catch(ParquetException ex) { Console.WriteLine($"Invalid Parquet file: {ex.Message}"); } catch(ApplicationException ex) when(ex.Message.Contains("serialise")) { Console.WriteLine("Serialization failed"); } ``` -------------------------------- ### Set Compression Level Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure the compression effort level for Parquet data. This allows balancing compression ratio against speed, with options ranging from Fastest to Optimal. ```csharp var options = new ParquetOptions { CompressionMethod = CompressionMethod.Zstd, CompressionLevel = CompressionLevel.Optimal }; ``` -------------------------------- ### Memory-Constrained Parquet Configuration Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/configuration.md Configure ParquetOptions for memory-constrained environments by setting maximum pool free bytes and a smaller row group size. ```csharp var options = new ParquetOptions { MaximumSmallPoolFreeBytes = 4 * 1024 * 1024, MaximumLargePoolFreeBytes = 16 * 1024 * 1024, RowGroupSize = 100_000 }; ``` -------------------------------- ### Create ParquetReader from Stream Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/parquet-reader.md Creates a Parquet reader from an input stream. The stream must be readable and seekable. Use this when reading from sources like network streams or memory streams. The `leaveStreamOpen` parameter controls whether the stream is closed upon reader disposal. ```csharp using var fs = File.OpenRead("data.parquet"); await using ParquetReader reader = await ParquetReader.CreateAsync(fs, leaveStreamOpen: false); ``` -------------------------------- ### ParquetSchema Constructors Source: https://github.com/aloneguid/parquet-dotnet/blob/master/_autodocs/api-reference/schema-classes.md Represents the complete dataset schema as a collection of fields. Use these constructors to create a new ParquetSchema instance with specified fields. ```APIDOC ## ParquetSchema Constructors ### Description Represents the complete dataset schema as a collection of fields. Use these constructors to create a new ParquetSchema instance with specified fields. ### Constructor ```csharp public ParquetSchema(params Field[] fields) public ParquetSchema(IEnumerable fields) ``` ### Parameters #### Path Parameters - **fields** (Field[] or IEnumerable) - Required - At least one field required ### Request Example ```csharp var schema = new ParquetSchema( new DataField("id"), new DataField("name"), new DataField("salary")); ``` ``` -------------------------------- ### Append Data to Parquet File Source: https://github.com/aloneguid/parquet-dotnet/blob/master/docs/README.md Illustrates how to append new data to an existing Parquet file by creating and writing to a new row group. Note that existing row groups are immutable. ```csharp //write a file with a single row group var id = new DataField("id"); var schema = new ParquetSchema(id); var ms = new MemoryStream(); await using(ParquetWriter writer = await ParquetWriter.CreateAsync(schema, ms)) { using(ParquetRowGroupWriter rg = writer.CreateRowGroup()) { await rg.WriteAsync(id, new int[] { 1, 2 }); } } //append to this file. Note that you cannot append to existing row group, therefore create a new one ms.Position = 0; // this is to rewind our memory stream, no need to do it in real code. await using(ParquetWriter writer = await ParquetWriter.CreateAsync(schema, ms, append: true)) { using(ParquetRowGroupWriter rg = writer.CreateRowGroup()) { await rg.WriteAsync(id, new int[] { 3, 4 }); } } //check that this file now contains two row groups and all the data is valid ms.Position = 0; await using(ParquetReader reader = await ParquetReader.CreateAsync(ms)) { Assert.Equal(2, reader.RowGroupCount); using(ParquetRowGroupReader rg = reader.OpenRowGroupReader(0)) { Assert.Equal(2, rg.RowCount); int[] values0 = new int[rg.RowCount]; await rg.ReadAsync(id, values0); Assert.Equal(new int[] { 1, 2 }, values0); } using(ParquetRowGroupReader rg = reader.OpenRowGroupReader(1)) { Assert.Equal(2, rg.RowCount); int[] values1 = new int[rg.RowCount]; await rg.ReadAsync(id, values1); Assert.Equal(new int[] { 3, 4 }, values1); } } ```