@@ -43,19 +43,31 @@ public class SchemaChanger: CustomStringConvertible {
4343
4444 public enum Operation {
4545 case addColumn( ColumnDefinition )
46+ case addIndex( IndexDefinition )
4647 case dropColumn( String )
4748 case renameColumn( String , String )
4849 case renameTable( String )
50+ case createTable( columns: [ ColumnDefinition ] )
4951
5052 /// Returns non-nil if the operation can be executed with a simple SQL statement
5153 func toSQL( _ table: String , version: SQLiteVersion ) -> String ? {
5254 switch self {
5355 case . addColumn( let definition) :
5456 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`) "
5563 case . renameColumn( let from, let to) where SQLiteFeature . renameColumn. isSupported ( by: version) :
5664 return " ALTER TABLE \( table. quote ( ) ) RENAME COLUMN \( from. quote ( ) ) TO \( to. quote ( ) ) "
5765 case . dropColumn( let column) where SQLiteFeature . dropColumn. isSupported ( by: version) :
5866 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+ " ) "
5971 default : return nil
6072 }
6173 }
@@ -108,12 +120,39 @@ public class SchemaChanger: CustomStringConvertible {
108120 }
109121 }
110122
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+
111149 private let connection : Connection
112150 private let schemaReader : SchemaReader
113151 private let version : SQLiteVersion
114152 static let tempPrefix = " tmp_ "
115153 typealias Block = ( ) throws -> Void
116154 public typealias AlterTableDefinitionBlock = ( AlterTableDefinition ) -> Void
155+ public typealias CreateTableDefinitionBlock = ( CreateTableDefinition ) -> Void
117156
118157 struct Options : OptionSet {
119158 let rawValue : Int
@@ -141,6 +180,15 @@ public class SchemaChanger: CustomStringConvertible {
141180 }
142181 }
143182
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+
144192 public func drop( table: String , ifExists: Bool = true ) throws {
145193 try dropTable ( table, ifExists: ifExists)
146194 }
@@ -263,6 +311,7 @@ extension TableDefinition {
263311 func apply( _ operation: SchemaChanger . Operation ? ) -> TableDefinition {
264312 switch operation {
265313 case . none: return self
314+ case . createTable, . addIndex: fatalError ( )
266315 case . addColumn: fatalError ( " Use 'ALTER TABLE ADD COLUMN (...)' " )
267316 case . dropColumn( let column) :
268317 return TableDefinition ( name: name,
0 commit comments