It's not as pretty, but it's the only supported solution.

Signed-off-by: Stephen Celis <stephen@stephencelis.com>
This commit is contained in:
Stephen Celis 2015-04-16 11:15:13 -04:00
Родитель 3abd6213b2
Коммит d287345320
48 изменённых файлов: 221 добавлений и 480 удалений

Двоичные данные
Documentation/Resources/playground@2x.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 91 KiB

После

Ширина:  |  Высота:  |  Размер: 122 KiB

Просмотреть файл

@ -0,0 +1,218 @@
/*:
> _Note_: This playground must be running inside the Xcode project to run. Build the OS X framework prior to use. (You may have to close and reopen the project after building it.)
# SQLite.swift
This playground contains sample code to explore [SQLite.swift](https://github.com/stephencelis/SQLite.swift), a [Swift](https://developer.apple.com/swift) wrapper for [SQLite3](https://sqlite.org).
Lets get started by importing the framework and opening a new in-memory database connection using the `Database` class.
*/
import SQLite
let db = Database()
/*:
This implicitly opens a database in `":memory:"`. To open a database at a specific location, pass the path as a parameter during instantiation, *e.g.*,
Database("path/to/database.sqlite3")
Pass `nil` or an empty string (`""`) to open a temporary, disk-backed database, instead.
Once we instantiate a database connection, we can execute SQL statements directly against it. Lets create a table.
*/
db.execute(
"CREATE TABLE users (" +
"id INTEGER PRIMARY KEY, " +
"email TEXT NOT NULL UNIQUE, " +
"age INTEGER, " +
"admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)), " +
"manager_id INTEGER, " +
"FOREIGN KEY(manager_id) REFERENCES users(id)" +
")"
)
/*:
The `execute` function can run multiple SQL statements at once as a convenience and will throw an assertion failure if an error occurs during execution. This is useful for seeding and migrating databases with well-tested statements that are guaranteed to succeed (or where failure can be graceful and silent).
Its generally safer to prepare SQL statements individually. Lets instantiate a `Statement` object and insert a couple rows.
*/
let stmt = db.prepare("INSERT INTO users (email, admin) VALUES (?, ?)")
for (email, admin) in ["alice@acme.com": 1, "betsy@acme.com": 0] {
stmt.run(email, admin)
}
/*:
Prepared statements can bind and escape input values safely. In this case, `email` and `admin` columns are bound with different values over two executions.
The `Database` class exposes information about recently run queries via several properties: `totalChanges` returns the total number of changes (inserts, updates, and deletes) since the connection was opened; `changes` returns the number of changes from the last statement that modified the database; `lastInsertRowid` returns the rowid of the last insert.
*/
db.totalChanges
db.changes
db.lastInsertRowid
/*:
## Querying
`Statement` objects act as both sequences _and_ generators. We can iterate over a select statements rows directly using a `for``in` loop.
*/
for row in db.prepare("SELECT id, email FROM users") {
println("id: \(row[0]), email: \(row[1])")
}
/*:
Single, scalar values can be plucked directly from a statement.
*/
let count = db.prepare("SELECT count(*) FROM users")
count.scalar()
db.scalar("SELECT email FROM users WHERE id = ?", 1)
/*:
> ### Experiment
>
> Try plucking a single row by taking advantage of the fact that `Statement` conforms to the `GeneratorType` protocol.
>
> Also try using the `Array` initializer to return an array of all rows at once.
## Transactions & Savepoints
Using the `transaction` and `savepoint` functions, we can run a series of statements, commiting the changes to the database if they all succeed. If a single statement fails, we bail out early and roll back. In the following example we prepare two statements: one to insert a manager into the database, and onegiven a managers rowidto insert a managed user into the database.
*/
let sr = db.prepare("INSERT INTO users (email, admin) VALUES (?, 1)")
let jr = db.prepare("INSERT INTO users (email, admin, manager_id) VALUES (?, 0, ?)")
/*:
Statements can be chained with other statements using the `&&` and `||` operators. The right-hand side is an auto-closure and therefore has access to database information at the time of execution. In this case, we insert Dolly, a supervisor, and immediately reference her rowid when we insert her assistant, Emery.
*/
db.transaction()
&& sr.run("dolly@acme.com")
&& jr.run("emery@acme.com", db.lastInsertRowid)
&& db.commit()
|| db.rollback()
/*:
Our database has a uniqueness constraint on email address, so lets see what happens when we insert Fiona, who also claims to be managing Emery.
*/
let txn = db.transaction()
&& sr.run("fiona@acme.com")
&& jr.run("emery@acme.com", db.lastInsertRowid)
&& db.commit()
txn || db.rollback()
count.scalar()
txn.failed
txn.reason
/*:
This time, our transaction fails because Emery has already been added to the database. The addition of Fiona has been rolled back, and well need to get to the bottom of this discrepancy (or make some schematic changes to our database to allow for multiple managers per user).
> ### Experiment
>
> Transactions cant be nested, but savepoints can! Try calling the `savepoint` function instead, which shares semantics with `transaction`, but can successfully run in layers.
## Query Building
SQLite.swift provides a powerful, type-safe query builder. With only a small amount of boilerplate to map our columns to types, we can ensure the queries we build are valid upon compilation.
*/
let id = Expression<Int64>("id")
let email = Expression<String>("email")
let age = Expression<Int?>("age")
let admin = Expression<Bool>("admin")
let manager_id = Expression<Int64?>("manager_id")
/*:
The query-building interface is provided via the `Query` struct. We can access this interface by subscripting our database connection with a table name.
*/
let users = db["users"]
/*:
From here, we can build a variety of queries. For example, we can build and run an `INSERT` statement by calling the querys `insert` function. Lets add a few new rows this way.
*/
users.insert(email <- "giles@acme.com", age <- 42, admin <- true).rowid
users.insert(email <- "haley@acme.com", age <- 30, admin <- true).rowid
users.insert(email <- "inigo@acme.com", age <- 24).rowid
/*:
No room for syntax errors! Try changing an input to the wrong type and see what happens.
The `insert` function can return a `rowid` (which will be `nil` in the case of failure) and the just-run `statement`. It can also return a `Statement` object directly, making it easy to run in a transaction.
*/
db.transaction()
&& users.insert(email <- "julie@acme.com")
&& users.insert(email <- "kelly@acme.com", manager_id <- db.lastInsertRowid)
&& db.commit()
|| db.rollback()
/*:
`Query` objects can also build `SELECT` statements. A freshly-subscripted query will select every row (and every column) from a table. Iteration lazily executes the statement.
*/
// SELECT * FROM users
for user in users {
println(user[email])
}
/*:
You may notice that iteration works a little differently here. Rather than arrays of raw values, we are given `Row` objects, which can be subscripted with the same expressions we prepared above. This gives us a little more powerful of a mapping to work with and pass around.
Queries can be used and reused, and can quickly return rows, counts and other aggregate values.
*/
// SELECT * FROM users LIMIT 1
users.first
// SELECT count(*) FROM users
users.count
users.min(age)
users.max(age)
users.average(age)
/*:
> ### Experiment
>
> In addition to `first`, you can also try plucking the `last` row from the result set in an optimized fashion.
>
> The example above uses the computed variable `count`, but `Query` has a `count` function, as well. (The computed variable is actually a convenience wrapper around `count(*)`.) Try counting the distinct ages in our group of users.
>
> Try calling the `sum` and `total` functions. Note the differences!
Queries can be refined using a collection of chainable helper functions. Lets filter our query to the administrator subset.
*/
let admins = users.filter(admin)
/*:
Filtered queries will in turn filter their aggregate functions.
*/
// SELECT count(*) FROM users WHERE admin
admins.count
/*:
Alongside `filter`, we can use the `select`, `join`, `group`, `order`, and `limit` functions to compose rich queries with safety and ease. Lets say we want to order our results by email, then age, and return no more than three rows.
*/
let ordered = admins.order(email.asc, age.asc).limit(3)
// SELECT * FROM users WHERE admin ORDER BY email ASC, age ASC LIMIT 3
for admin in ordered {
println(admin[id])
println(admin[age])
}
/*:
> ### Experiment
>
> Try using the `select` function to specify which columns are returned.
>
> Try using the `group` function to group users by a column.
>
> Try to return results by a column in descending order.
>
> Try using an alternative `limit` function to add an `OFFSET` clause to the query.
We can further filter by chaining additional conditions onto the query. Lets find administrators that havent (yet) provided their ages.
*/
let agelessAdmins = admins.filter(age == nil)
// SELECT count(*) FROM users WHERE (admin AND age IS NULL)
agelessAdmins.count
/*:
Unfortunately, the HR department has ruled that age disclosure is required for administrator responsibilities. We can use our querys `update` interface to (temporarily) revoke their privileges while we wait for them to update their profiles.
*/
// UPDATE users SET admin = 0 WHERE (admin AND age IS NULL)
agelessAdmins.update(admin <- false).changes
/*:
If we ever need to remove rows from our database, we can use the `delete` function, which will be scoped to a querys filters. **Be careful!** You may just want to archive the records, instead.
We dont archive user data at Acme Inc. (we respect privacy, after all), and unfortunately, Alice has decided to move on. We can carefully, _carefully_ scope a query to match her and delete her record.
*/
// DELETE FROM users WHERE (email = 'alice@acme.com')
users.filter(email == "alice@acme.com").delete().changes
/*:
And thats that.
## & More
Weve only explored the surface to SQLite.swift. Dive into the code to discover more!
*/

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<aside>
<h4>Note</h4>
<p>
This playground must be running inside the Xcode project to run. Build the iOS framework prior to use.
</p>
</aside>
<h3>SQLite.swift</h3>
<p>
This playground contains sample code to explore <a href='https://github.com/stephencelis/SQLite.swift'>SQLite.swift</a>, a <a href='https://developer.apple.com/swift'>Swift</a> wrapper for <a href='https://sqlite.org'>SQLite3</a>.
</p>
<p>
Lets get started by importing the framework and opening a new in-memory database connection using the <code>Database</code> class.
</p>
</section>

Просмотреть файл

@ -1,14 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<meta name='apple-mobile-web-app-capable' content='yes'>
<meta name='viewport' content='width = device-width, maximum-scale=1.0'>
<section>
<p>
This implicitly opens a database in <code>":memory:"</code>. To open a database at a specific location, pass the path as a parameter during instantiation, <em>e.g.</em>, <code>Database("path/to/database.sqlite3")</code>. Pass <code>nil</code> or an empty string (<code>""</code>) to open a temporary, disk-backed database, instead.
</p>
<p>
Once we instantiate a database connection, we can execute SQL statements directly against it. Lets create a table.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
The query-building interface is provided via the <code>Query</code> struct. We can access this interface by subscripting our database connection with a table name.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
From here, we can build a variety of queries. For example, we can build and run an <code>INSERT</code> statement by calling the querys <code>insert</code> function. Lets add a few new rows this way.
</p>
</section>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
No room for syntax errors! Try changing an input to the wrong type and see what happens.
</p>
<p>
The <code>insert</code> function can return an <code>ID</code> (which will be <code>nil</code> in the case of failure) and the just-run <code>statement</code>. It can also return a <code>Statement</code> object directly, making it easy to run in a transaction.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
<code>Query</code> objects can also build <code>SELECT</code> statements. A freshly-subscripted query will select every row (and every column) from a table. Iteration lazily executes the statement.
</p>
</section>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
You may notice that iteration works a little differently here. Rather than arrays of raw values, we are given <code>Row</code> objects, which can be subscripted with the same expressions we prepared above. This gives us a little more powerful of a mapping to work with and pass around.
</p>
<p>
Queries can be used and reused, and can quickly return rows, counts and other aggregate values.
</p>
</section>

Просмотреть файл

@ -1,21 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<aside>
<h4>Experiment</h4>
<!-- <p>
In addition to <code>first</code>, you can also try plucking the <code>last</code> row from the result set in an optimized fashion.
</p> -->
<!-- <p>
The example above uses the computed variable <code>count</code>, but <code>Query</code> has a <code>count</code> function, as well. (The computed variable is actually a convenience wrapper around <code>count("*")</code>.) Try counting the distinct ages in our group of users.
</p> -->
<p>
Try calling the <code>sum</code> and <code>total</code> functions. Note the differences!
</p>
</aside>
<p>
Queries can be refined using a collection of chainable helper functions. Lets filter our query to the administrator subset.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Filtered queries will in turn filter their aggregate functions.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Alongside <code>filter</code>, we can use the <code>select</code>, <code>join</code>, <code>group</code>, <code>order</code>, and <code>limit</code> functions to compose rich queries with safety and ease. Lets say we want to order our results by email, then age, and return no more than three rows.
</p>
</section>

Просмотреть файл

@ -1,24 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<aside>
<h4>Experiment</h4>
<p>
Try using the <code>select</code> function to specify which columns are returned.
</p>
<p>
Try using the <code>group</code> function to group users by a column.
</p>
<p>
Try to return results by a column in descending order.
</p>
<p>
Try using an alternative <code>limit</code> function to add an <code>OFFSET</code> clause to the query.
</p>
</aside>
<p>
We can further filter by chaining additional conditions onto the query. Lets find administrators that havent (yet) provided their ages.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Unfortunately, the HR department has ruled that age disclosure is required for administrator responsibilities. We can use our querys <code>update</code> interface to (temporarily) revoke their privileges while we wait for them to update their profiles.
</p>
</section>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
The <code>execute</code> function can run multiple SQL statements at once as a convenience and will throw an assertion failure if an error occurs during execution. This is useful for seeding and migrating databases with well-tested statements that are guaranteed to succeed (or where failure can be graceful and silent).
</p>
<p>
Its generally safer to prepare SQL statements individually. Lets instantiate a <code>Statement</code> object and insert a couple rows.
</p>
</section>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
If we ever need to remove rows from our database, we can use the <code>delete</code> function, which will be scoped to a querys filters. <strong>Be careful!</strong> You may just want to archive the records, instead.
</p>
<p>
We dont archive user data at Acme Inc. (we respect privacy, after all), and unfortunately, Alice has decided to move on. We can carefully, <em>carefully</em> scope a query to match her and delete her record.
</p>
</section>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
And thats that.
</p>
<h3>&amp; More…</h3>
<p>
Weve only explored the surface to SQLite.swift. Dive into the code to discover more!
</p>
</section>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Prepared statements can bind and escape input values safely. In this case, <code>email</code> and <code>admin</code> columns are bound with different values over two executions.
</p>
<p>
The <code>Database</code> class exposes information about recently run queries via several properties: <code>totalChanges</code> returns the total number of changes (inserts, updates, and deletes) since the connection was opened; <code>lastChanges</code> returns the number of changes from the last statement that modified the database; <code>lastID</code> returns the row ID of the last insert.
</p>
</section>

Просмотреть файл

@ -1,10 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<h3>Querying</h3>
<p>
<code>Statement</code> objects act as both sequences <em>and</em> generators. We can iterate over a select statements rows directly using a <code>for</code><code>in</code> loop.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Single, scalar values can be plucked directly from a statement.
</p>
</section>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<aside>
<h4>Experiment</h4>
<p>
Try plucking a single row by taking advantage of the fact that <code>Statement</code> conforms to the <code>GeneratorType</code> protocol.
</p>
<p>
Also try using the <code>Array</code> initializer to return an array of all rows at once.
</p>
</aside>
<h3>Transactions &amp; Savepoints</h3>
<p>
Using the <code>transaction</code> and <code>savepoint</code> functions, we can run a series of statements, commiting the changes to the database if they all succeed. If a single statement fails, we bail out early and roll back. In the following example we prepare two statements: one to insert a manager into the database, and one—given a managers row ID—to insert a managed user into the database.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Arguments sent to <code>transaction</code> are auto-closures and therefore have access to <code>Database</code> information at the time of execution. In this case, we insert Dolly, a supervisor, and immediately reference her row ID when we insert her assistant, Emery.
</p>
</section>

Просмотреть файл

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
Our database has a uniqueness constraint on email address, so lets see what happens when we insert Fiona, who also claims to be managing Emery.
</p>
</section>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel='stylesheet' type='text/css' href='style-1.1.15.css'>
<meta id='xcode-display' name='xcode-display' content='render'>
<section>
<p>
This time, our transaction fails because Emery has already been added to the database. The addition of Fiona has been rolled back, and well need to get to the bottom of this discrepancy (or make some schematic changes to our database to allow for multiple managers per user).
</p>
<aside>
<h4>Experiment</h4>
<p>
Transactions cant be nested, but savepoints can! Try calling the <code>savepoint</code> function instead, which shares semantics with <code>transaction</code>, but can successfully run in layers.
</p>
</aside>
<h3>Query Building</h3>
<p>
SQLite.swift provides a powerful, type-safe query builder. With only a small amount of boilerplate to map our columns to types, we can ensure the queries we build are valid upon compilation.
</p>
</section>

Просмотреть файл

@ -1,65 +0,0 @@
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,
abbr,acronym,address,big,cite,code,del,dfn,em,figure,font,img,ins,kbd,q,s,
samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,
fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
border: 0;
font-size: 100%;
margin: 0;
outline: 0;
padding: 0;
vertical-align: baseline
}
body {
background-color: rgba(255,255,255,0.65);
color: rgba(0,0,0,1);
font-family: Helvetica,sans-serif;
font-size: 62.5%;
margin-left: 15px;
}
section {
padding: 20px 25px 20px 35px
}
h3 {
color: rgba(128,128,128,1);
display: block;
font-size: 2.2em;
font-weight: 100;
margin-bottom: 15px;
margin-top: 20px;
}
p {
color: rgba(65,65,65,1);
font-size: 1.4em;
line-height: 145%;
margin-bottom: 5px;
}
a {
color: rgba(0,136,204,1);
text-decoration: none
}
code {
color: rgba(128,128,128,1);
font-family: Menlo,monospace;
font-size: .9em;
word-wrap: break-word
}
h4 {
color: rgba(128,128,128,1);
font-size: .6em;
font-weight: normal;
letter-spacing: 2px;
margin-bottom: 8px;
text-transform: uppercase
}
aside {
background-color: rgba(249,249,249,1);
border-left: 5px solid rgba(238,238,238,1);
font-size: 1.2em;
margin: 25px 45px 35px 35px;
padding: 15px 15px 7px;
}
aside p {
font-size: 1em;
margin-bottom: 8px
}

Просмотреть файл

@ -1,49 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='3.0' sdk='iphonesimulator'>
<sections>
<documentation relative-path='fragment-0.html'/>
<code source-file-name='section-2.swift'/>
<documentation relative-path='fragment-1.html'/>
<code source-file-name='section-4.swift'/>
<documentation relative-path='fragment-2.html'/>
<code source-file-name='section-6.swift'/>
<documentation relative-path='fragment-3.html'/>
<code source-file-name='section-8.swift'/>
<documentation relative-path='fragment-4.html'/>
<code source-file-name='section-10.swift'/>
<documentation relative-path='fragment-5.html'/>
<code source-file-name='section-12.swift'/>
<documentation relative-path='fragment-6.html'/>
<code source-file-name='section-14.swift'/>
<documentation relative-path='fragment-7.html'/>
<code source-file-name='section-16.swift'/>
<documentation relative-path='fragment-8.html'/>
<code source-file-name='section-18.swift'/>
<documentation relative-path='fragment-9.html'/>
<code source-file-name='section-20.swift'/>
<documentation relative-path='fragment-10.html'/>
<code source-file-name='section-22.swift'/>
<documentation relative-path='fragment-11.html'/>
<code source-file-name='section-24.swift'/>
<documentation relative-path='fragment-12.html'/>
<code source-file-name='section-26.swift'/>
<documentation relative-path='fragment-13.html'/>
<code source-file-name='section-28.swift'/>
<documentation relative-path='fragment-14.html'/>
<code source-file-name='section-30.swift'/>
<documentation relative-path='fragment-15.html'/>
<code source-file-name='section-32.swift'/>
<documentation relative-path='fragment-16.html'/>
<code source-file-name='section-34.swift'/>
<documentation relative-path='fragment-17.html'/>
<code source-file-name='section-36.swift'/>
<documentation relative-path='fragment-18.html'/>
<code source-file-name='section-38.swift'/>
<documentation relative-path='fragment-19.html'/>
<code source-file-name='section-40.swift'/>
<documentation relative-path='fragment-20.html'/>
<code source-file-name='section-42.swift'/>
<documentation relative-path='fragment-21.html'/>
</sections>
<playground version='5.0' target-platform='osx' display-mode='rendered'>
<timeline fileName='timeline.xctimeline'/>
</playground>

Просмотреть файл

@ -1,3 +0,0 @@
for row in db.prepare("SELECT id, email FROM users") {
println("id: \(row[0]), email: \(row[1])")
}

Просмотреть файл

@ -1,4 +0,0 @@
let count = db.prepare("SELECT count(*) FROM users")
count.scalar()
db.scalar("SELECT email FROM users WHERE id = ?", 1)

Просмотреть файл

@ -1,2 +0,0 @@
let sr = db.prepare("INSERT INTO users (email, admin) VALUES (?, 1)")
let jr = db.prepare("INSERT INTO users (email, admin, manager_id) VALUES (?, 0, ?)")

Просмотреть файл

@ -1,4 +0,0 @@
db.transaction() &&
sr.run("dolly@acme.com") &&
jr.run("emery@acme.com", db.lastId) &&
db.commit() || db.rollback()

Просмотреть файл

@ -1,10 +0,0 @@
let txn = db.transaction() &&
sr.run("fiona@acme.com") &&
jr.run("emery@acme.com", db.lastId) &&
db.commit()
txn || db.rollback()
count.scalar()
txn.failed
txn.reason

Просмотреть файл

@ -1,3 +0,0 @@
import SQLite
let db = Database()

Просмотреть файл

@ -1,5 +0,0 @@
let id = Expression<Int>("id")
let email = Expression<String>("email")
let age = Expression<Int?>("age")
let admin = Expression<Bool>("admin")
let manager_id = Expression<Int?>("manager_id")

Просмотреть файл

@ -1 +0,0 @@
let users = db["users"]

Просмотреть файл

@ -1,3 +0,0 @@
users.insert(email <- "giles@acme.com", age <- 42, admin <- true).id
users.insert(email <- "haley@acme.com", age <- 30, admin <- true).id
users.insert(email <- "inigo@acme.com", age <- 24).id

Просмотреть файл

@ -1,4 +0,0 @@
db.transaction() &&
users.insert(email <- "julie@acme.com") &&
users.insert(email <- "kelly@acme.com", manager_id <- db.lastId) &&
db.commit() || db.rollback()

Просмотреть файл

@ -1,4 +0,0 @@
// SELECT * FROM users
for user in users {
println(user[email])
}

Просмотреть файл

@ -1,9 +0,0 @@
// SELECT * FROM users LIMIT 1
users.first
// SELECT count(*) FROM users
users.count
users.min(age)
users.max(age)
users.average(age)

Просмотреть файл

@ -1 +0,0 @@
let admins = users.filter(admin)

Просмотреть файл

@ -1,2 +0,0 @@
// SELECT count(*) FROM users WHERE admin
admins.count

Просмотреть файл

@ -1,7 +0,0 @@
let ordered = admins.order(email.asc, age.asc).limit(3)
// SELECT * FROM users WHERE admin ORDER BY email ASC, age ASC LIMIT 3
for admin in ordered {
println(admin[id])
println(admin[age])
}

Просмотреть файл

@ -1,4 +0,0 @@
let agelessAdmins = admins.filter(age == nil)
// SELECT count(*) FROM users WHERE (admin AND age IS NULL)
agelessAdmins.count

Просмотреть файл

@ -1,10 +0,0 @@
db.execute(
"CREATE TABLE users (" +
"id INTEGER PRIMARY KEY, " +
"email TEXT NOT NULL UNIQUE, " +
"age INTEGER, " +
"admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)), " +
"manager_id INTEGER, " +
"FOREIGN KEY(manager_id) REFERENCES users(id)" +
")"
)

Просмотреть файл

@ -1,2 +0,0 @@
// UPDATE users SET admin = 0 WHERE (admin AND age IS NULL)
agelessAdmins.update(admin <- false).changes

Просмотреть файл

@ -1,2 +0,0 @@
// DELETE FROM users WHERE (email = 'alice@acme.com')
users.filter(email == "alice@acme.com").delete().changes

Просмотреть файл

@ -1,4 +0,0 @@
let stmt = db.prepare("INSERT INTO users (email, admin) VALUES (?, ?)")
for (email, admin) in ["alice@acme.com": 1, "betsy@acme.com": 0] {
stmt.run(email, admin)
}

Просмотреть файл

@ -1,3 +0,0 @@
db.totalChanges
db.lastChanges
db.lastId

Просмотреть файл

@ -134,6 +134,7 @@
DC475E9E19F2199900788FBD /* ExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionTests.swift; sourceTree = "<group>"; };
DC5B12121ABE3298000DA146 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/lib/libsqlite3.dylib; sourceTree = DEVELOPER_DIR; };
DC650B9519F0CDC3002FBE91 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Expression.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
DC97EC9F1ADE955E00F550A6 /* SQLite.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SQLite.playground; sourceTree = "<group>"; };
DC9D389B1AAD458500780AE7 /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../Vendor/fts3_tokenizer.h; sourceTree = "<group>"; };
DCAD429619E2E0F1004A51DF /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Query.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
DCAD429919E2EE50004A51DF /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
@ -145,7 +146,6 @@
DCAE4D311ABE0B8B00EFCE7A /* macosx.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = macosx.modulemap; sourceTree = "<group>"; };
DCAFEAD21AABC818000C21A1 /* FTS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS.swift; sourceTree = "<group>"; };
DCAFEAD61AABEFA7000C21A1 /* FTSTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTSTests.swift; sourceTree = "<group>"; };
DCBC8C301ABE3CDA002B4631 /* SQLite.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SQLite.playground; sourceTree = "<group>"; };
DCBE28401ABDF18F0042A3FC /* RTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTree.swift; sourceTree = "<group>"; };
DCBE28441ABDF2A80042A3FC /* RTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTreeTests.swift; sourceTree = "<group>"; };
DCC6B3801A9191C300734B78 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -245,7 +245,7 @@
isa = PBXGroup;
children = (
DC37744719C8F50B004FCF85 /* README.md */,
DCBC8C301ABE3CDA002B4631 /* SQLite.playground */,
DC97EC9F1ADE955E00F550A6 /* SQLite.playground */,
DC37742D19C8CC90004FCF85 /* SQLite */,
DC10500F19C904DD00D8CA30 /* SQLite Tests */,
DCC6B3A11A91949C00734B78 /* SQLiteCipher */,