Skip to content

Commit a7323ad

Browse files
vkuttypCopilot
andcommitted
Add SQLDataTable.toJson() - render rows as clean JSON array
Uses JSONSerialization for native type mapping: - bool/int/double/decimal → native JSON types - string → JSON string - null → JSON null - date → ISO-8601 string - bytes → base64 string - uuid → UUID string pretty: true (default) for indented output, false for compact. Mirrors .NET ToJson() added in CosmoSQLClient v1.2.5. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8852c9e commit a7323ad

49 files changed

Lines changed: 2577 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Sources/CosmoSQLCore/SQLDataTable.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ public enum SQLCellValue: Sendable, Equatable {
5454

5555
public var isNull: Bool { if case .null = self { return true }; return false }
5656

57+
/// Native value for use with JSONSerialization (nil = JSON null).
58+
var jsonValue: Any? {
59+
switch self {
60+
case .null: return nil
61+
case .bool(let v): return v
62+
case .int(let v): return v
63+
case .int64(let v): return v
64+
case .double(let v): return v
65+
case .decimal(let v): return NSDecimalNumber(decimal: v)
66+
case .string(let v): return v
67+
case .bytes(let v): return Data(v).base64EncodedString()
68+
case .uuid(let v): return v.uuidString
69+
case .date(let v):
70+
let f = ISO8601DateFormatter()
71+
f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
72+
return f.string(from: v)
73+
}
74+
}
75+
5776
/// Human-readable string for display / Markdown rendering.
5877
public var displayString: String {
5978
switch self {
@@ -208,6 +227,23 @@ public struct SQLDataTable: Sendable {
208227
return try toSQLRows().map { try decoder.decode(T.self, from: $0) }
209228
}
210229

230+
// MARK: JSON rendering
231+
232+
/// Renders the table as a JSON array of objects (column name → native value).
233+
/// SQL NULL becomes JSON `null`. Dates are ISO-8601 strings.
234+
public func toJson(pretty: Bool = true) -> String {
235+
let array = rows.map { row -> [String: Any?] in
236+
Dictionary(uniqueKeysWithValues: zip(columns.map(\.name), row.map(\.jsonValue)))
237+
}
238+
// JSONSerialization needs [String: Any] with NSNull for nulls
239+
let sanitized = array.map { dict in
240+
dict.mapValues { $0 ?? NSNull() as Any }
241+
}
242+
let opts: JSONSerialization.WritingOptions = pretty ? [.prettyPrinted, .sortedKeys] : []
243+
let data = (try? JSONSerialization.data(withJSONObject: sanitized, options: opts)) ?? Data()
244+
return String(data: data, encoding: .utf8) ?? "[]"
245+
}
246+
211247
// MARK: Markdown rendering
212248

213249
/// Renders the table as a GitHub-flavored Markdown table string.

cosmo-swift/Package.resolved

Lines changed: 78 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cosmo-swift/Package.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// swift-tools-version: 6.0
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "cosmo-swift",
6+
platforms: [.macOS(.v13)],
7+
dependencies: [
8+
.package(path: ".."),
9+
],
10+
targets: [
11+
.executableTarget(
12+
name: "cosmo-swift",
13+
dependencies: [
14+
.product(name: "CosmoMSSQL", package: "sql-nio"),
15+
]
16+
),
17+
]
18+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import CosmoMSSQL
2+
import CosmoSQLCore
3+
4+
print("Hello, World!")
5+
6+
let conn = try await MSSQLConnection.connect(configuration: .init(
7+
connectionString: "Server=localhost,1433;Database=MurshiDb;User Id=sa;Password=aBCD111;Encrypt=true;TrustServerCertificate=true"
8+
))
9+
defer { Task { try? await conn.close() } }
10+
11+
let rows = try await conn.query("SELECT TOP 3 AccountNo, AccountName, AccountTypeID, IsMain FROM Accounts", [])
12+
let table = rows.asDataTable(name: "Accounts")
13+
14+
print("Rows: \(table.rowCount), Columns: \(table.columnCount)")
15+
print(table.toJson())

cosmo/Program.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// See https://aka.ms/new-console-template for more information
2+
using CosmoSQLClient.Core;
3+
using CosmoSQLClient.MsSql;
4+
5+
Console.WriteLine("Hello, World!");
6+
await using var conn = await MsSqlConnection.OpenAsync(
7+
"Server=localhost,1433;Database=MurshiDb;User Id=sa;Password=aBCD111;Encrypt=True;TrustServerCertificate=True;");
8+
9+
var table = await conn.QueryTableAsync("SELECT TOP 3 AccountNo, AccountName, AccountTypeID, IsMain FROM Accounts");
10+
11+
Console.WriteLine(table.ToJson());
12+
13+
public class Account
14+
{
15+
public string? AccountNo { get; set; }
16+
public string? AccountName { get; set; }
17+
public int AccountTypeID { get; set; }
18+
public bool IsMain { get; set; }
19+
}
44.5 KB
Binary file not shown.
23.4 KB
Binary file not shown.
84.5 KB
Binary file not shown.
36 KB
Binary file not shown.
176 KB
Binary file not shown.

0 commit comments

Comments
 (0)