113 lines
3.2 KiB
Swift
113 lines
3.2 KiB
Swift
/// A type that prints database rows.
|
|
///
|
|
/// Types that conform to `DumpFormat` feed the printing methods such as
|
|
/// ``DatabaseReader/dumpContent(format:to:)`` and
|
|
/// ``Database/dumpSQL(_:format:to:)``.
|
|
///
|
|
/// Most built-in formats are inspired from the
|
|
/// [output formats of the SQLite command line tool](https://sqlite.org/cli.html#changing_output_formats).
|
|
///
|
|
/// ## Topics
|
|
///
|
|
/// ### Built-in Formats
|
|
///
|
|
/// - ``debug(header:separator:nullValue:)``
|
|
/// - ``json(encoder:)``
|
|
/// - ``line(nullValue:)``
|
|
/// - ``list(header:separator:nullValue:)``
|
|
/// - ``quote(header:separator:)``
|
|
///
|
|
/// ### Supporting Types
|
|
///
|
|
/// - ``DebugDumpFormat``
|
|
/// - ``JSONDumpFormat``
|
|
/// - ``LineDumpFormat``
|
|
/// - ``ListDumpFormat``
|
|
/// - ``QuoteDumpFormat``
|
|
/// - ``DumpStream``
|
|
///
|
|
/// ### Implementing a custom format
|
|
///
|
|
/// [**🔥 EXPERIMENTAL**](https://github.com/groue/GRDB.swift/blob/master/README.md#what-are-experimental-features)
|
|
///
|
|
/// - ``writeRow(_:statement:to:)``
|
|
/// - ``finalize(_:statement:to:)``
|
|
public protocol DumpFormat {
|
|
/// Writes a row from the given statement.
|
|
///
|
|
/// - Parameters:
|
|
/// - db: A connection to the database
|
|
/// - statement: The iterated statement
|
|
/// - stream: A stream for text output.
|
|
mutating func writeRow(
|
|
_ db: Database,
|
|
statement: Statement,
|
|
to stream: inout DumpStream) throws
|
|
|
|
/// All rows from the statement have been printed.
|
|
///
|
|
/// - Parameters:
|
|
/// - db: A connection to the database
|
|
/// - statement: The statement that was iterated.
|
|
/// - stream: A stream for text output.
|
|
mutating func finalize(
|
|
_ db: Database,
|
|
statement: Statement,
|
|
to stream: inout DumpStream)
|
|
}
|
|
|
|
/// A TextOutputStream that prints to standard output
|
|
struct StandardOutputStream: TextOutputStream {
|
|
func write(_ string: String) {
|
|
print(string, terminator: "")
|
|
}
|
|
}
|
|
|
|
/// A text output stream suited for printing database content.
|
|
///
|
|
/// [**🔥 EXPERIMENTAL**](https://github.com/groue/GRDB.swift/blob/master/README.md#what-are-experimental-features)
|
|
public struct DumpStream {
|
|
var base: any TextOutputStream
|
|
var needsMarginLine = false
|
|
|
|
init(_ base: (any TextOutputStream)?) {
|
|
self.base = base ?? StandardOutputStream()
|
|
}
|
|
|
|
/// Will write `"\n"` before the next non-empty string.
|
|
public mutating func margin() {
|
|
needsMarginLine = true
|
|
}
|
|
}
|
|
|
|
extension DumpStream: TextOutputStream {
|
|
public mutating func write(_ string: String) {
|
|
if needsMarginLine && !string.isEmpty {
|
|
needsMarginLine = false
|
|
if string.first != "\n" {
|
|
base.write("\n")
|
|
}
|
|
}
|
|
base.write(string)
|
|
}
|
|
}
|
|
|
|
extension TextOutputStream {
|
|
mutating func writeln(_ string: String) {
|
|
write(string)
|
|
write("\n")
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
func leftPadding(toLength newLength: Int, withPad padString: String) -> String {
|
|
precondition(padString.count == 1)
|
|
if count < newLength {
|
|
return String(repeating: padString, count: newLength - count) + self
|
|
} else {
|
|
let startIndex = index(startIndex, offsetBy: count - newLength)
|
|
return String(self[startIndex...])
|
|
}
|
|
}
|
|
}
|