-
-
Notifications
You must be signed in to change notification settings - Fork 744
/
Copy pathLineDumpFormat.swift
138 lines (122 loc) · 3.6 KB
/
LineDumpFormat.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Import C SQLite functions
#if GRDBCIPHER
import SQLCipher
#elseif SWIFT_PACKAGE
import GRDBSQLite
#elseif !GRDBCUSTOMSQLITE && !GRDBCIPHER
import SQLite3
#endif
import Foundation
/// A format that prints one line per database value. All blob values
/// are interpreted as strings.
///
/// For example:
///
/// ```swift
/// // name = Arthur
/// // score = 500
/// //
/// // name = Barbara
/// // score = 1000
/// try db.dumpRequest(Player.all(), format: .line())
/// ```
public struct LineDumpFormat: Sendable {
/// The string to print for NULL values.
public var nullValue: String
var firstRow = true
/// Creates a `LineDumpFormat`.
///
/// - Parameters:
/// - nullValue: The string to print for NULL values.
public init(
nullValue: String = "")
{
self.nullValue = nullValue
}
}
extension LineDumpFormat: DumpFormat {
public mutating func writeRow(
_ db: Database,
statement: Statement,
to stream: inout DumpStream)
{
var lines: [(column: String, value: String)] = []
let sqliteStatement = statement.sqliteStatement
for index in 0..<sqlite3_column_count(sqliteStatement) {
// Don't log GRDB columns
let column = String(cString: sqlite3_column_name(sqliteStatement, index))
if column.starts(with: "grdb_") { continue }
lines.append((
column: column,
value: formattedValue(db, in: sqliteStatement, at: index)))
}
if lines.isEmpty { return }
if firstRow {
firstRow = false
} else {
stream.write("\n")
}
let columnWidth = lines.map(\.column.count).max()!
for line in lines {
stream.write(line.column.leftPadding(toLength: columnWidth, withPad: " "))
stream.write(" = ")
stream.writeln(line.value)
}
}
public mutating func finalize(
_ db: Database,
statement: Statement,
to stream: inout DumpStream)
{
if firstRow == false {
stream.margin()
}
firstRow = true
}
func formattedValue(
_ db: Database,
in sqliteStatement: SQLiteStatement,
at index: CInt)
-> String
{
switch sqlite3_column_type(sqliteStatement, index) {
case SQLITE_NULL:
return nullValue
case SQLITE_INTEGER:
return Int64(sqliteStatement: sqliteStatement, index: index).description
case SQLITE_FLOAT:
return Double(sqliteStatement: sqliteStatement, index: index).description
case SQLITE_BLOB, SQLITE_TEXT:
return String(sqliteStatement: sqliteStatement, index: index)
default:
return ""
}
}
}
extension DumpFormat where Self == LineDumpFormat {
/// A format that prints one line per database value. All blob values
/// are interpreted as strings.
///
/// On each line, database values are separated by a separator (`|`
/// by default). Blob values are interpreted as UTF8 strings.
///
/// For example:
///
/// ```swift
/// // name = Arthur
/// // score = 500
/// //
/// // name = Barbara
/// // score = 1000
/// try db.dumpRequest(Player.all(), format: .line())
/// ```
///
/// - Parameters:
/// - nullValue: The string to print for NULL values.
public static func line(
nullValue: String = "")
-> Self
{
LineDumpFormat(nullValue: nullValue)
}
}