Skip to content
This repository was archived by the owner on Apr 27, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests
  • Loading branch information
vkhobor committed Jan 22, 2026
commit e3fca7da9dff55b8d04608707bcd810ce6797943
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.CSharp;
using Microsoft.DotNet.Interactive.App;
using Microsoft.DotNet.Interactive.Commands;
using FluentAssertions;
using Xunit;
using System.Collections.Generic;

namespace Microsoft.DotNet.Interactive.PostgreSql.Tests;

Expand Down Expand Up @@ -82,155 +84,154 @@ public async Task It_returns_error_if_query_is_not_valid()
.Contain("column \"not_known_column\" does not exist");
}

// public async Task When_variable_does_not_exist_then_an_error_is_returned()
// {
// var connectionString = MsSqlFactAttribute.GetConnectionStringForTests();
// using var kernel = await CreateKernelAsync();
// var result = await kernel.SubmitCodeAsync(
// $"#!connect mssql --kernel-name adventureworks \"{connectionString}\"");

// result.Events
// .Should()
// .NotContainErrors();

// var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

// result = await sqlKernel.SendAsync(new RequestValue("my_data_result"));

// result.Events.Should()
// .ContainSingle<CommandFailed>()
// .Which
// .Message
// .Should()
// .Contain("Value 'my_data_result' not found in kernel sql-adventureworks");
// }

// [MsSqlFact]
// public async Task It_can_store_result_set_with_a_name()
// {
// var connectionString = MsSqlFactAttribute.GetConnectionStringForTests();
// using var kernel = await CreateKernelAsync();
// await kernel.SubmitCodeAsync(
// $"#!connect mssql --kernel-name adventureworks \"{connectionString}\"");

// // Run query with result set
// await kernel.SubmitCodeAsync($@"
// #!sql-adventureworks --name my_data_result
// select * from sys.databases
// ");

// // Use share to fetch result set
// var result = await kernel.SubmitCodeAsync($@"
// #!csharp
// #!share --from sql-adventureworks my_data_result
// my_data_result");

// // Verify the variable loaded is of the correct type and has the expected number of result sets
// result.Events
// .Should()
// .ContainSingle<ReturnValueProduced>()
// .Which
// .Value
// .Should()
// .BeAssignableTo<IEnumerable<TabularDataResource>>()
// .Which.Count()
// .Should()
// .Be(1);
// }

// [MsSqlFact]
// public async Task Stored_query_results_are_listed_in_ValueInfos()
// {
// var connectionString = MsSqlFactAttribute.GetConnectionStringForTests();
// using var kernel = await CreateKernelAsync();
// await kernel.SubmitCodeAsync(
// $"#!connect mssql --kernel-name adventureworks \"{connectionString}\"");

// // Run query with result set
// await kernel.SubmitCodeAsync($@"
// #!sql-adventureworks --name my_data_result
// select * from sys.databases
// ");

// var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

// var result = await sqlKernel.SendAsync(new RequestValueInfos());

// var valueInfos = result.Events.Should().ContainSingle<ValueInfosProduced>()
// .Which.ValueInfos;

// valueInfos.Should().Contain(v => v.Name == "my_data_result");
// }

// [MsSqlFact]
// public async Task Storing_results_does_interfere_with_subsequent_executions()
// {
// var connectionString = MsSqlFactAttribute.GetConnectionStringForTests();
// using var kernel = await CreateKernelAsync();
// await kernel.SubmitCodeAsync(
// $"#!connect mssql --kernel-name adventureworks \"{connectionString}\"");

// // Run query with result set
// await kernel.SubmitCodeAsync($@"
// #!sql-adventureworks --name my_data_result
// select * from sys.databases
// ");

// var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

// var result = await sqlKernel.SendAsync(new RequestValueInfos());

// var valueInfos = result.Events.Should().ContainSingle<ValueInfosProduced>()
// .Which.ValueInfos;

// valueInfos.Should().Contain(v => v.Name == "my_data_result");

// result = await kernel.SubmitCodeAsync($@"
// #!sql-adventureworks --name my_data_result
// select * from sys.databases
// ");

// result.Events.Should().NotContainErrors();
// }

// [MsSqlFact]
// public async Task It_can_store_multiple_result_set_with_a_name()
// {
// var connectionString = MsSqlFactAttribute.GetConnectionStringForTests();
// using var kernel = await CreateKernelAsync();
// await kernel.SubmitCodeAsync(
// $"#!connect mssql --kernel-name adventureworks \"{connectionString}\"");

// // Run query with result set
// await kernel.SubmitCodeAsync($@"
// #!sql-adventureworks --name my_data_result
// select * from sys.databases
// select * from sys.databases
// ");

// // Use share to fetch result set
// var result = await kernel.SubmitCodeAsync($@"
// #!csharp
// #!share --from sql-adventureworks my_data_result
// my_data_result");

// // Verify the variable loaded is of the correct type and has the expected number of result sets
// result.Events
// .Should()
// .ContainSingle<ReturnValueProduced>()
// .Which
// .Value
// .Should()
// .BeAssignableTo<IEnumerable<TabularDataResource>>()
// .Which.Count()
// .Should()
// .Be(2);
// }
[PostgreSqlFact]
public async Task When_variable_does_not_exist_then_an_error_is_returned()
{
var connectionString = PostgreSqlFactAttribute.GetConnectionStringForTests();
using var kernel = CreateKernel();
var result = await kernel.SubmitCodeAsync(
$"#!connect postgres --kernel-name adventureworks \"{connectionString}\"");

result.Events
.Should()
.NotContainErrors();

var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

result = await sqlKernel.SendAsync(new RequestValue("my_data_result"));

result.Events.Should()
.ContainSingle<CommandFailed>()
.Which
.Message
.Should()
.Contain("Value 'my_data_result' not found in kernel sql-adventureworks");
}

[PostgreSqlFact]
public async Task It_can_store_result_set_with_a_name()
{
var connectionString = PostgreSqlFactAttribute.GetConnectionStringForTests();
using var kernel = CreateKernel();
await kernel.SubmitCodeAsync(
$"#!connect postgres --kernel-name adventureworks \"{connectionString}\"");

// Run query with result set
await kernel.SubmitCodeAsync($@"
#!sql-adventureworks --name my_data_result
SELECT * FROM customers LIMIT 10;
");

// Use share to fetch result set
var result = await kernel.SubmitCodeAsync($@"
#!csharp
#!share --from sql-adventureworks my_data_result
my_data_result");

// Verify the variable loaded is of the correct type and has the expected number of result sets
Comment thread
vkhobor marked this conversation as resolved.
Outdated
result.Events
.Should()
.ContainSingle<ReturnValueProduced>()
.Which
.Value
.Should()
.BeAssignableTo<IEnumerable<TabularDataResource>>()
.Which.Count()
.Should()
.Be(1);
}

[PostgreSqlFact]
public async Task Stored_query_results_are_listed_in_ValueInfos()
{
var connectionString = PostgreSqlFactAttribute.GetConnectionStringForTests();
using var kernel = CreateKernel();
await kernel.SubmitCodeAsync(
$"#!connect postgres --kernel-name adventureworks \"{connectionString}\"");

// Run query with result set
await kernel.SubmitCodeAsync($@"
#!sql-adventureworks --name my_data_result
SELECT * FROM customers LIMIT 10;
");

var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

var result = await sqlKernel.SendAsync(new RequestValueInfos());

var valueInfos = result.Events.Should().ContainSingle<ValueInfosProduced>()
.Which.ValueInfos;

valueInfos.Should().Contain(v => v.Name == "my_data_result");
}

[PostgreSqlFact]
public async Task Storing_results_does_interfere_with_subsequent_executions()
{
var connectionString = PostgreSqlFactAttribute.GetConnectionStringForTests();
using var kernel = CreateKernel();
await kernel.SubmitCodeAsync(
$"#!connect postgres --kernel-name adventureworks \"{connectionString}\"");

// Run query with result set
await kernel.SubmitCodeAsync($@"
#!sql-adventureworks --name my_data_result
SELECT * FROM customers LIMIT 10;
");

var sqlKernel = kernel.FindKernelByName("sql-adventureworks");

var result = await sqlKernel.SendAsync(new RequestValueInfos());

var valueInfos = result.Events.Should().ContainSingle<ValueInfosProduced>()
.Which.ValueInfos;

valueInfos.Should().Contain(v => v.Name == "my_data_result");

result = await kernel.SubmitCodeAsync($@"
#!sql-adventureworks --name my_data_result
SELECT * FROM customers LIMIT 10;
");

result.Events.Should().NotContainErrors();
}

[PostgreSqlFact]
public async Task It_can_store_multiple_result_set_with_a_name()
{
var connectionString = PostgreSqlFactAttribute.GetConnectionStringForTests();
using var kernel = CreateKernel();
await kernel.SubmitCodeAsync(
$"#!connect postgres --kernel-name adventureworks \"{connectionString}\"");

// Run query with result set
await kernel.SubmitCodeAsync($@"
#!sql-adventureworks --name my_data_result
SELECT * FROM customers LIMIT 5;
SELECT * FROM customers LIMIT 5;
");

// Use share to fetch result set
var result = await kernel.SubmitCodeAsync($@"
#!csharp
#!share --from sql-adventureworks my_data_result
my_data_result");

// Verify the variable loaded is of the correct type and has the expected number of result sets
result.Events
.Should()
.ContainSingle<ReturnValueProduced>()
.Which
.Value
.Should()
.BeAssignableTo<IEnumerable<TabularDataResource>>()
.Which.Count()
.Should()
.Be(2);
}

public void Dispose()
{
DataExplorer.ResetToDefault();
}
}
}
32 changes: 27 additions & 5 deletions src/Microsoft.DotNet.Interactive.PostgreSql/PostgreSqlKernel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Formatting;
using Microsoft.DotNet.Interactive.Formatting.TabularData;
using Microsoft.DotNet.Interactive.ValueSharing;
using Npgsql;
using Enumerable = System.Linq.Enumerable;

Expand All @@ -21,7 +22,8 @@ namespace Microsoft.DotNet.Interactive.PostgreSql;
public class PostgreSqlKernel :
Kernel,
IKernelCommandHandler<SubmitCode>,
IKernelCommandHandler<RequestValue>
IKernelCommandHandler<RequestValue>,
IKernelCommandHandler<RequestValueInfos>
{
private readonly string _connectionString;
private IEnumerable<IEnumerable<IEnumerable<(string name, object value)>>> _tables;
Expand Down Expand Up @@ -84,7 +86,8 @@ async Task IKernelCommandHandler<SubmitCode>.HandleAsync(
finally
{
submitCode.Parameters.TryGetValue("--name", out var queryName);
StoreQueryResultSet(queryName ?? "", results);
string name = queryName ?? "";
_resultSets[name] = results;
}
}

Expand Down Expand Up @@ -153,7 +156,7 @@ public static void AddPostgreSqlKernelConnectorToCurrentRoot()
}
}

public bool TryGetValue<T>(string name, out T value)
private bool TryGetValue<T>(string name, out T value)
{
if (_resultSets.TryGetValue(name, out var resultSet) &&
resultSet is T resultSetT)
Expand Down Expand Up @@ -186,8 +189,27 @@ Task IKernelCommandHandler<RequestValue>.HandleAsync(RequestValue command, Kerne
return Task.CompletedTask;
}

protected void StoreQueryResultSet(string name, IReadOnlyCollection<TabularDataResource> queryResultSet)
Task IKernelCommandHandler<RequestValueInfos>.HandleAsync(RequestValueInfos command, KernelInvocationContext context)
{
_resultSets[name] = queryResultSet;
var valueInfos = CreateKernelValueInfos(_resultSets, command.MimeType).ToArray();

context.Publish(new ValueInfosProduced(valueInfos, command));

return Task.CompletedTask;

static IEnumerable<KernelValueInfo> CreateKernelValueInfos(IReadOnlyDictionary<string, object> source, string mimeType)
{
return source.Keys.Select(key =>
{
var formattedValues = FormattedValue.CreateSingleFromObject(
source[key],
mimeType);

return new KernelValueInfo(
key,
formattedValues,
type: typeof(IEnumerable<TabularDataResource>));
});
}
}
}
Loading