Skip to content

Commit fabbe8c

Browse files
committed
Fix column affinity parsing to match how SQLite determines affinity
See https://www.sqlite.org/datatype3.html#determination_of_column_affinity for how SQLite determines column affinity.
1 parent 1b1eba0 commit fabbe8c

File tree

3 files changed

+77
-5
lines changed

3 files changed

+77
-5
lines changed

Sources/SQLite/Schema/SchemaDefinitions.swift

+13-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,19 @@ public struct ColumnDefinition: Equatable {
5757
}
5858

5959
init(_ string: String) {
60-
self = Affinity.allCases.first { $0.rawValue.lowercased() == string.lowercased() } ?? .TEXT
60+
let test = string.uppercased()
61+
// https://sqlite.org/datatype3.html#determination_of_column_affinity
62+
if test.contains("INT") { // Rule 1
63+
self = .INTEGER
64+
} else if ["CHAR", "CLOB", "TEXT"].first(where: {test.contains($0)}) != nil { // Rule 2
65+
self = .TEXT
66+
} else if string.contains("BLOB") { // Rule 3
67+
self = .BLOB
68+
} else if ["REAL", "FLOA", "DOUB"].first(where: {test.contains($0)}) != nil { // Rule 4
69+
self = .REAL
70+
} else { // Rule 5
71+
self = .NUMERIC
72+
}
6173
}
6274
}
6375

Tests/SQLiteTests/Schema/SchemaDefinitionsTests.swift

+62-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,68 @@ class AffinityTests: XCTestCase {
7171
XCTAssertEqual(ColumnDefinition.Affinity("NUMERIC"), .NUMERIC)
7272
}
7373

74-
func test_returns_TEXT_for_unknown_type() {
75-
XCTAssertEqual(ColumnDefinition.Affinity("baz"), .TEXT)
74+
// [Determination Of Column Affinity](https://sqlite.org/datatype3.html#determination_of_column_affinity)
75+
// Rule 1
76+
func testIntegerAffinity() {
77+
let declared = [
78+
"INT",
79+
"INTEGER",
80+
"TINYINT",
81+
"SMALLINT",
82+
"MEDIUMINT",
83+
"BIGINT",
84+
"UNSIGNED BIG INT",
85+
"INT2",
86+
"INT8"
87+
]
88+
XCTAssertTrue(declared.allSatisfy({ColumnDefinition.Affinity($0) == .INTEGER}))
89+
}
90+
91+
// Rule 2
92+
func testTextAffinity() {
93+
let declared = [
94+
"CHARACTER(20)",
95+
"VARCHAR(255)",
96+
"VARYING CHARACTER(255)",
97+
"NCHAR(55)",
98+
"NATIVE CHARACTER(70)",
99+
"NVARCHAR(100)",
100+
"TEXT",
101+
"CLOB"
102+
]
103+
XCTAssertTrue(declared.allSatisfy({ColumnDefinition.Affinity($0) == .TEXT}))
104+
}
105+
106+
// Rule 3
107+
func testBlobAffinity() {
108+
XCTAssertEqual(ColumnDefinition.Affinity("BLOB"), .BLOB)
109+
}
110+
111+
// Rule 4
112+
func testRealAffinity() {
113+
let declared = [
114+
"REAL",
115+
"DOUBLE",
116+
"DOUBLE PRECISION",
117+
"FLOAT"
118+
]
119+
XCTAssertTrue(declared.allSatisfy({ColumnDefinition.Affinity($0) == .REAL}))
120+
}
121+
122+
// Rule 5
123+
func testNumericAffinity() {
124+
let declared = [
125+
"NUMERIC",
126+
"DECIMAL(10,5)",
127+
"BOOLEAN",
128+
"DATE",
129+
"DATETIME"
130+
]
131+
XCTAssertTrue(declared.allSatisfy({ColumnDefinition.Affinity($0) == .NUMERIC}))
132+
}
133+
134+
func test_returns_NUMERIC_for_unknown_type() {
135+
XCTAssertEqual(ColumnDefinition.Affinity("baz"), .NUMERIC)
76136
}
77137
}
78138

Tests/SQLiteTests/Schema/SchemaReaderTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class SchemaReaderTests: SQLiteTestCase {
4040
references: nil),
4141
ColumnDefinition(name: "admin",
4242
primaryKey: nil,
43-
type: .TEXT,
43+
type: .NUMERIC,
4444
nullable: false,
4545
defaultValue: .numericLiteral("0"),
4646
references: nil),
@@ -51,7 +51,7 @@ class SchemaReaderTests: SQLiteTestCase {
5151
references: .init(table: "users", column: "manager_id", primaryKey: "id", onUpdate: nil, onDelete: nil)),
5252
ColumnDefinition(name: "created_at",
5353
primaryKey: nil,
54-
type: .TEXT,
54+
type: .NUMERIC,
5555
nullable: true,
5656
defaultValue: .NULL,
5757
references: nil)

0 commit comments

Comments
 (0)