Kinetica   C#   API  Version 7.2.3.1
AsyncRecordRetrieverTests.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Threading.Tasks;
4 using Xunit;
6 using kinetica;
7 
9 {
15  [Trait("Category", "Integration")]
16  [Trait("Category", "Async")]
18  {
22  private async Task<string> SetupShardedTableAsync(TestContext ctx, int numRecords)
23  {
24  // Create type with shard keys
25  var typeDef = @"{""type"":""record"",""name"":""simple_record"",""fields"":[{""name"":""id"",""type"":""int""},{""name"":""name_sk"",""type"":""string""},{""name"":""value_sk"",""type"":""int""},{""name"":""score"",""type"":""double""}]}";
26 
27  var properties = new Dictionary<string, IList<string>>
28  {
29  { "id", new List<string>() },
30  { "name_sk", new List<string> { "shard_key" } },
31  { "value_sk", new List<string> { "shard_key" } },
32  { "score", new List<string>() }
33  };
34 
35  var typeResp = await ctx.Kinetica.CreateTypeAsync(typeDef, "test_retriever_type", properties, new Dictionary<string, string>());
36 
37  var tableName = ctx.QualifiedTable("test_retriever");
38  await ctx.Kinetica.CreateTableAsync(tableName, typeResp.type_id, new Dictionary<string, string>());
39 
40  // Create indices on shard key columns for multi-head lookup
41  foreach (var col in new[] { "name_sk", "value_sk" })
42  {
43  try
44  {
45  await ctx.Kinetica.AlterTableAsync(tableName, "create_index", col, new Dictionary<string, string>());
46  }
47  catch { /* Ignore if index already exists */ }
48  }
49 
50  // Insert test data using SQL
51  for (int i = 0; i < numRecords; i++)
52  {
53  var nameSk = $"name_{i:D5}";
54  var valueSk = i;
55  var score = (i % 10) * 10.0;
56  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} (id, name_sk, value_sk, score) VALUES ({i}, '{nameSk}', {valueSk}, {score})");
57  }
58 
59  return tableName;
60  }
61 
62  [Fact]
63  public async Task TestGetRecordsBasicAsync()
64  {
65  using var ctx = new TestContext("async_get_records_basic");
66  var numRecords = 50;
67  var tableName = await SetupShardedTableAsync(ctx, numRecords);
68 
69  // Verify table has expected records using SQL
70  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 0, -9999);
71  Console.WriteLine($"Table has {response.total_number_of_records} records (expected {numRecords})");
72 
73  Assert.Equal(numRecords, response.total_number_of_records);
74  Assert.Equal(numRecords, response.data.Count);
75  }
76 
77  [Fact]
78  public async Task TestGetRecordsByShardKeyAsync()
79  {
80  using var ctx = new TestContext("async_get_records_key");
81  var numRecords = 20;
82  var tableName = await SetupShardedTableAsync(ctx, numRecords);
83 
84  // Test: Retrieve record by shard key values
85  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} WHERE name_sk = 'name_00005' AND value_sk = 5", 0, -9999);
86 
87  Console.WriteLine($"Query by shard key returned {response.total_number_of_records} records");
88  Assert.Equal(1, response.total_number_of_records);
89  }
90 
91  [Fact]
93  {
94  using var ctx = new TestContext("async_get_records_expr");
95  var tableName = await SetupShardedTableAsync(ctx, 50);
96 
97  // Test: Retrieve with expression filter
98  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} WHERE id < 25", 0, -9999);
99  Console.WriteLine($"Query with expression returned {response.total_number_of_records} records (expected 25)");
100 
101  Assert.Equal(25, response.total_number_of_records);
102 
103  // Test: Retrieve with combined expression
104  var response2 = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} WHERE id >= 40 AND score < 50", 0, -9999);
105  Console.WriteLine($"Query with combined expression returned {response2.total_number_of_records} records");
106 
107  Assert.True(response2.total_number_of_records >= 0);
108  }
109 
110  [Fact]
112  {
113  using var ctx = new TestContext("async_get_records_multi");
114  var numRecords = 30;
115  var tableName = await SetupShardedTableAsync(ctx, numRecords);
116 
117  var totalFound = 0;
118 
119  // Search for multiple records by key
120  for (int i = 0; i < 10; i++)
121  {
122  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} WHERE name_sk = 'name_{i:D5}' AND value_sk = {i}", 0, -9999);
123  totalFound += (int)response.total_number_of_records;
124  }
125 
126  Console.WriteLine($"Multi-key retrieval: found {totalFound} records");
127  Assert.Equal(10, totalFound); // Each key should find exactly 1 record
128  }
129 
130  [Fact]
131  public async Task TestGetRecordsWithSortingAsync()
132  {
133  using var ctx = new TestContext("async_get_records_sort");
134  var tableName = await SetupShardedTableAsync(ctx, 25);
135 
136  // Test: Retrieve with sorting
137  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} ORDER BY score DESC, id ASC", 0, -9999);
138 
139  Console.WriteLine($"Sorted query returned {response.total_number_of_records} records");
140  Assert.Equal(25, response.total_number_of_records);
141  }
142 
143  [Fact]
144  public async Task TestGetRecordsPaginationAsync()
145  {
146  using var ctx = new TestContext("async_get_records_page");
147  var numRecords = 50;
148  var tableName = await SetupShardedTableAsync(ctx, numRecords);
149 
150  // Get first page
151  var page1 = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 0, 10);
152  Assert.Equal(50, page1.total_number_of_records);
153  Assert.Equal(10, page1.data.Count);
154  Assert.True(page1.has_more_records);
155 
156  // Get second page
157  var page2 = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 10, 10);
158  Assert.Equal(10, page2.data.Count);
159  Assert.True(page2.has_more_records);
160 
161  // Get last page
162  var lastPage = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 40, 10);
163  Assert.Equal(10, lastPage.data.Count);
164  Assert.False(lastPage.has_more_records);
165  }
166 
167  [Fact]
168  public async Task TestGetRecordsEmptyTableAsync()
169  {
170  using var ctx = new TestContext("async_get_records_empty");
171  var tableName = await SetupShardedTableAsync(ctx, 0);
172 
173  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 0, -9999);
174 
175  Assert.Equal(0, response.total_number_of_records);
176  Assert.Empty(response.data);
177  Assert.False(response.has_more_records);
178  }
179 
180  [Fact]
182  {
183  using var ctx = new TestContext("async_get_records_offset");
184  var tableName = await SetupShardedTableAsync(ctx, 10);
185 
186  // Offset beyond table size
187  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}", 100, 10);
188 
189  Assert.Equal(10, response.total_number_of_records);
190  Assert.Empty(response.data);
191  }
192 
193  [Fact]
195  {
196  using var ctx = new TestContext("async_get_records_cols");
197  var tableName = await SetupShardedTableAsync(ctx, 20);
198 
199  // Select specific columns
200  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT id, score FROM {tableName} WHERE id < 10", 0, -9999);
201 
202  Assert.Equal(10, response.total_number_of_records);
203  Assert.Equal(10, response.data.Count);
204  }
205 
206  [Fact]
208  {
209  using var ctx = new TestContext("async_get_records_agg");
210  var tableName = await SetupShardedTableAsync(ctx, 100);
211 
212  // Test aggregation
213  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT COUNT(*), AVG(score) FROM {tableName}", 0, -9999);
214 
215  Assert.Equal(1, response.total_number_of_records);
216  Assert.Single(response.data);
217  }
218 
219  [Fact]
220  public async Task TestGetRecordsGroupByAsync()
221  {
222  using var ctx = new TestContext("async_get_records_group");
223  var tableName = await SetupShardedTableAsync(ctx, 30);
224 
225  // Group by score (there should be 10 distinct scores: 0, 10, 20, ..., 90)
226  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT score, COUNT(*) as cnt FROM {tableName} GROUP BY score ORDER BY score", 0, -9999);
227 
228  Assert.Equal(10, response.total_number_of_records);
229  }
230  }
231 }
Test context that manages schema and cleanup for integration tests.
Definition: TestContext.cs:11
string QualifiedTable(string tableName)
Get a qualified table name (schema.table).
Definition: TestContext.cs:74