Giter Club home page Giter Club logo

sqlite.swift's Introduction

SQLite.swift

Build Status CocoaPods Version Swift5 compatible Platform Carthage compatible Join the chat at https://gitter.im/stephencelis/SQLite.swift

A type-safe, Swift-language layer over SQLite3.

SQLite.swift provides compile-time confidence in SQL statement syntax and intent.

Features

  • A pure-Swift interface
  • A type-safe, optional-aware SQL expression builder
  • A flexible, chainable, lazy-executing query layer
  • Automatically-typed data access
  • A lightweight, uncomplicated query and parameter binding interface
  • Developer-friendly error handling and debugging
  • Full-text search support
  • Well-documented
  • Extensively tested
  • SQLCipher support via CocoaPods
  • Schema query/migration
  • Works on Linux (with some limitations)
  • Active support at StackOverflow, and Gitter Chat Room (experimental)

Usage

import SQLite

// Wrap everything in a do...catch to handle errors
do {
    let db = try Connection("path/to/db.sqlite3")

    let users = Table("users")
    let id = Expression<Int64>("id")
    let name = Expression<String?>("name")
    let email = Expression<String>("email")

    try db.run(users.create { t in
        t.column(id, primaryKey: true)
        t.column(name)
        t.column(email, unique: true)
    })
    // CREATE TABLE "users" (
    //     "id" INTEGER PRIMARY KEY NOT NULL,
    //     "name" TEXT,
    //     "email" TEXT NOT NULL UNIQUE
    // )

    let insert = users.insert(name <- "Alice", email <- "[email protected]")
    let rowid = try db.run(insert)
    // INSERT INTO "users" ("name", "email") VALUES ('Alice', '[email protected]')

    for user in try db.prepare(users) {
        print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
        // id: 1, name: Optional("Alice"), email: [email protected]
    }
    // SELECT * FROM "users"

    let alice = users.filter(id == rowid)

    try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
    // UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
    // WHERE ("id" = 1)

    try db.run(alice.delete())
    // DELETE FROM "users" WHERE ("id" = 1)

    try db.scalar(users.count) // 0
    // SELECT count(*) FROM "users"
} catch {
    print (error)
}

SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C API.

// Wrap everything in a do...catch to handle errors
do {
    // ...

    let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)")
    for email in ["[email protected]", "[email protected]"] {
        try stmt.run(email)
    }

    db.totalChanges    // 3
    db.changes         // 1
    db.lastInsertRowid // 3

    for row in try db.prepare("SELECT id, email FROM users") {
        print("id: \(row[0]), email: \(row[1])")
        // id: Optional(2), email: Optional("[email protected]")
        // id: Optional(3), email: Optional("[email protected]")
    }

    try db.scalar("SELECT count(*) FROM users") // 2
} catch {
    print (error)
}

Read the documentation or explore more, interactively, from the Xcode project’s playground.

SQLite.playground Screen Shot

Installation

Swift Package Manager

The Swift Package Manager is a tool for managing the distribution of Swift code.

  1. Add the following to your Package.swift file:
dependencies: [
    .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.15.3")
]
  1. Build your project:
$ swift build

See the Tests/SPM folder for a small demo project which uses SPM.

Carthage

Carthage is a simple, decentralized dependency manager for Cocoa. To install SQLite.swift with Carthage:

  1. Make sure Carthage is installed.

  2. Update your Cartfile to include the following:

    github "stephencelis/SQLite.swift" ~> 0.15.3
  3. Run carthage update and add the appropriate framework.

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. To install SQLite.swift with CocoaPods:

  1. Make sure CocoaPods is installed.

    # Using the default Ruby install will require you to use sudo when
    # installing and updating gems.
    [sudo] gem install cocoapods
  2. Update your Podfile to include the following:

    use_frameworks!
    
    target 'YourAppTargetName' do
        pod 'SQLite.swift', '~> 0.14.0'
    end
  3. Run pod install --repo-update.

Manual

To install SQLite.swift as an Xcode sub-project:

  1. Drag the SQLite.xcodeproj file into your own project. (Submodule, clone, or download the project first.)

    Installation Screen Shot

  2. In your target’s General tab, click the + button under Linked Frameworks and Libraries.

  3. Select the appropriate SQLite.framework for your platform.

  4. Add.

Some additional steps are required to install the application on an actual device:

  1. In the General tab, click the + button under Embedded Binaries.

  2. Select the appropriate SQLite.framework for your platform.

  3. Add.

Communication

See the planning document for a roadmap and existing feature requests.

Read the contributing guidelines. The TL;DR (but please; R):

Original author

License

SQLite.swift is available under the MIT license. See the LICENSE file for more information.

Related

These projects enhance or use SQLite.swift:

Alternatives

Looking for something else? Try another Swift wrapper (or FMDB):

sqlite.swift's People

Contributors

adamwulf avatar atultw avatar benrlewis7450g avatar cjwirth avatar geoffmacd avatar jacobhearst avatar jberkel avatar kasei avatar kdubb avatar kujenga avatar mariotaku avatar marmphco avatar mcfedr avatar mikemee avatar nathanfallet avatar nickmshelley avatar ottosuess avatar p2 avatar redetection avatar sagarsdagdu avatar sburlewapg avatar sebastianosinski avatar st3fan avatar stefansaasen avatar stephencelis avatar tableau-david-potter avatar thebluepotato avatar wadetregaskis avatar willhbr avatar ypopovych avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlite.swift's Issues

SQL "LIKE" statement?

Hi,

This looks super promising - is there anyway I can do "LIKE" queries?

Thanks in advance!

Access column names by Expression name in query results

I need to join the the results of a query, this is my code:

let query = "SELECT p.* , c.id as categoryid, c.name as categoryname, c.thumb as categorythumb, c.orderid as categorysortid FROM pdf p inner join categories c on c.id=p.categoryid WHERE p.languageId='(language.id)'"
let pdfs = pdfDb!.prepare(query);

for row in pdfs {
println(row)
}

I can see the results are correct as aspected.
but when I try to get the columns names, it look I can only access them with an index, like row[0], and not by name like this:

let _categoryid = Expression("categoryid")
let categoryid = row[_categoryid]

Is this possible?

SQLITE_BLOB support

I have a database with a column of type BLOB.
It looks it is not supported by your framework.

this is what I used to use with objective C

  • (NSMutableArray *) select:(NSString *) query
    {
    NSMutableArray *results = [[NSMutableArray alloc] init];

    if (sqlite3_open([self.dbPath UTF8String], &_db) == SQLITE_OK)
    {
    sqlite3_stmt *selection;

    if ((sqlite3_prepare_v2(_db, (char *)[query UTF8String], -1, &selection, NULL)) == SQLITE_OK)
    {
        NSMutableDictionary *record = [[NSMutableDictionary alloc] init];
    
        while (sqlite3_step(selection) == SQLITE_ROW)
        {
            [record removeAllObjects];
    
            for (int i = 0; i < sqlite3_column_count(selection); i++)
            {
                NSString *fieldName = [NSString stringWithFormat:@"%s", sqlite3_column_name(selection, i)];
    
                switch (sqlite3_column_type(selection, i))
                {
                    case SQLITE_INTEGER:
                        record[fieldName] = @(sqlite3_column_int(selection, i));
                        break;
    
                    case SQLITE_FLOAT:
                        record[fieldName] = @(sqlite3_column_double(selection, i));
                        break;
    
                    case SQLITE_TEXT:
                        record[fieldName] = @((char *)sqlite3_column_text(selection, i));
                        break;
    
                    case SQLITE_BLOB:
                        record[fieldName] = [[NSData alloc] initWithBytes:sqlite3_column_blob(selection, i) length:sqlite3_column_bytes(selection, i)];
                        break;
    
                    case SQLITE_NULL:
    
                        break;
                }
            }
            [results addObject:[record copy]];
        }
    }
    else
        NSLog(@"%s", sqlite3_errmsg(_db));
    
    [self closeConnection];
    

    }
    return results;
    }

Access column by name broken

The following worked until a few commits ago (in the past 2-3 days, I'm still trying to figure out where)

var query = "SELECT * FROM things"
let statement = db.prepare(query)
while ((statement.next()) != nil){
            let row = statement.values!
            let id = row["id"]
            println "ID is \(id)"
}

I now get "'Statement' does not have a member names 'values'". I changed it to state.row!, but I am not able to get columns by name any more. I would like to keep te syntax as close to what I have as possible (I have a few hundred files that use row["colname"]).

What's the closest I can get?

I can't get the playground to work

I open the SQLite project, run the build command, than select the SQLite.playground file, but it doesn't print the results.
Am I missing some steps?

EXC_BAD_ACCESS

I have a very straight forward database that I fairly frequently get EXC_BAD_ACCESS with. It's not 100% clear that this isn't my own fault, but the code is fairly basic:

let row = self.cache.filter(self.id == Int(id) && self.context == context).first 

Occasionally this results in the following. Any ideas?

What does seem a bit odd is that it seems to be recursively calling try().

Thread 76: EXC_BAD_ACCESS (code=1, address=0x616369666669746f6e)

#0  0x0000000194508cb8 in ___lldb_unnamed_function167$$libsqlite3.dylib ()
#1  0x00000001944df690 in ___lldb_unnamed_function84$$libsqlite3.dylib ()
#2  0x00000001944c5c70 in ___lldb_unnamed_function42$$libsqlite3.dylib ()
#3  0x00000001944c48b0 in ___lldb_unnamed_function41$$libsqlite3.dylib ()
#4  0x00000001944c3b14 in ___lldb_unnamed_function38$$libsqlite3.dylib ()
#5  0x00000001944c33a4 in ___lldb_unnamed_function37$$libsqlite3.dylib ()
#6  0x00000001944c304c in ___lldb_unnamed_function36$$libsqlite3.dylib ()
#7  0x0000000100e814c0 in SQLite.Statement.(init (SQLite.Statement.Type) -> (SQLite.Database, Swift.String) -> SQLite.Statement).(implicit closure #1) at MyApp/Vendor/SQLite.swift/SQLite Common/Statement.swift:36
#8  0x0000000100eaa464 in SQLite.Database.(try (SQLite.Database) -> (@autoclosure () -> Swift.Int32) -> ()).(closure #1) at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:335
#9  0x0000000100eaa66c in reabstraction thunk helper from @callee_owned () -> (@unowned ()) to @callee_unowned @objc_block () -> (@unowned ()) at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:342
#10 0x0000000100d18df0 in _dispatch_client_callout ()
#11 0x0000000100d228c8 in _dispatch_barrier_sync_f_invoke ()
#12 0x0000000100ea7304 in SQLite.Database.perform (SQLite.Database)(() -> ()) -> () at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:342
#13 0x0000000100ea40f4 in SQLite.Database.try (SQLite.Database)(@autoclosure () -> Swift.Int32) -> () at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:335
#14 0x0000000100e7b6f8 in SQLite.Statement.init (SQLite.Statement.Type)(SQLite.Database, Swift.String) -> SQLite.Statement at MyApp/Vendor/SQLite.swift/SQLite Common/Statement.swift:36
#15 0x0000000100e7b784 in SQLite.Statement.__allocating_init (SQLite.Statement.Type)(SQLite.Database, Swift.String) -> SQLite.Statement ()
#16 0x0000000100ea45fc in SQLite.Database.prepare (SQLite.Database)(Swift.String, Swift.Array<Swift.Optional<SQLite.Binding>>...) -> SQLite.Statement at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:91
#17 0x0000000100ea471c in SQLite.Database.prepare (SQLite.Database)(Swift.String, Swift.Array<Swift.Optional<SQLite.Binding>>) -> SQLite.Statement at MyApp/Vendor/SQLite.swift/SQLite Common/Database.swift:102
#18 0x0000000100e4f5b4 in SQLite.Query.selectStatement.getter : SQLite.Statement at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:320
#19 0x0000000100e7365c in SQLite.QueryGenerator.((columnNames in _14CB4A30965D85E6DF5BEBC63D2EB0EA).getter : Swift.Dictionary<Swift.String, Swift.Int>).(closure #1).((expandGlob #1) (Swift.Bool) -> (SQLite.Query) -> ()).(closure #1) at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:797
#20 0x0000000100e75008 in reabstraction thunk helper from @callee_owned (@in SQLite.Query) -> (@unowned ()) to @callee_owned (@in SQLite.Query) -> (@out ()) at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:814
#21 0x0000000100e6cf6c in partial apply forwarder for reabstraction thunk helper from @callee_owned (@in SQLite.Query) -> (@unowned ()) to @callee_owned (@in SQLite.Query) -> (@out ()) ()
#22 0x0000000100959d94 in Swift.MapCollectionView.subscript.getter (A.Index) -> B ()
#23 0x000000010095b520 in protocol witness for Swift.CollectionType.subscript.getter (Swift.CollectionType.Self.Index) -> Swift.CollectionType.Self.Generator.Element in conformance Swift.MapCollectionView : Swift.CollectionType ()
#24 0x00000001009578e0 in protocol witness for Swift.CollectionType.subscript.getter (Swift.CollectionType.Self.Index) -> Swift.CollectionType.Self.Generator.Element in conformance Swift.LazyRandomAccessCollection : Swift.CollectionType ()
#25 0x00000001008cf35c in Swift._copyCollectionToNativeArrayBuffer <A : Swift.CollectionType>(A) -> Swift._ContiguousArrayBuffer<A._Element> ()
#26 0x000000010095774c in protocol witness for Swift.SequenceType.~> infix <A : Swift.SequenceType>(Swift.SequenceType.Self.Type)(Swift.SequenceType.Self, (Swift._CopyToNativeArrayBuffer, ())) -> Swift._ContiguousArrayBuffer<Swift.SequenceType.Self.Generator.Element> in conformance Swift.LazyRandomAccessCollection : Swift.SequenceType ()
#27 0x00000001008ea8a4 in Swift.Array.map <A>(Swift.Array<A>)<B>((A) -> B) -> Swift.Array<B> ()
#28 0x0000000100e73194 in SQLite.QueryGenerator.((columnNames in _14CB4A30965D85E6DF5BEBC63D2EB0EA).getter : Swift.Dictionary<Swift.String, Swift.Int>).(closure #1) at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:814
#29 0x0000000100e6a3a0 in SQLite.QueryGenerator.(columnNames in _14CB4A30965D85E6DF5BEBC63D2EB0EA).getter : Swift.Dictionary<Swift.String, Swift.Int> at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:789
#30 0x0000000100e6fb10 in SQLite.QueryGenerator.(next (inout SQLite.QueryGenerator) -> () -> Swift.Optional<SQLite.Row>).(closure #1) at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:828
#31 0x0000000100e6fb78 in reabstraction thunk helper from @callee_owned (@owned Swift.Array<Swift.Optional<SQLite.Binding>>) -> (@owned SQLite.Row) to @callee_owned (@in Swift.Array<Swift.Optional<SQLite.Binding>>) -> (@out SQLite.Row) at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:828
#32 0x0000000100e6ae04 in partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.Array<Swift.Optional<SQLite.Binding>>) -> (@owned SQLite.Row) to @callee_owned (@in Swift.Array<Swift.Optional<SQLite.Binding>>) -> (@out SQLite.Row) ()
#33 0x000000010095f3d0 in Swift.Optional.map <A>(Swift.Optional<A>)<B>((A) -> B) -> Swift.Optional<B> ()
#34 0x0000000100e57298 in SQLite.QueryGenerator.next (inout SQLite.QueryGenerator)() -> Swift.Optional<SQLite.Row> at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:828
#35 0x0000000100e566c8 in SQLite.Query.first.getter : Swift.Optional<SQLite.Row> at MyApp/Vendor/SQLite.swift/SQLite Common/Query.swift:420
#36 0x000000010045a730 in MyAppAPI.Cache.get (MyAppAPI.Cache)<A : ProtocolBuffers.Message>(forContext : Swift.String, withId : Swift.Int64) -> Swift.Optional<A> at MyAppAPI/MyAppAPI/Cache.swift:47
#37 0x000000010047c958 in MyAppAPI.MyApp.markNotificationsAsRead (MyAppAPI.MyApp)(Swift.Array<MyAppAPI.Notification>) -> () at MyAppAPI/MyAppAPI/MyApp.swift:455
#38 0x00000001001200e0 in MyApp.NotificationsViewController.(close (MyApp.NotificationsViewController) -> (ObjectiveC.UIBarButtonItem) -> ()).(closure #1) at MyApp/ViewControllers/Notifications/NotificationsViewController.swift:137
#39 0x00000001000c8df8 in MyApp.Async.((cancellable in _9B555F11758C34BF9A5A1BA6338934FB) (MyApp.Async) -> (@objc_block () -> ()) -> @objc_block () -> ()).(closure #1) [inlined] at MyApp/Vendor/Async.legacy/AsyncLegacy.swift:175
#40 0x00000001000c8de4 in partial apply forwarder for MyApp.Async.((cancellable in _9B555F11758C34BF9A5A1BA6338934FB) (MyApp.Async) -> (@objc_block () -> ()) -> @objc_block () -> ()).(closure #1) with unmangled suffix "39" ()
#41 0x0000000100d18e30 in _dispatch_call_block_and_release ()
#42 0x0000000100d18df0 in _dispatch_client_callout ()
#43 0x0000000100d259a0 in _dispatch_root_queue_drain ()
#44 0x0000000100d26f18 in _dispatch_worker_thread3 ()
#45 0x00000001949ad2e4 in _pthread_wqthread ()
#46 0x00000001949acfa8 in start_wqthread ()

Enqueued from com.apple.main-thread (Thread 1)Queue : com.apple.main-thread (serial)
#0  0x0000000100d1dcf8 in dispatch_group_async ()
#1  0x00000001000c7480 in MyApp.Async.init (MyApp.Async.Type)() -> MyApp.Async [inlined] at MyApp/Vendor/Async.legacy/AsyncLegacy.swift:87
#2  0x00000001000c73d0 in MyApp.Async.background (MyApp.Async.Type)(@objc_block () -> ()) -> MyApp.Async at MyApp/Vendor/Async.legacy/AsyncLegacy.swift:108
#3  0x000000010011de28 in MyApp.NotificationsViewController.close (MyApp.NotificationsViewController)(ObjectiveC.UIBarButtonItem) -> () [inlined] at MyApp/ViewControllers/Notifications/NotificationsViewController.swift:135
#4  0x000000010011de1c in @objc MyApp.NotificationsViewController.close (MyApp.NotificationsViewController)(ObjectiveC.UIBarButtonItem) -> () ()
#5  0x0000000188268d34 in -[UIApplication sendAction:to:from:forEvent:] ()
#6  0x0000000188251e48 in -[UIControl _sendActionsForEvents:withEvent:] ()
#7  0x00000001882686d0 in -[UIControl touchesEnded:withEvent:] ()
#8  0x000000018826835c in -[UIWindow _sendTouchesForEvent:] ()
#9  0x00000001882618b0 in -[UIWindow sendEvent:] ()
#10 0x0000000188234fa8 in -[UIApplication sendEvent:] ()
#11 0x00000001884d3f58 in _UIApplicationHandleEventFromQueueEvent ()
#12 0x0000000188233510 in _UIApplicationHandleEventQueue ()
#13 0x0000000183a3a9ec in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#14 0x0000000183a39c90 in __CFRunLoopDoSources0 ()
#15 0x0000000183a37d40 in __CFRunLoopRun ()
#16 0x00000001839650a4 in CFRunLoopRunSpecific ()
#17 0x000000018cb0f5a4 in GSEventRunModal ()
#18 0x000000018829a3c0 in UIApplicationMain ()
#19 0x00000001000e4cb4 in top_level_code [inlined] at MyApp/AppDelegate.swift:22
#20 0x00000001000e4c64 in main ()
#21 0x00000001947faa08 in start ()

About insert and unresolved identifiers

Hello there,

I'm just trying to use SQLite.swift doing this:

-I created a DB with sqlitebrowser
-I put the file created in the root folder in my project
-I'm loading the db like this:
let path = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true
).first as String
let db = Database("(path)/db.sqlite3")
personDb = db["person"]

-I'm trying to insert values like this:
if let insertID = personDb.insert(name <- personName.text, email <- "[email protected]", hourlySalaray <- 14.0, minWeekHours <- minHours.text.toInt()!, maxWeekHours <- maxHours.text.toInt()!, maxDailyHours <- maxDailyHours.text.toInt()!, isSupervisor <- isSupervisor.on) {

        println("Inserted: \(insertID)")

    }

But XCode continues telling me "Use of unresolved identifier X" about "name, email, hourlySalaray..." and all the fields that are in my DB and in my person table.

I'm using the latest version of XCode with all the Libraries loaded correctly following the steps mentioned in the instructions.

I would be more than happy to use this project if I can solve this issue.

Thank you very much!

Regards

performance issue iterating over a query

I'm having big performance issue iterating over a query, this is my code:

func getPdfWithCategory(language:Language) -> CategoriesForLanguage {
        let categoriesForLanguage = CategoriesForLanguage()

        let PDFs = pdfDb!.pdfsTb.table
        let categories = pdfDb!.categoriesTb.table
        start = NSDate()
        let query = PDFs.select(PDFs[*], categories[pdfDb!.categoriesTb.id], categories[pdfDb!.categoriesTb.name], categories[pdfDb!.categoriesTb.thumb], categories[pdfDb!.categoriesTb.orderid])
.join(categories, on: categories[pdfDb!.categoriesTb.id] == PDFs[pdfDb!.pdfsTb.categoryId])
.filter(PDFs[pdfDb!.pdfsTb.languageId] == language.id)

        let timeInterval:NSTimeInterval = start!.timeIntervalSinceNow
        println("query \(timeInterval)")

        println("query count = \(query.count)")

        start = NSDate()
        for row in query {

        }

        let timeInterval2:NSTimeInterval = start!.timeIntervalSinceNow
        println("for row in query \(timeInterval2)")
        return categoriesForLanguage
    }

and this is the print results:

query -0.0109010338783264
query count = 88
for row in query -2.39910697937012

I have even removed the join to see if it was that:

func getPdfWithCategory(language:Language) -> CategoriesForLanguage {
        let categoriesForLanguage = CategoriesForLanguage()

        let PDFs = pdfDb!.pdfsTb.table
        let categories = pdfDb!.categoriesTb.table
        start = NSDate()
        let query = PDFs.select(PDFs[*]).filter(PDFs[pdfDb!.pdfsTb.languageId] == language.id)

        let timeInterval:NSTimeInterval = start!.timeIntervalSinceNow
        println("query \(timeInterval)")

        println("query count = \(query.count)")

        start = NSDate()
        for row in query {

        }

        let timeInterval2:NSTimeInterval = start!.timeIntervalSinceNow
        println("for row in query \(timeInterval2)")
        return categoriesForLanguage
    }

it improved a little bit, but still too long:

query -0.00782698392868042
query count = 88
for row in query -1.40383696556091

P.S. I'm testing on a iPad

Add Copy Bundle Resouces Image to Documentation

Before this section:

Read-Only Databases

If you bundle a database with your app, you can establish a read-only connection to it.

Before you do this, you have to copy the db.sqlite into your Bundle Resources. I believe adding a quick snapshot in the documentation and telling new users this step will help.

screen shot 2015-01-18 at 2 05 59 pm

Exist sqlite file.

If I prepare a exist slite file and had some tables in the file. How can I use the file in xcode 6.
I means which folder i should put in xcode and how to build a read-write able db?

unable to open database file

when I try to use
let db=Database("path/to/db.sqlite3")

it pop a error said
fatal error: unable to open database file: file /Users/apple/Desktop/SQLite.swift/SQLite Common/Database.swift, line 336

Thanks for your help in advance

Adding functions to database

In my project I would like to add some custom sqlite function to my database supporting my queries (using: sqlite3_create_function(...)).
Is there currently any possibility to do that without changing SQLite's code?

Type 'UIImage?' does not conform to protocol 'Value'

Hi, I have a really simple database with a "MuscleGroup" table with 3 columns:

  • id: INTEGER
  • name: TEXT
  • image: BLOB

I'm trying to insert new row with this code :

let db = Database(pathToMyDB)
let muscleGroups = db["MuscleGroup"]

let id = Expression<Int>("id")
let name = Expression<String>("name")
let image = Expression<UIImage?>("image")

muscleGroups.insert(name <- "foo", image <- UIImage()) 

I get an error on the last line :

Type 'UIImage?' does not conform to protocol 'Value'

I'm stuck here because I extended NSData & UIImage so they conform to the 'Value' protocol :

extension NSData: Value {

    // SQL Type
    public class var declaredDatatype: String {
        return Blob.declaredDatatype
    }

    // Decode
    public class func fromDatatypeValue(datatypeValue: Blob) -> NSData {
        return NSData(bytes: datatypeValue.bytes, length: datatypeValue.length)
    }

    // Encode
    public var datatypeValue: Blob {
        return Blob(bytes: self.bytes, length: self.length)
    }
}

extension UIImage: Value {

    // SQL Type
    public class var declaredDatatype: String {
        return NSData.declaredDatatype
    }

    // Decode
    public class func fromDatatypeValue(datatypeValue: Blob) -> UIImage? {
        return UIImage(data: NSData.fromDatatypeValue(datatypeValue))
    }

    // Encode
    public var datatypeValue: Blob {
        return UIImagePNGRepresentation(self).datatypeValue
    }
}

Am I missing something ?

Insert : expression was too complex to be solved

Hey,

I am trying to use .insert() as follow :

        var revisionQ: Query?
        if let insertedID = revisionT.insert(element1 <- "0", element2<-"0", element3<-"0", element4<-"0", element5<-"0", element6<-"0", element7<-"0", element8<-"0", element9<-"0", element10<-"0")? {
            println("inserted id: \(insertedID)")
        }

Am I doing something wrong for having this error :

Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

When I remove the element10, the error just disappears. When the count is at 9 it is ok, but not 10 ... I don't get it.

Btw, in your example you forgot a parenthesis, at the end of println():

for user in users {
    println("id: \(user[id]), name: \(user[name]), email: \(user[email])"
    // id: 1, name: Optional("Alice"), email: [email protected]
}

Thanks

compiler error: Could not find member 'update'

I got a weird compiler error for the class below

class PDSsTb {

    let id = Expression<String>("id")
    let categoryId = Expression<Int>("categoryId")
    let languageId = Expression<String>("languageId")
    let name = Expression<String>("name")
    let thumb = Expression<Blob?>("thumb")
    let modificationDate = Expression<String>("modificationDate")
    let isCurrent = Expression<Int>("isCurrent")
    let isLocal = Expression<Int>("isLocal")
    let needsUpdate = Expression<Int>("needsUpdate")
    let progress = Expression<Double>("progress")

    let table:SQLite.Query

    init(db:Database){

        table = db["pdf"]
    }

    func updatePdfStatusOnDb(brochure:Brochure) {
        let brochureToUpdate = table.filter(id == brochure.pdfId).update(isLocal <- brochure.isLocal, needsUpdate <- brochure.needsUpdate)
    }

    func deleteLocalBrochure(brochure:Brochure) {
        let fileToDelete = table.filter(id == brochure.pdfId).update(isLocal <- brochure.isLocal, needsUpdate <- brochure.needsUpdate)
    }
}

the compiler says:

Could not find member 'update'

for both functions.

Using dictionary instead o array to iterate over a Arbitrary SQL query result

Right now we have:

let stmt = db.prepare("SELECT id, email FROM users")
for row in stmt {
    println("id: \(row[0]), email: \(row[1])")
    // id: Optional(1), email: Optional("[email protected]")
}

this means we need to know the order of db columns. Which is not easy especially if you have a join query.
Also since iterating a query with typed API is much slower, depending on the complexity of the structure, it would be easier to have key/value access when using manual SQL statements.

Is there a reason why we can't use it like this:

let stmt = db.prepare("SELECT id, email FROM users")
for row in stmt {
    println("id: \(row["id"]), email: \(row["email"])")
}

Dates

In your documentation, you suggest the following NSDateFormatter:

let SQLDateFormatter: NSDateFormatter = {
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    formatter.timeZone = NSTimeZone(abbreviation: "UTC")
    return formatter
}()

I'd make a few suggestions:

  • I'd suggest you also set the locale of the NSDateFormatter to NSLocale(localeIdentifier: "en_US_POSIX") in order to ensure that you don't have problems with users/developers using non-Gregorian calendars. See Technical Q&A 1480.

  • I'd also suggest including the time zone in the string. If you want to handle it like NSLog, you could write it with nice human readable +0000. Or if you want to conform to ISO8601/RFC3339 standards, you'd put a T between the date and the time and append a Z at the end to designate that it's "Zulu".

    Personally, I'd also have the default behavior to include milliseconds (SSS in the format string, too), and perhaps adopt the ISO 8601 style, e.g. yyyy-MM-dd'T'HH:mm:ss.SSS'Z').

  • It's up to you, but rather than proper date handling being a comment in the documentation, and leaving it to the developer to implement it correctly (and, as evidenced by Stack Overflow, most of them won't), I might suggest incorporating it right into the class, so that, by default, the app developer has a good solid handling of NSDate parameters. Maybe make the NSDateFormatter property that the library uses a read/write property that the developer can override with whatever they want. But default it to some well-established best practice, perhaps something like what we've outlined above.

Expression fails when Field Contains a Number

After numerous testing, I believe that Query fails when Column heading contains a Number:

Here is my repo: If anyone can shed some light, I would appreciate it:
https://github.com/ericcgu/RWEGSeed/blob/NumericalColumnNames/Seed/RWEGFrequencyByLocationTableViewController.swift

    //Success
    let firstValue = Expression<String>("ON")

    //Failure
    let firstValue = Expression<String>("ON_1950")

    //Failure
    let secondValue = Expression<String>("19500301_OFF")
    let thirdValue = Expression<String>("19500301_TOTAL")

As a workaround, I tried using a literal to avoid expressions but this did not work:

 //Success
 var query = "SELECT * FROM STOCKS_CORN_LOCATION"
    let statement = db.prepare(query)
    while ((statement.next()) != nil){
      let row = statement.columnNames
      println(row)
    }

 //Failure
 var query = "SELECT 2011301_ON FROM STOCKS_CORN_LOCATION"
    let statement = db.prepare(query)
    while ((statement.next()) != nil){
      let row = statement.columnNames
      println(row)
    }

Swift compile error

It works fine when run, but when profile it cannot pass compilation with this (maybe a swift bug):

  1. While emitting IR SIL function @TF6SQLiteoi1pFTGVS_10ExpressionSS_SS_GS0_SS for '+' at /Users/PeiSong/VCube/gate-ios-swift/source/Gate-Swift/SQLite.swift/SQLite Common/Expression.swift:116:8

Can't use it with Mac.app

Hi,

I tried your SQlite3 wrapper but was unable to get it to work with an Mac / Cocoa application. It would only work if the app was an iOS app to begin with. Could you tell what I am doing wrong? I added the framework just as depicted in your documentation.
Regards Thomas
bildschirmfoto 2015-01-17 um 17 06 53

Support for CocoaPods

Now that the current pre release version of CocoaPods supports Swift Frameworks I would like to ask if you could provide a podspec for Sqlite.swift.

What do you think about this idea?

SQLCipher

Can I use SQLCipher with SQLite.swift?

Bulk Inserts

I am trying to insert 10k rows of small records, but running into slow runtime issues.

I came across this link in SO: http://stackoverflow.com/a/9497342/975129 which might be a viable solution.

I think the gist of the code (translated for my personal case) is this:

let stmt = db.prepare( "INSERT INTO cardannotation (cid,show_me_on) VALUES (?,?)" )
for r in not_in_db { stmt.run( r.id, d ) }

Please correct me if I'm off...

However, I'm having trouble wrapping this in an exclusive transaction.

EDIT: ok, I think I need to use bind instead of run, but I haven't quite figured out how to pass an array of these through the variadic parameters in db.transaction( ... )

EDIT: getting closer

let stmt = db.prepare( "INSERT INTO cardannotation (cid,show_me_on) VALUES (?,?)" )
let a    = not_in_db.map() { stmt.bind( $0.id, d ) }
db.transaction( Database.TransactionMode.Exclusive, a )  // compile failure here

How to Use NSDate

let question_date = Expression("question_date")
let chapter_id = Expression("chapter_id")
var filteredDB = dbQuestions.filter(chapter_id == incomeChapter.chapter_id)
if let searchText = searchTxt {
filteredDB = filteredDB.filter(like("%" + searchText + "%",question_content))
}
var filteredQuestion:[question]
for q in filteredDB {
let fuc = question()
fuc.question_content = q[question_content]
fuc.question_date = q[question_date] <================ ISSUE
}

class question
{
var question_content : String = ""
var question_date : NSDate = NSDate()

}

How to use db.prepare

for row in db.prepare("SELECT * FROM users") {
println("id: (row["id"]), email: (row["email"])")
}
not work

What about AUTOINCREMENT for integer keys??

One feature I rely on is the AUTOINCREMENT feature, and I can't find any support for that in the documentation. Is it there? I hate to have to create my table definition uses SQL strings just for that.

Attach and detach

Reading the documentation for this project I thought, "This is what Swift should be." I think it merits attach and detach methods (returning Bool or NSError). Some of the quirks to consider...

Working with FMDB, db.executeUpdate("ATTACH ? AS ?", withArgumentsInArray: [attachFilepath, attachAs]) is always returning true in my environment, perhaps everywhere. To determine success, I have to verify that the attached database is actually listed in the database_list pragma:

// Verify that the database is listed in the database_list pragma.
// http://www.sqlite.org/pragma.html#pragma_database_list
if let r = db.executeQuery("pragma database_list", withArgumentsInArray: []) {
    while r.next() {
        if let dbName = r.stringForColumnIndex(1) {
            if dbName == attachAs {
                return true
            }
        }
    }
}
return false

But even this wasn't sufficient. A zero-byte or corrupt database file could be attached, and would be listed in the database_list pragma, so I then test whether a query can be made against the expected tables:

/// Returns whether a query over the given table and columns may produce results.
func testQuery(#table: String, columns: [String]? = nil) -> Bool {
    let cols = (columns == nil) ? "*" : ",".join(columns!)
    let query = "SELECT \(cols) FROM \(table) LIMIT 1"
    // Result set will be nil if the query is invalid.
    return self.executeQuery(query, withArgumentsInArray: []) != nil
}

There may be a better way to determine the success of attach. If someone decides to implement attach and detach, I hope these notes will be useful. 👍

Is INTEGER PRIMARY KEY AUTOINCREMENT supported?

Hello,

I'm trying to implement INTEGER PRIMARY KEY AUTOINCREMENT. But I do not find where to add AUTOINCREMENT keyword. Perhaps it is already supported but I failed to locate it:)

The reason to use the keyword:
http://www.sqlite.org/autoinc.html

The behavior implemented by the AUTOINCREMENT keyword is subtly different from the default behavior. With AUTOINCREMENT, rows with automatically selected ROWIDs are guaranteed to have ROWIDs that have never been used before by the same table in the same database.

Thanks in advance,

Liwei

Getting `[Byte]` out of `Blob`

In order to serialize protobufs using protobuf-sqlite I need to provide it with a [Byte] array. The only way I'm aware of constructing this from an UnsafePointer is via an NSData object:

let col = row[self.data]
var bytes = [Byte](count: col.length, repeatedValue: 0)
col.data.getBytes(&bytes)

With Blob.data private I am unable to do this. I guess my question is a) is there another way to get a [Byte] from the Blob or b) could Blob.data be public?

include module on ios project

i use this project in my project, is error:

Undefined symbols for architecture arm64:
"__TMaC6SQlite8Database", referenced from:
_globalinit_func1 in Record.o
"_TIFC6SQlite8DatabasecFMS0_FTGSqSS_8readonlySb_S0_A0", referenced from:
_globalinit_func1 in Record.o
"_TFC6SQlite8DatabaseCfMS0_FTGSqSS_8readonlySb_S0", referenced from:
_globalinit_func1 in Record.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

import Foundation
import SQlite

let path = NSSearchPathForDirectoriesInDomains(
    .DocumentDirectory, .UserDomainMask, true
).first as String

let db =  Database("\(path)/db.sqlite3")

Bridging header issue

Hello,
Is it possible if you could add on the installation guide a simple how-to setup the bridging header?
Having this error:
unknown>:0: error: bridging header '/Users/user/app/myapp/SQLite.swift-master/SQLite Common/SQLite-Bridging-Header.h' does not exist

Thank you

More convenient transaction support

Hi,

The transaction support is not that convenient IMO. It forces pre-generation of statements with no opportunity for logic inside the transaction.

That is, AFAICT, you can not perform a select inside the transaction then conditionally issue other statements based on the result. Or in fact, issue any kind of conditional statements.

It also makes decomposition of many statements into separate functions more difficult, forcing all functions to return Statements.

eg. I can not do this:

db.transaction({
   if let user: In = users.filter(age >= 18).first {
    if user.location == location {
      // update some other table
    }
  } else {
    // do some other update
  }
})

Is there any reason a more convenient form of transaction couldn't be supported?

insert driving nuts!

Hi,

I'm trying to use SQLite.swift (iOS version) but I got stuck with the following insert statement.
XCode keeps telling me:
"Could not find an overload for 'insert' that accepts the supplied arguments"

let userDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
let name = "test.sqlite3"
let db = Database(path)
let package: Query = db["package"]
let id: Expression = Expression("id")
db.create(table: package, ifNotExists: true) { table in
table.column(id)
}
package.insert(id <- 0) ERROR HERE!

I can't see what I'm doing wrong!

[Question] Adding UIImage as Blob

I'm trying out the project but I am getting tied up on using Blobs. I have a UIImage (png) but when trying to insert a row using it I am getting "Type Blob? does not conform to protocol Value" error. I cannot see how it is not being conformed to after drawing upon your documentation.

let uuid = Expression<Int>("uuid")
let png = Expression<Blob?>("png")

if let insertedID = ingredientTable.insert(uuid <- createUUID() ,png <- pic?.datatypeValue) {
        println("inserted id: \(insertedID)")
}

I've used the following extensions from your documentation ...

extension NSData: Value {
    public class var declaredDatatype: String {
        return Blob.declaredDatatype
    }
    public class func fromDatatypeValue(blobValue: Blob) -> Self {
        return self(bytes: blobValue.bytes, length: blobValue.length)
    }
    public var datatypeValue: Blob {
        return Blob(bytes: bytes, length: length)
    }
}

extension UIImage: Value {
    public class var declaredDatatype: String {
        return NSData.declaredDatatype
    }
    public class func fromDatatypeValue(blobValue: Blob) -> Self {
        return self(data: NSData.fromDatatypeValue(blobValue))!
    }
    public var datatypeValue: Blob {
        return UIImagePNGRepresentation(self).datatypeValue
    }
}

location of the db that is secure

Hello,

I'm trying to learn using SQLite on my app directly without core data. Do you guys know where to put the db? I know from the documentation here that I can create a db in Documents directory. However, is it safe enough to do so? I googled for a while and it seems files in this location can be accessed by 3rd party. Is this location safe enough to store the data? Any advice regarding my security concern?

Thanks in advance,

Liwei

error when import Framework

Hi,

i have problem when import SQLite.swift framework in to my project.
i did exactly step by step in guide, and it work on simulator i can create DB and select data.
but when i run on device it throw error:
dyld: Library not loaded: @rpath/SQLite.framework/SQLite
Referenced from: /private/var/mobile/Containers/Bundle/Application/375E16EF-D210-42E9-8D11-2D004F629354/ViHaT.FrameWork.app/ViHaT.FrameWork
Reason: image not found

I guess it's because framework didn't copied when build debug mode in device.
but still can not fix it.

Can you help me this case :)

Many thanks for useful framework !.

32 bit platform overflow and crash with Int64 value

I found if I save Int64 integer value in sqlite INTEGER, it will crash while retrieve the value on iPhone5 or other 32bit iPhone, will you support BIG_INT or what opinion you have on this issue?

Although you use sqlite3_column_int64 to get value, but Int depends on platform, even if the value is Int64 on iPhone5, Int still 32bit and will overflow

case SQLITE_INTEGER:
            let int = Int(sqlite3_column_int64(handle, Int32(idx)))
            var bool = false
            if let type = String.fromCString(sqlite3_column_decltype(handle, Int32(idx))) {
                bool = type.hasPrefix("BOOL")
            }
            row.append(bool ? int != 0 : int)

Table names not properly quoted

I wanted to create a table called "table", but it seems that SQLite.swift does not correctly quote the word, resulting in a syntax error.

Unable to open database file when deployed on device

let db = Database("path/to/db.sqlite3")

I used my local mac path here and working fine with simulator. But when i deploy the app to device, it is giving me error.

fatal error: unable to open database file:

Database ifExists argument not recognized.

I'm trying to run the following code:

    let db : Database = getDb()
    let onegram = db["onegram"]
    db.drop(table: onegram, ifExists: true) 

but Xcode throws a compiler error:
Incorrect argument labels in call (have 'table:ifExists:', expected 'index:on:')

Foreign Key Constraints are disabled

When trying to set a foreign key for a column an assertion fails with the message:
assertion failed: foreign key constraints are disabled

Are they disabled by default? If yes, how can I enable them?
Thank you for this lib. It is awesome btw ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.