@@ -43,19 +43,31 @@ public class SchemaChanger: CustomStringConvertible {
43
43
44
44
public enum Operation {
45
45
case addColumn( ColumnDefinition )
46
+ case addIndex( IndexDefinition )
46
47
case dropColumn( String )
47
48
case renameColumn( String , String )
48
49
case renameTable( String )
50
+ case createTable( columns: [ ColumnDefinition ] )
49
51
50
52
/// Returns non-nil if the operation can be executed with a simple SQL statement
51
53
func toSQL( _ table: String , version: SQLiteVersion ) -> String ? {
52
54
switch self {
53
55
case . addColumn( let definition) :
54
56
return " ALTER TABLE \( table. quote ( ) ) ADD COLUMN \( definition. toSQL ( ) ) "
57
+ case . addIndex( let definition) :
58
+ let unique = definition. unique ? " UNIQUE " : " "
59
+ let columns = definition. columns. joined ( separator: " , " )
60
+ let `where` = definition. where. map { " WHERE " + $0 } ?? " "
61
+
62
+ return " CREATE \( unique) INDEX \( definition. name) ON \( definition. table) ( \( columns) ) \( `where`) "
55
63
case . renameColumn( let from, let to) where SQLiteFeature . renameColumn. isSupported ( by: version) :
56
64
return " ALTER TABLE \( table. quote ( ) ) RENAME COLUMN \( from. quote ( ) ) TO \( to. quote ( ) ) "
57
65
case . dropColumn( let column) where SQLiteFeature . dropColumn. isSupported ( by: version) :
58
66
return " ALTER TABLE \( table. quote ( ) ) DROP COLUMN \( column. quote ( ) ) "
67
+ case . createTable( let columns) :
68
+ return " CREATE TABLE \( table. quote ( ) ) ( " +
69
+ columns. map { $0. toSQL ( ) } . joined ( separator: " , " ) +
70
+ " ) "
59
71
default : return nil
60
72
}
61
73
}
@@ -108,12 +120,39 @@ public class SchemaChanger: CustomStringConvertible {
108
120
}
109
121
}
110
122
123
+ public class CreateTableDefinition {
124
+ fileprivate var columnDefinitions : [ ColumnDefinition ] = [ ]
125
+ fileprivate var indexDefinitions : [ IndexDefinition ] = [ ]
126
+
127
+ let name : String
128
+
129
+ init ( name: String ) {
130
+ self . name = name
131
+ }
132
+
133
+ public func add( column: ColumnDefinition ) {
134
+ columnDefinitions. append ( column)
135
+ }
136
+
137
+ public func add( index: IndexDefinition ) {
138
+ indexDefinitions. append ( index)
139
+ }
140
+
141
+ var operations : [ Operation ] {
142
+ precondition ( !columnDefinitions. isEmpty)
143
+ return [
144
+ . createTable( columns: columnDefinitions)
145
+ ] + indexDefinitions. map { . addIndex( $0) }
146
+ }
147
+ }
148
+
111
149
private let connection : Connection
112
150
private let schemaReader : SchemaReader
113
151
private let version : SQLiteVersion
114
152
static let tempPrefix = " tmp_ "
115
153
typealias Block = ( ) throws -> Void
116
154
public typealias AlterTableDefinitionBlock = ( AlterTableDefinition ) -> Void
155
+ public typealias CreateTableDefinitionBlock = ( CreateTableDefinition ) -> Void
117
156
118
157
struct Options : OptionSet {
119
158
let rawValue : Int
@@ -141,6 +180,15 @@ public class SchemaChanger: CustomStringConvertible {
141
180
}
142
181
}
143
182
183
+ public func create( table: String , ifNotExists: Bool = false , block: CreateTableDefinitionBlock ) throws {
184
+ let createTableDefinition = CreateTableDefinition ( name: table)
185
+ block ( createTableDefinition)
186
+
187
+ for operation in createTableDefinition. operations {
188
+ try run ( table: table, operation: operation)
189
+ }
190
+ }
191
+
144
192
public func drop( table: String , ifExists: Bool = true ) throws {
145
193
try dropTable ( table, ifExists: ifExists)
146
194
}
@@ -263,6 +311,7 @@ extension TableDefinition {
263
311
func apply( _ operation: SchemaChanger . Operation ? ) -> TableDefinition {
264
312
switch operation {
265
313
case . none: return self
314
+ case . createTable, . addIndex: fatalError ( )
266
315
case . addColumn: fatalError ( " Use 'ALTER TABLE ADD COLUMN (...)' " )
267
316
case . dropColumn( let column) :
268
317
return TableDefinition ( name: name,
0 commit comments