-
-
Notifications
You must be signed in to change notification settings - Fork 172
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #48 from qutheory/schema
Schema
- Loading branch information
Showing
42 changed files
with
1,133 additions
and
337 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
Packages | ||
.build | ||
|
||
Database | ||
|
||
.DS_Store | ||
*.xcodeproj | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
A dummy `Driver` useful for developing. | ||
*/ | ||
public class PrintDriver: Driver { | ||
public var idKey: String = "foo" | ||
|
||
public func query<T: Model>(_ query: Query<T>) throws -> [[String : Value]] { | ||
|
||
let sql = SQL(query: query) | ||
let serializer = GeneralSQLSerializer(sql: sql) | ||
|
||
let (statement, values) = serializer.serialize() | ||
print("[Print driver]") | ||
|
||
print("Statement: \(statement) Values: \(values)") | ||
|
||
print("Table \(query.entity)") | ||
print("Action \(query.action)") | ||
print("Filters \(query.filters)") | ||
print() | ||
|
||
return [] | ||
} | ||
|
||
public func schema(_ schema: Schema) throws { | ||
//let sql = SQL(builder: builder) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
A type of data that can be retrieved | ||
or stored in a database. | ||
*/ | ||
public protocol Value: CustomStringConvertible, StructuredDataRepresentable, Polymorphic {} | ||
|
||
extension Int: Value { | ||
public var structuredData: StructuredData { | ||
return .int(self) | ||
} | ||
} | ||
|
||
extension String: Value { | ||
public var structuredData: StructuredData { | ||
return .string(self) | ||
} | ||
|
||
public var description: String { | ||
return self | ||
} | ||
} | ||
|
||
extension Double: Value { | ||
public var structuredData: StructuredData { | ||
return .double(self) | ||
} | ||
} | ||
|
||
extension Float: Value { | ||
public var structuredData: StructuredData { | ||
return .double(Double(self)) | ||
} | ||
} | ||
|
||
extension StructuredData: Fluent.Value { | ||
public var structuredData: StructuredData { | ||
return self | ||
} | ||
} | ||
|
||
extension Bool: Value { | ||
public var structuredData: StructuredData { | ||
return .bool(self) | ||
} | ||
} | ||
|
||
extension StructuredData: CustomStringConvertible { | ||
public var description: String { | ||
switch self { | ||
case .array(let array): | ||
return array.description | ||
case .bool(let bool): | ||
return bool.description | ||
case .data(let data): | ||
return data.description | ||
case .dictionary(let dict): | ||
return dict.description | ||
case .double(let double): | ||
return double.description | ||
case .int(let int): | ||
return int.description | ||
case .null: | ||
return "NULL" | ||
case .string(let string): | ||
return string | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
extension Database { | ||
public func prepare(_ preparations: [Preparation.Type]) throws { | ||
for preparation in preparations { | ||
try prepare(preparation) | ||
} | ||
} | ||
|
||
public func hasPrepared(_ preparation: Preparation.Type) throws -> Bool { | ||
Migration.database = self | ||
|
||
do { | ||
// check to see if this preparation has already run | ||
if let _ = try Migration.filter("name", preparation.name).first() { | ||
return true | ||
} | ||
} catch { | ||
// could not fetch migrations | ||
// try to create `.fluent` table | ||
try Migration.prepare(database: self) | ||
} | ||
|
||
return false | ||
} | ||
|
||
public func prepare(_ preparation: Preparation.Type) throws { | ||
Migration.database = self | ||
|
||
// set the current database on involved Models | ||
if let model = preparation as? Model.Type { | ||
model.database = self | ||
} | ||
|
||
|
||
if try hasPrepared(preparation) { | ||
throw PreparationError.alreadyPrepared | ||
} | ||
|
||
try preparation.prepare(database: self) | ||
|
||
// record that this preparation has run | ||
var migration = Migration(name: preparation.name) | ||
try migration.save() | ||
} | ||
} | ||
|
||
extension Preparation { | ||
public static var name: String { | ||
let type = "\(self.dynamicType)" | ||
return type.components(separatedBy: ".Type").first ?? type | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
final class Migration: Model { | ||
static var entity = "fluent" | ||
|
||
var id: Value? | ||
var name: String | ||
|
||
init(name: String) { | ||
self.name = name | ||
} | ||
|
||
init(serialized: [String: Value]) { | ||
id = serialized["id"] | ||
name = serialized["name"]?.string ?? "" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// MARK: Preparation | ||
|
||
extension Model { | ||
/** | ||
Automates the preparation of a model. | ||
*/ | ||
public static func prepare(database: Database) throws { | ||
try database.create(entity) { builder in | ||
let model = self.init() | ||
let mirror = Mirror(reflecting: model) | ||
|
||
for property in mirror.children { | ||
guard let name = property.label else { | ||
throw PreparationError.automationFailed("Unable to unwrap property name.") | ||
} | ||
let type = "\(property.value.dynamicType)" | ||
|
||
if name == database.driver.idKey { | ||
builder.id() | ||
} else { | ||
if type.contains("String") { | ||
builder.string(name) | ||
} else if type.contains("Int") { | ||
builder.int(name) | ||
} else if type.contains("Double") || type.contains("Float") { | ||
builder.double(name) | ||
} else { | ||
throw PreparationError.automationFailed("Unable to prepare property '\(name): \(type)', only String, Int, Double, and Float are supported.") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
Automates reverting the model's preparation. | ||
*/ | ||
public static func revert(database: Database) throws { | ||
try database.delete(entity) | ||
} | ||
} | ||
|
||
// MARK: Automation | ||
|
||
extension Model { | ||
private init() { | ||
self.init(serialized: [:]) | ||
} | ||
|
||
/** | ||
Automates the serialization of a model. | ||
*/ | ||
public func serialize() -> [String: Value?] { | ||
var serialized: [String: Value?] = [:] | ||
|
||
let mirror = Mirror(reflecting: self) | ||
for property in mirror.children { | ||
let name = property.label ?? "" | ||
let type = "\(property.value.dynamicType)" | ||
|
||
if let id = id { | ||
serialized["id"] = id.int ?? id.string | ||
} | ||
|
||
if type.contains("String") { | ||
if let string = property.value as? String { | ||
serialized[name] = string | ||
} | ||
} else if type.contains("Int") { | ||
if let int = property.value as? Int { | ||
serialized[name] = int | ||
} | ||
} | ||
|
||
} | ||
|
||
return serialized | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
A preparation prepares the database for | ||
any task that it may need to perform during runtime. | ||
*/ | ||
public protocol Preparation { | ||
/** | ||
The prepare method should call any methods | ||
it needs on the database to prepare. | ||
*/ | ||
static func prepare(database: Database) throws | ||
|
||
/** | ||
The revert method should undo any actions | ||
caused by the prepare method. | ||
If this is impossible, the `PreparationError.revertImpossible` | ||
error should be thrown. | ||
*/ | ||
static func revert(database: Database) throws | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
public enum PreparationError: ErrorProtocol { | ||
case alreadyPrepared | ||
case revertImpossible | ||
case automationFailed(String) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,5 +7,5 @@ public enum Action { | |
case fetch | ||
case delete | ||
case create | ||
case update | ||
case modify | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.