Skip to content

Commit

Permalink
Readme and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
inkyfox committed Oct 28, 2016
1 parent b29930b commit db7c39e
Show file tree
Hide file tree
Showing 9 changed files with 1,015 additions and 523 deletions.
936 changes: 519 additions & 417 deletions Playground/SwiftySQL.playground/Contents.swift

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions Playground/SwiftySQL.playground/Sources/SwiftSQLTestEnv.swift
@@ -0,0 +1,60 @@
import Foundation
import SwiftySQL

extension String {
func replacingOccurrences(of regex: NSRegularExpression, with to: String) -> String {
return regex.stringByReplacingMatches(in: self, options: [], range: NSRange(location: 0, length: characters.count),
withTemplate: to)
}
}

func unformat(_ query: String) -> String {
return
query.components(separatedBy: "\n")
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces) }
.joined(separator: " ")
.replacingOccurrences(of: " FROM ", with: " FROM ")
.replacingOccurrences(of: " GROUP BY ", with: " GROUP BY ")
.replacingOccurrences(of: " ORDER BY ", with: " ORDER BY ")
.replacingOccurrences(of: " LIMIT ", with: " LIMIT ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " WHERE [ ]*", options: .caseInsensitive),
with: " WHERE ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " VALUES [ ]*", options: .caseInsensitive),
with: " VALUES ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " SET [ ]*", options: .caseInsensitive),
with: " SET ")
.replacingOccurrences(of: "( ", with: "(")
.replacingOccurrences(of: " )", with: ")")
}

extension SQLStringConvertible {
func sql(by generator: SQLGenerator) -> String {
return (self as? SQLQueryType)?.query(by: generator) ??
self.sqlString(forRead: true, by: generator)
}

func formattedSQL(withIndent indent: Int, by generator: SQLGenerator) -> String {
return (self as? SQLQueryType)?.formattedQuery(withIndent: indent,
by: generator) ??
self.formattedSQLString(forRead: true,
withIndent: indent,
by: generator)
}
}


public func checkSQL(_ sql: SQLStringConvertible) {
let generator = SQLGenerator.default
let query = sql.sql(by: generator)
let formatted = sql.formattedSQL(withIndent: 0, by: generator)
let passed = query == unformat(formatted)
let result = passed ? "[Passed] " : "[Failed] "
let indent = result.characters.count
if passed {
print("\(result)\(sql.formattedSQL(withIndent: indent, by: generator))")
} else {
print("\(result)\(sql.formattedSQL(withIndent: indent, by: generator))")
print(" \(query)")
print(" \(unformat(formatted))")
}
}
163 changes: 161 additions & 2 deletions README.md
@@ -1,4 +1,163 @@
# SwiftySQL
Easy and safe way to write SQL in Swift
======================================

## Write your SQL in Swift

`SwiftySQL` is the easiest way to write SQL in Swift:

- Minimize SQL String literals.
- Use Swift variables for table and column names.
- Use Swift operators and expressions for SQL expressions.

For example, you can write Swift codes:

``` swift
SQL.select(student.name).from(student).where(student.year >= 3 && student.id < 100)
```

to generate SQL string:

``` SQL
SELECT s.name FROM student AS s WHERE s.year >= 3 AND s.id < 100
```

More complex SQL:

<table>
<tr>
<th width="50%">Swift</th>
<th width="50%">SQL</th>
</tr>
<tr>
<td width="50%"><pre lang="swift" style="border: none;">
SQL.select(student.name,
student.birth)
.from(student,
attending)
.where(student.id == attending.studentID)
.orderBy(student.name.asc)
</pre></td>
<td width="50%"><pre lang="sql" style="border: none;">
SELECT s.name,
s.birth
FROM student AS s,
user.attending AS a
WHERE s = a.student_id
ORDER BY s.name ASC
</pre></td>
</tr>
</table>

Even more complex SQL:

<table>
<tr>
<th width="50%">Swift</th>
<th width="50%">SQL</th>
</tr>
<tr>
<td width="50%"><pre lang="swift" style="border: none;">
SQL.select(student.name,
when(lecture.name.isNotNull,
then: lecture.name)
.else("N/A"),
when(teature.name.isNotNull,
then: teature.name)
.else("N/A")
)
.from(student
.leftJoin(attending,
on: student.id == attending.studentID)
.leftJoin(lecture,
on: lecture.id == attending.lectureID)
.leftJoin(teature,
on: teature.id == lecture.teatureID)
)
.where(student.year >= 2
&& student.year <= 3
&& (teature.office.hasPrefix("A")
|| teature.office.isNull)
)
.orderBy(student.name.asc)
</pre></td>
<td width="50%"><pre lang="sql" style="border: none;">
SELECT s.name,
CASE
WHEN l.name NOTNULL THEN l.name
ELSE 'N/A'
END,
CASE
WHEN t.name NOTNULL THEN t.name
ELSE 'N/A'
END
FROM student AS s
LEFT JOIN attending AS a
ON s.id = a.student_id
LEFT JOIN lecture AS l
ON l.id = a.lecture_id
LEFT JOIN teature AS t
ON t.id = l.teature_id
WHERE s.year >= 2
AND s.year <= 3
AND ( t.office LIKE 'A%'
OR t.office ISNULL )
ORDER BY s.name ASC
</pre></td>
</tr>
</table>

## Requirements

- iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
- Xcode 8

## Installation

### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html)
```
# Podfile
use_frameworks!
target 'YOUR_TARGET_NAME' do
pod 'SwiftySQL'
end
```

Replace `YOUR_TARGET_NAME` and then, in the `Podfile` directory, type:

```
$ pod install
```

### [Carthage](https://github.com/Carthage/Carthage)

Add this to `Cartfile`

```
github "inkyfox/SwiftySQL"
```

```
$ carthage update
```

### [Swift Package Manager](https://github.com/apple/swift-package-manager)

Create a `Package.swift` file.

```
import PackageDescription
let package = Package(
name: "TestProject",
targets: [],
dependencies: [
.Package(url: "https://github.com/inkyfox/SwiftySQL.git")
]
)
```

```
$ swift build
```

Now working on! Please wait until Nov 1st.
2 changes: 1 addition & 1 deletion Sources/Generators/SQL.Join+DefaultDB.swift
Expand Up @@ -44,7 +44,7 @@ extension SQL.Join {
var line1 = space(indent) + typeString(element.type) + " "
let line2Indent = line1.characters.count - 3
line1 += element.right.formattedSQLString(forRead: forRead,
withIndent: indent + line1.characters.count,
withIndent: line1.characters.count,
by: generator)
if let on = element.on {
let line2 = "\n" + space(line2Indent)
Expand Down
4 changes: 4 additions & 0 deletions SwiftySQL.xcodeproj/project.pbxproj
Expand Up @@ -80,6 +80,7 @@
A9B39BBB1DBC40BD00A208FC /* SQL.Table+DefaultDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B39BBA1DBC40BD00A208FC /* SQL.Table+DefaultDB.swift */; };
A9B39BBD1DBC411F00A208FC /* SQL.Join+DefaultDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B39BBC1DBC411F00A208FC /* SQL.Join+DefaultDB.swift */; };
A9D9DFEA1DC2BB83005CF80D /* DeleteTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D9DFE91DC2BB83005CF80D /* DeleteTest.swift */; };
A9D9DFEC1DC2F152005CF80D /* SwiftSQLTestEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D9DFEB1DC2F152005CF80D /* SwiftSQLTestEnv.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -191,6 +192,7 @@
A9B39BBA1DBC40BD00A208FC /* SQL.Table+DefaultDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SQL.Table+DefaultDB.swift"; sourceTree = "<group>"; };
A9B39BBC1DBC411F00A208FC /* SQL.Join+DefaultDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SQL.Join+DefaultDB.swift"; sourceTree = "<group>"; };
A9D9DFE91DC2BB83005CF80D /* DeleteTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteTest.swift; sourceTree = "<group>"; };
A9D9DFEB1DC2F152005CF80D /* SwiftSQLTestEnv.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSQLTestEnv.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -324,6 +326,7 @@
children = (
A9B39B731DB9D90900A208FC /* AppDelegate.swift */,
A9B39B751DB9D90900A208FC /* ViewController.swift */,
A9D9DFEB1DC2F152005CF80D /* SwiftSQLTestEnv.swift */,
A9B39B771DB9D90900A208FC /* Assets.xcassets */,
A9B39B791DB9D90900A208FC /* Main.storyboard */,
A9B39B7C1DB9D90900A208FC /* Info.plist */,
Expand Down Expand Up @@ -595,6 +598,7 @@
buildActionMask = 2147483647;
files = (
A9B39B761DB9D90900A208FC /* ViewController.swift in Sources */,
A9D9DFEC1DC2F152005CF80D /* SwiftSQLTestEnv.swift in Sources */,
A9B39B741DB9D90900A208FC /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
68 changes: 68 additions & 0 deletions SwiftySQLExample-macOS/SwiftSQLTestEnv.swift
@@ -0,0 +1,68 @@
import Foundation
import SwiftySQL

extension String {
func replacingOccurrences(of regex: NSRegularExpression, with to: String) -> String {
return regex.stringByReplacingMatches(in: self, options: [], range: NSRange(location: 0, length: characters.count),
withTemplate: to)
}
}

extension Date {
static func of(_ yyyymmdd: String) -> Date {
let f = DateFormatter()
f.dateFormat = "yyyyMMdd"
return f.date(from: yyyymmdd)!
}
}

func unformat(_ query: String) -> String {
return
query.components(separatedBy: "\n")
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces) }
.joined(separator: " ")
.replacingOccurrences(of: " FROM ", with: " FROM ")
.replacingOccurrences(of: " GROUP BY ", with: " GROUP BY ")
.replacingOccurrences(of: " ORDER BY ", with: " ORDER BY ")
.replacingOccurrences(of: " LIMIT ", with: " LIMIT ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " WHERE [ ]*", options: .caseInsensitive),
with: " WHERE ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " VALUES [ ]*", options: .caseInsensitive),
with: " VALUES ")
.replacingOccurrences(of: try! NSRegularExpression(pattern: " SET [ ]*", options: .caseInsensitive),
with: " SET ")
.replacingOccurrences(of: "( ", with: "(")
.replacingOccurrences(of: " )", with: ")")
}

extension SQLStringConvertible {
func sql(by generator: SQLGenerator) -> String {
return (self as? SQLQueryType)?.query(by: generator) ??
self.sqlString(forRead: true, by: generator)
}

func formattedSQL(withIndent indent: Int, by generator: SQLGenerator) -> String {
return (self as? SQLQueryType)?.formattedQuery(withIndent: indent,
by: generator) ??
self.formattedSQLString(forRead: true,
withIndent: indent,
by: generator)
}
}


public func checkSQL(_ sql: SQLStringConvertible) {
let generator = SQLGenerator.default
let query = sql.sql(by: generator)
let formatted = sql.formattedSQL(withIndent: 0, by: generator)
let passed = query == unformat(formatted)
let result = passed ? "[Passed] " : "[Failed] "
let indent = result.characters.count
if passed {
print("\(result)\(sql.formattedSQL(withIndent: indent, by: generator))")
} else {
print("\(result)\(sql.formattedSQL(withIndent: indent, by: generator))")
print(" \(query)")
print(" \(unformat(formatted))")
}
}

0 comments on commit db7c39e

Please sign in to comment.