DataLiteCore swift package
This commit is contained in:
34
Sources/DataLiteCore/Extensions/BinaryFloatingPoint.swift
Normal file
34
Sources/DataLiteCore/Extensions/BinaryFloatingPoint.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
import Foundation
|
||||
|
||||
public extension SQLiteRawBindable where Self: BinaryFloatingPoint {
|
||||
/// Provides the `SQLiteRawValue` representation for floating-point types.
|
||||
///
|
||||
/// This implementation converts the floating-point value to a `real` SQLite raw value.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.real`, containing the floating-point value.
|
||||
var sqliteRawValue: SQLiteRawValue {
|
||||
.real(.init(self))
|
||||
}
|
||||
}
|
||||
|
||||
public extension SQLiteRawRepresentable where Self: BinaryFloatingPoint {
|
||||
/// Initializes an instance of the conforming type from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.real`, converting it to the floating-point value.
|
||||
/// It also handles `SQLiteRawValue` of type `.int`, converting it to the floating-point value.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .int(let value):
|
||||
self.init(Double(value))
|
||||
case .real(let value):
|
||||
self.init(value)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Float: SQLiteRawRepresentable {}
|
||||
extension Double: SQLiteRawRepresentable {}
|
||||
43
Sources/DataLiteCore/Extensions/BinaryInteger.swift
Normal file
43
Sources/DataLiteCore/Extensions/BinaryInteger.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
import Foundation
|
||||
|
||||
public extension SQLiteRawBindable where Self: BinaryInteger {
|
||||
/// Provides the `SQLiteRawValue` representation for integer types.
|
||||
///
|
||||
/// This implementation converts the integer value to an `SQLiteRawValue` of type `.int`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.int`, containing the integer value.
|
||||
var sqliteRawValue: SQLiteRawValue {
|
||||
.int(Int64(self))
|
||||
}
|
||||
}
|
||||
|
||||
public extension SQLiteRawRepresentable where Self: BinaryInteger {
|
||||
/// Initializes an instance of the conforming type from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.int`, converting it to the integer value.
|
||||
/// It uses the `init(exactly:)` initializer to ensure that the value fits within the range of the
|
||||
/// integer type. If the value cannot be exactly represented by the integer type, the initializer
|
||||
/// will return `nil`.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .int(let value):
|
||||
self.init(exactly: value)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Int: SQLiteRawRepresentable {}
|
||||
extension Int8: SQLiteRawRepresentable {}
|
||||
extension Int16: SQLiteRawRepresentable {}
|
||||
extension Int32: SQLiteRawRepresentable {}
|
||||
extension Int64: SQLiteRawRepresentable {}
|
||||
|
||||
extension UInt: SQLiteRawRepresentable {}
|
||||
extension UInt8: SQLiteRawRepresentable {}
|
||||
extension UInt16: SQLiteRawRepresentable {}
|
||||
extension UInt32: SQLiteRawRepresentable {}
|
||||
extension UInt64: SQLiteRawRepresentable {}
|
||||
32
Sources/DataLiteCore/Extensions/Bool.swift
Normal file
32
Sources/DataLiteCore/Extensions/Bool.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
import Foundation
|
||||
|
||||
extension Bool: SQLiteRawRepresentable {
|
||||
/// Provides the `SQLiteRawValue` representation for boolean types.
|
||||
///
|
||||
/// This implementation converts the boolean value to an `SQLiteRawValue` of type `.int`.
|
||||
/// - `true` is represented as `1`.
|
||||
/// - `false` is represented as `0`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.int`, containing `1` for `true` and `0` for `false`.
|
||||
public var sqliteRawValue: SQLiteRawValue {
|
||||
.int(self ? 1 : 0)
|
||||
}
|
||||
|
||||
/// Initializes an instance of the conforming type from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.int`, converting it to a boolean value.
|
||||
/// - `1` is converted to `true`.
|
||||
/// - `0` is converted to `false`.
|
||||
///
|
||||
/// If the integer value is not `0` or `1`, the initializer returns `nil`.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
public init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .int(let value) where value == 0 || value == 1:
|
||||
self = value == 1
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Sources/DataLiteCore/Extensions/Data.swift
Normal file
26
Sources/DataLiteCore/Extensions/Data.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
|
||||
extension Data: SQLiteRawRepresentable {
|
||||
/// Provides the `SQLiteRawValue` representation for `Data` types.
|
||||
///
|
||||
/// This implementation converts the `Data` value to an `SQLiteRawValue` of type `.blob`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.blob`, containing the data.
|
||||
public var sqliteRawValue: SQLiteRawValue {
|
||||
.blob(self)
|
||||
}
|
||||
|
||||
/// Initializes an instance of the conforming type from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.blob`, converting it to `Data`.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
public init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .blob(let data):
|
||||
self = data
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Sources/DataLiteCore/Extensions/Date.swift
Normal file
39
Sources/DataLiteCore/Extensions/Date.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
import Foundation
|
||||
|
||||
extension Date: SQLiteRawRepresentable {
|
||||
/// Provides the `SQLiteRawValue` representation for `Date` types.
|
||||
///
|
||||
/// This implementation converts the `Date` value to an `SQLiteRawValue` of type `.text`.
|
||||
/// The date is formatted as an ISO 8601 string.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.text`, containing the ISO 8601 string representation of the date.
|
||||
public var sqliteRawValue: SQLiteRawValue {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
let dateString = formatter.string(from: self)
|
||||
return .text(dateString)
|
||||
}
|
||||
|
||||
/// Initializes an instance of `Date` from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.text`, converting it from an ISO 8601 string.
|
||||
/// It also supports `.int` and `.real` types representing time intervals since 1970.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
public init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .int(let value):
|
||||
self.init(timeIntervalSince1970: TimeInterval(value))
|
||||
case .real(let value):
|
||||
self.init(timeIntervalSince1970: value)
|
||||
case .text(let value):
|
||||
let formatter = ISO8601DateFormatter()
|
||||
if let date = formatter.date(from: value) {
|
||||
self = date
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Sources/DataLiteCore/Extensions/RawRepresentable.swift
Normal file
31
Sources/DataLiteCore/Extensions/RawRepresentable.swift
Normal file
@@ -0,0 +1,31 @@
|
||||
import Foundation
|
||||
|
||||
public extension SQLiteRawBindable where Self: RawRepresentable, RawValue: SQLiteRawBindable {
|
||||
/// Provides the `SQLiteRawValue` representation for `RawRepresentable` types.
|
||||
///
|
||||
/// This implementation converts the `RawRepresentable` type's `rawValue` to its corresponding
|
||||
/// `SQLiteRawValue` representation. The `rawValue` itself must conform to `SQLiteRawBindable`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` representation of the `RawRepresentable` type.
|
||||
var sqliteRawValue: SQLiteRawValue {
|
||||
rawValue.sqliteRawValue
|
||||
}
|
||||
}
|
||||
|
||||
public extension SQLiteRawRepresentable where Self: RawRepresentable, RawValue: SQLiteRawRepresentable {
|
||||
/// Initializes an instance of the conforming type from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer converts the `SQLiteRawValue` to the `RawRepresentable` type's `rawValue`.
|
||||
/// It first attempts to create a `RawValue` from the `SQLiteRawValue`, then uses that to initialize
|
||||
/// the `RawRepresentable` instance. If the `SQLiteRawValue` cannot be converted to the `RawValue`, the
|
||||
/// initializer returns `nil`.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
if let value = RawValue(sqliteRawValue) {
|
||||
self.init(rawValue: value)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
731
Sources/DataLiteCore/Extensions/String+SQL.swift
Normal file
731
Sources/DataLiteCore/Extensions/String+SQL.swift
Normal file
@@ -0,0 +1,731 @@
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
/// Removes SQL comments from the string while preserving string literals.
|
||||
///
|
||||
/// This function preserves escaped single quotes inside string literals
|
||||
/// and removes both single-line (`-- ...`) and multi-line (`/* ... */`) comments.
|
||||
///
|
||||
/// The implementation of this function is generated using
|
||||
/// [`re2swift`](https://re2c.org/manual/manual_swift.html)
|
||||
/// from the following parsing template:
|
||||
///
|
||||
/// ```swift
|
||||
/// @inline(__always)
|
||||
/// func removingComments() -> String {
|
||||
/// withCString {
|
||||
/// let yyinput = $0
|
||||
/// let yylimit = strlen($0)
|
||||
/// var yyoutput = [CChar]()
|
||||
/// var yycursor = 0
|
||||
/// loop: while yycursor < yylimit {
|
||||
/// var llmarker = yycursor/*!re2c
|
||||
/// re2c:define:YYCTYPE = "CChar";
|
||||
/// re2c:yyfill:enable = 0;
|
||||
///
|
||||
/// "'" ([^'] | "''")* "'" {
|
||||
/// while llmarker < yycursor {
|
||||
/// yyoutput.append(yyinput[llmarker])
|
||||
/// llmarker += 1
|
||||
/// }
|
||||
/// continue loop }
|
||||
///
|
||||
/// "--" [^\r\n\x00]* {
|
||||
/// continue loop }
|
||||
///
|
||||
/// "/*" ([^*] | "*"[^/])* "*/" {
|
||||
/// continue loop }
|
||||
///
|
||||
/// [^] {
|
||||
/// yyoutput.append(yyinput[llmarker])
|
||||
/// continue loop }
|
||||
/// */}
|
||||
/// yyoutput.append(0)
|
||||
/// return String(
|
||||
/// cString: yyoutput,
|
||||
/// encoding: .utf8
|
||||
/// ) ?? ""
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@inline(__always)
|
||||
func removingComments() -> String {
|
||||
withCString {
|
||||
let yyinput = $0
|
||||
let yylimit = strlen($0)
|
||||
var yyoutput = [CChar]()
|
||||
var yycursor = 0
|
||||
loop: while yycursor < yylimit {
|
||||
var llmarker = yycursor
|
||||
var yych: CChar = 0
|
||||
var yystate: UInt = 0
|
||||
yyl: while true {
|
||||
switch yystate {
|
||||
case 0:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
case 0x2D:
|
||||
yystate = 4
|
||||
continue yyl
|
||||
case 0x2F:
|
||||
yystate = 5
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 1
|
||||
continue yyl
|
||||
}
|
||||
case 1:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
case 2:
|
||||
yyoutput.append(yyinput[llmarker])
|
||||
continue loop
|
||||
case 3:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yystate = 6
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
}
|
||||
case 4:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x2D:
|
||||
yycursor += 1
|
||||
yystate = 8
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
}
|
||||
case 5:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x2A:
|
||||
yycursor += 1
|
||||
yystate = 10
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
}
|
||||
case 6:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yycursor += 1
|
||||
yystate = 3
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 7
|
||||
continue yyl
|
||||
}
|
||||
case 7:
|
||||
while llmarker < yycursor {
|
||||
yyoutput.append(yyinput[llmarker])
|
||||
llmarker += 1
|
||||
}
|
||||
continue loop
|
||||
case 8:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x00:
|
||||
fallthrough
|
||||
case 0x0A:
|
||||
fallthrough
|
||||
case 0x0D:
|
||||
yystate = 9
|
||||
continue yyl
|
||||
default:
|
||||
yycursor += 1
|
||||
yystate = 8
|
||||
continue yyl
|
||||
}
|
||||
case 9:
|
||||
continue loop
|
||||
case 10:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x2A:
|
||||
yystate = 11
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 10
|
||||
continue yyl
|
||||
}
|
||||
case 11:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x2F:
|
||||
yystate = 12
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 10
|
||||
continue yyl
|
||||
}
|
||||
case 12:
|
||||
continue loop
|
||||
default: fatalError("internal lexer error")
|
||||
}
|
||||
}
|
||||
}
|
||||
yyoutput.append(0)
|
||||
return String(cString: yyoutput, encoding: .utf8) ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
/// Trims empty lines and trailing whitespace outside string literals.
|
||||
///
|
||||
/// This function preserves line breaks and whitespace inside string literals,
|
||||
/// removing only redundant empty lines and trailing whitespace outside literals.
|
||||
///
|
||||
/// The implementation of this function is generated using
|
||||
/// [`re2swift`](https://re2c.org/manual/manual_swift.html)
|
||||
/// from the following parsing template:
|
||||
///
|
||||
/// ```swift
|
||||
/// @inline(__always)
|
||||
/// func trimmingLines() -> String {
|
||||
/// withCString {
|
||||
/// let yyinput = $0
|
||||
/// let yylimit = strlen($0)
|
||||
/// var yyoutput = [CChar]()
|
||||
/// var yycursor = 0
|
||||
/// var yymarker = 0
|
||||
/// loop: while yycursor < yylimit {
|
||||
/// var llmarker = yycursor/*!re2c
|
||||
/// re2c:define:YYCTYPE = "CChar";
|
||||
/// re2c:yyfill:enable = 0;
|
||||
///
|
||||
/// "'" ([^'] | "''")* "'" {
|
||||
/// while llmarker < yycursor {
|
||||
/// yyoutput.append(yyinput[llmarker])
|
||||
/// llmarker += 1
|
||||
/// }
|
||||
/// continue loop }
|
||||
///
|
||||
/// [ \t]* "\x00" {
|
||||
/// continue loop }
|
||||
///
|
||||
/// [ \t]* "\n\x00" {
|
||||
/// continue loop }
|
||||
///
|
||||
/// [ \t\n]* "\n"+ {
|
||||
/// if llmarker > 0 && yycursor < yylimit {
|
||||
/// yyoutput.append(0x0A)
|
||||
/// }
|
||||
/// continue loop }
|
||||
///
|
||||
/// [^] {
|
||||
/// yyoutput.append(yyinput[llmarker])
|
||||
/// continue loop }
|
||||
/// */}
|
||||
/// yyoutput.append(0)
|
||||
/// return String(
|
||||
/// cString: yyoutput,
|
||||
/// encoding: .utf8
|
||||
/// ) ?? ""
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@inline(__always)
|
||||
func trimmingLines() -> String {
|
||||
withCString {
|
||||
let yyinput = $0
|
||||
let yylimit = strlen($0)
|
||||
var yyoutput = [CChar]()
|
||||
var yycursor = 0
|
||||
var yymarker = 0
|
||||
loop: while yycursor < yylimit {
|
||||
var llmarker = yycursor
|
||||
var yych: CChar = 0
|
||||
var yyaccept: UInt = 0
|
||||
var yystate: UInt = 0
|
||||
yyl: while true {
|
||||
switch yystate {
|
||||
case 0:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x00:
|
||||
yystate = 1
|
||||
continue yyl
|
||||
case 0x09:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yystate = 4
|
||||
continue yyl
|
||||
case 0x0A:
|
||||
yystate = 5
|
||||
continue yyl
|
||||
case 0x27:
|
||||
yystate = 7
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
}
|
||||
case 1:
|
||||
continue loop
|
||||
case 2:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
case 3:
|
||||
yyoutput.append(yyinput[llmarker])
|
||||
continue loop
|
||||
case 4:
|
||||
yyaccept = 0
|
||||
yymarker = yycursor
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x00:
|
||||
fallthrough
|
||||
case 0x09...0x0A:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yystate = 9
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
}
|
||||
case 5:
|
||||
yyaccept = 1
|
||||
yymarker = yycursor
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x00:
|
||||
yycursor += 1
|
||||
yystate = 11
|
||||
continue yyl
|
||||
case 0x09...0x0A:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yystate = 13
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 6
|
||||
continue yyl
|
||||
}
|
||||
case 6:
|
||||
if llmarker > 0 && yycursor < yylimit {
|
||||
yyoutput.append(0x0A)
|
||||
}
|
||||
continue loop
|
||||
case 7:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yystate = 15
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 7
|
||||
continue yyl
|
||||
}
|
||||
case 8:
|
||||
yych = yyinput[yycursor]
|
||||
yystate = 9
|
||||
continue yyl
|
||||
case 9:
|
||||
switch yych {
|
||||
case 0x00:
|
||||
yycursor += 1
|
||||
yystate = 1
|
||||
continue yyl
|
||||
case 0x09:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yycursor += 1
|
||||
yystate = 8
|
||||
continue yyl
|
||||
case 0x0A:
|
||||
yycursor += 1
|
||||
yystate = 5
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 10
|
||||
continue yyl
|
||||
}
|
||||
case 10:
|
||||
yycursor = yymarker
|
||||
if yyaccept == 0 {
|
||||
yystate = 3
|
||||
continue yyl
|
||||
} else {
|
||||
yystate = 6
|
||||
continue yyl
|
||||
}
|
||||
case 11:
|
||||
continue loop
|
||||
case 12:
|
||||
yych = yyinput[yycursor]
|
||||
yystate = 13
|
||||
continue yyl
|
||||
case 13:
|
||||
switch yych {
|
||||
case 0x09:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yycursor += 1
|
||||
yystate = 12
|
||||
continue yyl
|
||||
case 0x0A:
|
||||
yycursor += 1
|
||||
yystate = 14
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 10
|
||||
continue yyl
|
||||
}
|
||||
case 14:
|
||||
yyaccept = 1
|
||||
yymarker = yycursor
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x09:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yycursor += 1
|
||||
yystate = 12
|
||||
continue yyl
|
||||
case 0x0A:
|
||||
yycursor += 1
|
||||
yystate = 14
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 6
|
||||
continue yyl
|
||||
}
|
||||
case 15:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yycursor += 1
|
||||
yystate = 7
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 16
|
||||
continue yyl
|
||||
}
|
||||
case 16:
|
||||
while llmarker < yycursor {
|
||||
yyoutput.append(yyinput[llmarker])
|
||||
llmarker += 1
|
||||
}
|
||||
continue loop
|
||||
default: fatalError("internal lexer error")
|
||||
}
|
||||
}
|
||||
}
|
||||
yyoutput.append(0)
|
||||
return String(
|
||||
cString: yyoutput,
|
||||
encoding: .utf8
|
||||
) ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the SQL script into individual statements by semicolons.
|
||||
///
|
||||
/// This function preserves string literals (enclosed in single quotes),
|
||||
/// and treats `BEGIN...END` blocks as single nested statements, preventing
|
||||
/// splitting inside these blocks. Statements are split only at semicolons
|
||||
/// outside string literals and `BEGIN...END` blocks.
|
||||
///
|
||||
/// The implementation of this function is generated using
|
||||
/// [`re2swift`](https://re2c.org/manual/manual_swift.html)
|
||||
/// from the following parsing template:
|
||||
///
|
||||
/// ```swift
|
||||
/// @inline(__always)
|
||||
/// func splitStatements() -> [String] {
|
||||
/// withCString {
|
||||
/// let yyinput = $0
|
||||
/// let yylimit = strlen($0)
|
||||
/// var yyranges = [Range<Int>]()
|
||||
/// var yycursor = 0
|
||||
/// var yymarker = 0
|
||||
/// var yynesting = 0
|
||||
/// var yystart = 0
|
||||
/// var yyend = 0
|
||||
/// loop: while yycursor < yylimit {/*!re2c
|
||||
/// re2c:define:YYCTYPE = "CChar";
|
||||
/// re2c:yyfill:enable = 0;
|
||||
///
|
||||
/// "'" ( [^'] | "''" )* "'" {
|
||||
/// yyend = yycursor
|
||||
/// continue loop }
|
||||
///
|
||||
/// 'BEGIN' {
|
||||
/// yynesting += 1
|
||||
/// yyend = yycursor
|
||||
/// continue loop }
|
||||
///
|
||||
/// 'END' {
|
||||
/// if yynesting > 0 {
|
||||
/// yynesting -= 1
|
||||
/// }
|
||||
/// yyend = yycursor
|
||||
/// continue loop }
|
||||
///
|
||||
/// ";" [ \t]* "\n"* {
|
||||
/// if yynesting == 0 {
|
||||
/// if yystart < yyend {
|
||||
/// yyranges.append(yystart..<yyend)
|
||||
/// }
|
||||
/// yystart = yycursor
|
||||
/// continue loop
|
||||
/// } else {
|
||||
/// continue loop
|
||||
/// }}
|
||||
///
|
||||
/// [^] {
|
||||
/// yyend = yycursor
|
||||
/// continue loop }
|
||||
/// */}
|
||||
/// if yystart < yyend {
|
||||
/// yyranges.append(yystart..<yyend)
|
||||
/// }
|
||||
/// return yyranges.map { range in
|
||||
/// let buffer = UnsafeBufferPointer<CChar>(
|
||||
/// start: yyinput.advanced(by: range.lowerBound),
|
||||
/// count: range.count
|
||||
/// )
|
||||
/// let array = Array(buffer) + [0]
|
||||
/// return String(cString: array, encoding: .utf8) ?? ""
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@inline(__always)
|
||||
func splitStatements() -> [String] {
|
||||
withCString {
|
||||
let yyinput = $0
|
||||
let yylimit = strlen($0)
|
||||
var yyranges = [Range<Int>]()
|
||||
var yycursor = 0
|
||||
var yymarker = 0
|
||||
var yynesting = 0
|
||||
var yystart = 0
|
||||
var yyend = 0
|
||||
loop: while yycursor < yylimit {
|
||||
var yych: CChar = 0
|
||||
var yystate: UInt = 0
|
||||
yyl: while true {
|
||||
switch yystate {
|
||||
case 0:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
case 0x3B:
|
||||
yystate = 4
|
||||
continue yyl
|
||||
case 0x42:
|
||||
fallthrough
|
||||
case 0x62:
|
||||
yystate = 6
|
||||
continue yyl
|
||||
case 0x45:
|
||||
fallthrough
|
||||
case 0x65:
|
||||
yystate = 7
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 1
|
||||
continue yyl
|
||||
}
|
||||
case 1:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
case 2:
|
||||
yyend = yycursor
|
||||
continue loop
|
||||
case 3:
|
||||
yych = yyinput[yycursor]
|
||||
yycursor += 1
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yystate = 8
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 3
|
||||
continue yyl
|
||||
}
|
||||
case 4:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x09:
|
||||
fallthrough
|
||||
case 0x20:
|
||||
yycursor += 1
|
||||
yystate = 4
|
||||
continue yyl
|
||||
case 0x0A:
|
||||
yycursor += 1
|
||||
yystate = 10
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 5
|
||||
continue yyl
|
||||
}
|
||||
case 5:
|
||||
if yynesting == 0 {
|
||||
if yystart < yyend {
|
||||
yyranges.append(yystart..<yyend)
|
||||
}
|
||||
yystart = yycursor
|
||||
continue loop
|
||||
} else {
|
||||
continue loop
|
||||
}
|
||||
case 6:
|
||||
yymarker = yycursor
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x45:
|
||||
fallthrough
|
||||
case 0x65:
|
||||
yycursor += 1
|
||||
yystate = 11
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
}
|
||||
case 7:
|
||||
yymarker = yycursor
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x4E:
|
||||
fallthrough
|
||||
case 0x6E:
|
||||
yycursor += 1
|
||||
yystate = 13
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 2
|
||||
continue yyl
|
||||
}
|
||||
case 8:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x27:
|
||||
yycursor += 1
|
||||
yystate = 3
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 9
|
||||
continue yyl
|
||||
}
|
||||
case 9:
|
||||
yyend = yycursor
|
||||
continue loop
|
||||
case 10:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x0A:
|
||||
yycursor += 1
|
||||
yystate = 10
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 5
|
||||
continue yyl
|
||||
}
|
||||
case 11:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x47:
|
||||
fallthrough
|
||||
case 0x67:
|
||||
yycursor += 1
|
||||
yystate = 14
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 12
|
||||
continue yyl
|
||||
}
|
||||
case 12:
|
||||
yycursor = yymarker
|
||||
yystate = 2
|
||||
continue yyl
|
||||
case 13:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x44:
|
||||
fallthrough
|
||||
case 0x64:
|
||||
yycursor += 1
|
||||
yystate = 15
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 12
|
||||
continue yyl
|
||||
}
|
||||
case 14:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x49:
|
||||
fallthrough
|
||||
case 0x69:
|
||||
yycursor += 1
|
||||
yystate = 16
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 12
|
||||
continue yyl
|
||||
}
|
||||
case 15:
|
||||
if yynesting > 0 {
|
||||
yynesting -= 1
|
||||
}
|
||||
yyend = yycursor
|
||||
continue loop
|
||||
case 16:
|
||||
yych = yyinput[yycursor]
|
||||
switch yych {
|
||||
case 0x4E:
|
||||
fallthrough
|
||||
case 0x6E:
|
||||
yycursor += 1
|
||||
yystate = 17
|
||||
continue yyl
|
||||
default:
|
||||
yystate = 12
|
||||
continue yyl
|
||||
}
|
||||
case 17:
|
||||
yynesting += 1
|
||||
yyend = yycursor
|
||||
continue loop
|
||||
default: fatalError("internal lexer error")
|
||||
}
|
||||
}
|
||||
}
|
||||
if yystart < yyend {
|
||||
yyranges.append(yystart..<yyend)
|
||||
}
|
||||
return yyranges.map { range in
|
||||
let buffer = UnsafeBufferPointer<CChar>(
|
||||
start: yyinput.advanced(by: range.lowerBound),
|
||||
count: range.count
|
||||
)
|
||||
let array = Array(buffer) + [0]
|
||||
return String(cString: array, encoding: .utf8) ?? ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Sources/DataLiteCore/Extensions/String.swift
Normal file
26
Sources/DataLiteCore/Extensions/String.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
|
||||
extension String: SQLiteRawRepresentable {
|
||||
/// Provides the `SQLiteRawValue` representation for `String` type.
|
||||
///
|
||||
/// This implementation converts the `String` value to an `SQLiteRawValue` of type `.text`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.text`, containing the string value.
|
||||
public var sqliteRawValue: SQLiteRawValue {
|
||||
.text(self)
|
||||
}
|
||||
|
||||
/// Initializes an instance of `String` from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.text`, converting it to a `String` value.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
public init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .text(let value):
|
||||
self = value
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Sources/DataLiteCore/Extensions/UUID.swift
Normal file
26
Sources/DataLiteCore/Extensions/UUID.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
|
||||
extension UUID: SQLiteRawRepresentable {
|
||||
/// Provides the `SQLiteRawValue` representation for `UUID`.
|
||||
///
|
||||
/// This implementation converts the `UUID` value to an `SQLiteRawValue` of type `.text`.
|
||||
///
|
||||
/// - Returns: An `SQLiteRawValue` of type `.text`, containing the UUID string.
|
||||
public var sqliteRawValue: SQLiteRawValue {
|
||||
.text(self.uuidString)
|
||||
}
|
||||
|
||||
/// Initializes an instance of `UUID` from an `SQLiteRawValue`.
|
||||
///
|
||||
/// This initializer handles `SQLiteRawValue` of type `.text`, converting it to a `UUID`.
|
||||
///
|
||||
/// - Parameter sqliteRawValue: The raw SQLite value used to initialize the instance.
|
||||
public init?(_ sqliteRawValue: SQLiteRawValue) {
|
||||
switch sqliteRawValue {
|
||||
case .text(let value):
|
||||
self.init(uuidString: value)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user