You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Affected-row counts** — `rowsAffected` from `INSERT` / `UPDATE` / `DELETE`
@@ -234,6 +235,119 @@ try await client.run(
234
235
235
236
> **Note:** This uses string-level escaping (single-quote doubling). For maximum security with untrusted user input, prefer stored procedures.
236
237
238
+
### SQLDataTable & SQLDataSet
239
+
240
+
`SQLDataTable` is a typed, named result table — the Swift equivalent of .NET's `DataTable`. Each cell is a strongly-typed `SQLCellValue` enum, the table is `Codable` for JSON serialisation, and it can render itself as a Markdown table.
241
+
242
+
`SQLDataSet` is a collection of `SQLDataTable` instances, used when a query or stored procedure returns multiple result sets.
243
+
244
+
#### Fetching a single table
245
+
246
+
```swift
247
+
let table =tryawait client.dataTable("SELECT * FROM Users")
248
+
249
+
print(table.rowCount) // number of rows
250
+
print(table.columnCount) // number of columns
251
+
```
252
+
253
+
#### Cell access
254
+
255
+
```swift
256
+
// By row index and column name (case-insensitive)
257
+
let cell: SQLCellValue = table[0, "Name"]
258
+
259
+
// By row and column index
260
+
let cell: SQLCellValue = table[0, 0]
261
+
262
+
// As a typed value
263
+
switch table[0, "Age"] {
264
+
case .int32(let age):print("Age:", age)
265
+
case .null:print("Age unknown")
266
+
default:break
267
+
}
268
+
269
+
// As Any? for interop with existing code
270
+
let raw: Any?= table[0, "Name"].anyValue
271
+
272
+
// Whole row as a dictionary
273
+
let dict: [String: SQLCellValue] = table.row(at: 0)
274
+
275
+
// All values in a column
276
+
let names: [SQLCellValue] = table.column(named: "Name")
277
+
```
278
+
279
+
#### Markdown rendering
280
+
281
+
```swift
282
+
print(table.toMarkdown())
283
+
```
284
+
285
+
Output example:
286
+
287
+
```
288
+
| ID | Name | Email |
289
+
|---|---|---|
290
+
| 1 | Alice | alice@example.com |
291
+
| 2 | Bob | bob@example.com |
292
+
```
293
+
294
+
#### Decoding rows into a `Decodable` struct
295
+
296
+
```swift
297
+
structUser: Decodable {
298
+
let id: Int
299
+
let name: String
300
+
let email: String
301
+
}
302
+
303
+
let users: [User] =try table.decode()
304
+
```
305
+
306
+
#### JSON serialisation
307
+
308
+
`SQLDataTable` and `SQLDataSet` are fully `Codable`:
309
+
310
+
```swift
311
+
let json =tryJSONEncoder().encode(table)
312
+
let restored =tryJSONDecoder().decode(SQLDataTable.self, from: json)
313
+
```
314
+
315
+
#### Converting an existing `SQLClientResult`
316
+
317
+
```swift
318
+
let result =tryawait client.execute("SELECT * FROM Orders")
319
+
320
+
// First result set as SQLDataTable
321
+
let table = result.asDataTable(name: "Orders")
322
+
323
+
// All result sets as SQLDataSet
324
+
let ds = result.asSQLDataSet()
325
+
```
326
+
327
+
#### Multi-table — `SQLDataSet`
328
+
329
+
Use `dataSet()` when a stored procedure or batch returns more than one result set:
330
+
331
+
```swift
332
+
let ds =tryawait client.dataSet("EXEC sp_GetDashboard")
333
+
334
+
// Access by index
335
+
let summary = ds[0]
336
+
337
+
// Access by name (case-insensitive, uses the table name assigned by the procedure)
338
+
let details = ds["Details"]
339
+
340
+
print(ds.count) // number of tables
341
+
```
342
+
343
+
#### Backward compatibility
344
+
345
+
`SQLDataTable` can be converted back to `[SQLRow]` if you need to pass it to existing code:
346
+
347
+
```swift
348
+
let sqlRows: [SQLRow] = table.toSQLRows()
349
+
```
350
+
237
351
### Error Handling
238
352
239
353
All errors are thrown as `SQLClientError`, which conforms to `LocalizedError`:
|`sql_variant`, `cursor`, `table`| ⚠️ Not supported | — |
327
441
328
442
> **Date types note:**`date`, `time`, `datetime2`, and `datetimeoffset` are returned as `Date` when using TDS 7.3 or higher. FreeTDS 1.x defaults to `auto` protocol negotiation, which will select 7.3+ automatically for modern SQL Server versions. If you see strings instead of dates on an older server, set the `TDSVER` environment variable in your Xcode scheme to `7.3` or `auto`.
0 commit comments