├── docs ├── docsets │ ├── .tgz │ └── .docset │ │ └── Contents │ │ ├── Resources │ │ ├── docSet.dsidx │ │ └── Documents │ │ │ ├── undocumented.json │ │ │ ├── img │ │ │ ├── dash.png │ │ │ ├── gh.png │ │ │ └── carat.png │ │ │ ├── js │ │ │ └── jazzy.js │ │ │ ├── index.html │ │ │ ├── Enums.html │ │ │ ├── Enums │ │ │ └── SQLiteError.html │ │ │ ├── css │ │ │ ├── highlight.css │ │ │ └── jazzy.css │ │ │ ├── Classes.html │ │ │ └── Classes │ │ │ └── SQLite.html │ │ └── Info.plist ├── img │ ├── dash.png │ ├── gh.png │ └── carat.png ├── undocumented.json ├── js │ └── jazzy.js ├── index.html ├── Enums.html ├── Enums │ └── SQLiteError.html ├── css │ ├── highlight.css │ └── jazzy.css ├── Classes.html └── Classes │ └── SQLite.html ├── Tests ├── LinuxMain.swift └── PerfectSQLiteTests │ └── XCTestManifests.swift ├── .jazzy.yaml ├── Package.swift ├── .gitignore ├── README.md ├── LICENSE └── Sources └── PerfectSQLite ├── SQLiteCRUD.swift └── SQLite.swift /docs/docsets/.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/docsets/.tgz -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/img/carat.png -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | {"warnings":[],"source_directory":"/Users/taplin/Documents/PerfectProjects/Perfect-SQLite/Xcode/Perfect-SQLite"} -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import PerfectSQLiteTests 3 | 4 | XCTMain([ 5 | testCase(PerfectSQLiteTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/docsets/.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | {"warnings":[],"source_directory":"/Users/taplin/Documents/PerfectProjects/Perfect-SQLite/Xcode/Perfect-SQLite"} -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/docsets/.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/docsets/.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerfectlySoft/Perfect-SQLite/HEAD/docs/docsets/.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | module: PerfectSQLite 2 | author: PerfectlySoft 3 | author_url: https://perfect.org 4 | github_url: https://github.com/PerfectlySoft/Perfect-SQLite 5 | copyright: '© 2016 PerfectlySoft Inc. and the Perfect project authors' 6 | theme: fullwidth 7 | xcodebuild_arguments: [-target, SQLite, -toolchain, org.swift.3020160620a] 8 | clean: true 9 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy. 7 | CFBundleName 8 | 9 | DocSetPlatformFamily 10 | jazzy 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/PerfectSQLiteTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCTestManifests.swift 3 | // 4 | // Created by Kyle Jessup on 2015-10-19. 5 | // Copyright © 2015 PerfectlySoft. All rights reserved. 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This source file is part of the Perfect.org open source project 10 | // 11 | // Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors 12 | // Licensed under Apache License v2.0 13 | // 14 | // See http://perfect.org/licensing.html for license information 15 | // 16 | //===----------------------------------------------------------------------===// 17 | // 18 | 19 | import XCTest 20 | 21 | #if !os(OSX) 22 | public func allTests() -> [XCTestCaseEntry] { 23 | return [ 24 | testCase(PerfectSQLiteTests.allTests) 25 | ] 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // Generated automatically by Perfect Assistant 3 | // Date: 2018-12-25 02:23:42 +0000 4 | import PackageDescription 5 | 6 | #if os(Linux) 7 | let package = Package( 8 | name: "PerfectSQLite", 9 | products: [ 10 | .library(name: "PerfectSQLite", targets: ["PerfectSQLite"]) 11 | ], 12 | dependencies: [ 13 | .package(url: "https://github.com/PerfectlySoft/Perfect-CRUD.git", from: "2.0.0"), 14 | .package(url: "https://github.com/PerfectlySoft/Perfect-sqlite3-support.git", from: "3.0.0"), 15 | ], 16 | targets: [ 17 | .target(name: "PerfectSQLite", dependencies: ["PerfectCRUD"]), 18 | .testTarget(name: "PerfectSQLiteTests", dependencies: ["PerfectSQLite"]) 19 | ] 20 | ) 21 | #else 22 | let package = Package( 23 | name: "PerfectSQLite", 24 | platforms: [ 25 | .macOS(.v10_15) 26 | ], 27 | products: [ 28 | .library(name: "PerfectSQLite", targets: ["PerfectSQLite"]) 29 | ], 30 | dependencies: [ 31 | .package(url: "https://github.com/PerfectlySoft/Perfect-CRUD.git", from: "2.0.0") 32 | ], 33 | targets: [ 34 | .target(name: "PerfectSQLite", dependencies: ["PerfectCRUD"]), 35 | .testTarget(name: "PerfectSQLiteTests", dependencies: ["PerfectSQLite"]) 36 | ] 37 | ) 38 | #endif 39 | -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | 65 | Packages/ 66 | SQLite.xcodeproj/ 67 | .DS_Store 68 | .build_lin/ 69 | .packages_lin/ 70 | PADockerfile_build 71 | PADockerfile_deploy 72 | Package.pins 73 | Package.resolved 74 | buildlinux 75 | *.xcodeproj/ 76 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 | 54 |

Authors

55 | 56 |
57 |
58 | 62 |
63 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 | 54 |

Authors

55 | 56 |
57 |
58 | 62 |
63 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enums Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 |

Enums

54 |

The following enums are available globally.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | SQLiteError 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    This enum type indicates an exception when dealing with a SQLite database

    74 | 75 | See more 76 |
    77 |
    78 |

    Declaration

    79 |
    80 |

    Swift

    81 |
    public enum SQLiteError : ErrorProtocol
    82 | 83 |
    84 |
    85 |
    86 |
    87 |
  • 88 |
89 |
90 |
91 |
92 | 96 |
97 |
98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enums Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 |

Enums

54 |

The following enums are available globally.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | SQLiteError 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    This enum type indicates an exception when dealing with a SQLite database

    74 | 75 | See more 76 |
    77 |
    78 |

    Declaration

    79 |
    80 |

    Swift

    81 |
    public enum SQLiteError : ErrorProtocol
    82 | 83 |
    84 |
    85 |
    86 |
    87 |
  • 88 |
89 |
90 |
91 |
92 | 96 |
97 |
98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/Enums/SQLiteError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SQLiteError Enum Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 51 |
52 |
53 |
54 |

SQLiteError

55 |
56 |
57 |
public enum SQLiteError : ErrorProtocol
58 | 59 |
60 |
61 |

This enum type indicates an exception when dealing with a SQLite database

62 | 63 |
64 |
65 |
66 |
    67 |
  • 68 |
    69 | 70 | 71 | 72 | Error 73 | 74 |
    75 |
    76 |
    77 |
    78 |
    79 |
    80 |

    A SQLite error code and message.

    81 | 82 |
    83 |
    84 |

    Declaration

    85 |
    86 |

    Swift

    87 |
    case Error(code: Int, msg: String)
    88 | 89 |
    90 |
    91 |
    92 |
    93 |
  • 94 |
95 |
96 |
97 |
98 | 102 |
103 |
104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/Enums/SQLiteError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SQLiteError Enum Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 51 |
52 |
53 |
54 |

SQLiteError

55 |
56 |
57 |
public enum SQLiteError : ErrorProtocol
58 | 59 |
60 |
61 |

This enum type indicates an exception when dealing with a SQLite database

62 | 63 |
64 |
65 |
66 |
    67 |
  • 68 |
    69 | 70 | 71 | 72 | Error 73 | 74 |
    75 |
    76 |
    77 |
    78 |
    79 |
    80 |

    A SQLite error code and message.

    81 | 82 |
    83 |
    84 |

    Declaration

    85 |
    86 |

    Swift

    87 |
    case Error(code: Int, msg: String)
    88 | 89 |
    90 |
    91 |
    92 |
    93 |
  • 94 |
95 |
96 |
97 |
98 | 102 |
103 |
104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 |

Classes

54 |

The following classes are available globally.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | SQLite 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    A SQLite database

    74 | 75 | See more 76 |
    77 |
    78 |

    Declaration

    79 |
    80 |

    Swift

    81 |
    public class SQLite
    82 | 83 |
    84 |
    85 |
    86 |
    87 |
  • 88 |
  • 89 |
    90 | 91 | 92 | 93 | SQLiteStmt 94 | 95 |
    96 |
    97 |
    98 |
    99 |
    100 |
    101 |

    A compiled SQLite statement

    102 | 103 | See more 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public class SQLiteStmt
    110 | 111 |
    112 |
    113 |
    114 |
    115 |
  • 116 |
117 |
118 |
119 |
120 | 124 |
125 |
126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 50 |
51 |
52 |
53 |

Classes

54 |

The following classes are available globally.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | SQLite 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    A SQLite database

    74 | 75 | See more 76 |
    77 |
    78 |

    Declaration

    79 |
    80 |

    Swift

    81 |
    public class SQLite
    82 | 83 |
    84 |
    85 |
    86 |
    87 |
  • 88 |
  • 89 |
    90 | 91 | 92 | 93 | SQLiteStmt 94 | 95 |
    96 |
    97 |
    98 |
    99 |
    100 |
    101 |

    A compiled SQLite statement

    102 | 103 | See more 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public class SQLiteStmt
    110 | 111 |
    112 |
    113 |
    114 |
    115 |
  • 116 |
117 |
118 |
119 |
120 | 124 |
125 |
126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perfect - SQLite Connector 2 | 3 | 4 |

5 | 6 | Get Involed with Perfect! 7 | 8 |

9 | 10 |

11 | 12 | Star Perfect On Github 13 | 14 | 15 | Stack Overflow 16 | 17 | 18 | Follow Perfect on Twitter 19 | 20 | 21 | Join the Perfect Slack 22 | 23 |

24 | 25 |

26 | 27 | Swift 4.0 28 | 29 | 30 | Platforms OS X | Linux 31 | 32 | 33 | License Apache 34 | 35 | 36 | PerfectlySoft Twitter 37 | 38 | 39 | Slack Status 40 | 41 |

42 | 43 | This project provides a Swift wrapper around the SQLite 3 library. 44 | 45 | This package builds with Swift Package Manager and is part of the [Perfect](https://github.com/PerfectlySoft/Perfect) project. It was written to be stand-alone and so does not require PerfectLib or any other components. 46 | 47 | Ensure you have installed and activated the latest Swift 4.0 tool chain. 48 | 49 | To learn more, you can read the full documentation guide [here](https://github.com/PerfectlySoft/PerfectDocs/blob/master/guide/SQLite.md) or jump to the example [here](#Usage-Example) 50 | 51 | 52 | ## Linux Build Notes 53 | 54 | Ensure that you have installed sqlite3. 55 | 56 | ``` 57 | sudo apt-get install sqlite3 58 | ``` 59 | 60 | ## Building 61 | 62 | Add this project as a dependency in your Package.swift file. 63 | 64 | ``` 65 | .Package(url: "https://github.com/PerfectlySoft/Perfect-SQLite.git", majorVersion: 3) 66 | ``` 67 | 68 | ### Edge Case 69 | If you encounter error like such ``` sqlite3.h file not found ``` during ```$ swift build ```, one solution is to install the sqlite3-dev i.e. ```$ sudo apt-get install libsqlite3-dev``` 70 | 71 | 72 | ## Usage Example 73 | 74 | Let’s assume you’d like to host a blog in Swift. First we need tables. Assuming you’ve created an SQLite file `./db/database`, we simply need to connect and add the tables. 75 | 76 | ```swift 77 | let dbPath = "./db/database" 78 | 79 | do { 80 | let sqlite = try SQLite(dbPath) 81 | defer { 82 | sqlite.close() 83 | } 84 | 85 | try sqlite.execute(statement: "CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY NOT NULL, post_title TEXT NOT NULL, post_content TEXT NOT NULL, featured_image_uri TEXT NOT NULL)") 86 | } catch { 87 | print("Failure creating database tables") //Handle Errors 88 | } 89 | ``` 90 | 91 | Next, we would need to add some content. 92 | 93 | ```swift 94 | let dbPath = "./db/database" 95 | let postTitle = "Test Title" 96 | let postContent = "Lorem ipsum dolor sit amet…" 97 | 98 | do { 99 | let sqlite = try SQLite(dbPath) 100 | defer { 101 | sqlite.close() 102 | } 103 | 104 | try sqlite.execute(statement: "INSERT INTO posts (post_title, post_content) VALUES (:1,:2)") { 105 | (stmt:SQLiteStmt) -> () in 106 | 107 | try stmt.bind(position: 1, postTitle) 108 | try stmt.bind(position: 2, postContent) 109 | } 110 | } catch { 111 | //Handle Errors 112 | } 113 | ``` 114 | 115 | Finally, we retrieve posts and post titles from an SQLite database full of blog content. Each id, post, and title is appended to a dictionary for use elsewhere. 116 | 117 | ``` swift 118 | let dbPath = "./db/database" 119 | var contentDict = [String: Any]() 120 | 121 | do { 122 | let sqlite = try SQLite(dbPath) 123 | defer { 124 | sqlite.close() // This makes sure we close our connection. 125 | } 126 | 127 | let demoStatement = "SELECT post_title, post_content FROM posts ORDER BY id DESC LIMIT :1" 128 | 129 | try sqlite.forEachRow(statement: demoStatement, doBindings: { 130 | 131 | (statement: SQLiteStmt) -> () in 132 | 133 | let bindValue = 5 134 | try statement.bind(position: 1, bindValue) 135 | 136 | }) {(statement: SQLiteStmt, i:Int) -> () in 137 | 138 | self.contentDict.append([ 139 | "id": statement.columnText(position: 0), 140 | "second_field": statement.columnText(position: 1), 141 | "third_field": statement.columnText(position: 2) 142 | ]) 143 | } 144 | 145 | } catch { 146 | //Handle Errors 147 | } 148 | ``` 149 | 150 | ## Further Information 151 | For more information on the Perfect project, please visit [perfect.org](http://www.perfect.org/docs/SQLite.html). 152 | -------------------------------------------------------------------------------- /docs/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | 168 | .section { 169 | padding: 0 25px; } 170 | 171 | .highlight { 172 | background-color: #eee; 173 | padding: 10px 12px; 174 | border: 1px solid #e2e2e2; 175 | border-radius: 4px; 176 | overflow-x: auto; } 177 | 178 | .declaration .highlight { 179 | overflow-x: initial; 180 | padding: 0 40px 40px 0; 181 | margin-bottom: -25px; 182 | background-color: transparent; 183 | border: none; } 184 | 185 | .section-name { 186 | margin: 0; 187 | margin-left: 18px; } 188 | 189 | .task-group-section { 190 | padding-left: 6px; 191 | border-top: 1px solid #e2e2e2; } 192 | 193 | .task-group { 194 | padding-top: 0px; } 195 | 196 | .task-name-container a[name]:before { 197 | content: ""; 198 | display: block; 199 | padding-top: 70px; 200 | margin: -70px 0 0; } 201 | 202 | .item { 203 | padding-top: 8px; 204 | width: 100%; 205 | list-style-type: none; } 206 | .item a[name]:before { 207 | content: ""; 208 | display: block; 209 | padding-top: 70px; 210 | margin: -70px 0 0; } 211 | .item code { 212 | background-color: transparent; 213 | padding: 0; } 214 | .item .token { 215 | padding-left: 3px; 216 | margin-left: 15px; 217 | font-size: 11.9px; } 218 | .item .declaration-note { 219 | font-size: .85em; 220 | color: gray; 221 | font-style: italic; } 222 | 223 | .pointer-container { 224 | border-bottom: 1px solid #e2e2e2; 225 | left: -23px; 226 | padding-bottom: 13px; 227 | position: relative; 228 | width: 110%; } 229 | 230 | .pointer { 231 | background: #f9f9f9; 232 | border-left: 1px solid #e2e2e2; 233 | border-top: 1px solid #e2e2e2; 234 | height: 12px; 235 | left: 21px; 236 | top: -7px; 237 | -webkit-transform: rotate(45deg); 238 | -moz-transform: rotate(45deg); 239 | -o-transform: rotate(45deg); 240 | transform: rotate(45deg); 241 | position: absolute; 242 | width: 12px; } 243 | 244 | .height-container { 245 | display: none; 246 | left: -25px; 247 | padding: 0 25px; 248 | position: relative; 249 | width: 100%; 250 | overflow: hidden; } 251 | .height-container .section { 252 | background: #f9f9f9; 253 | border-bottom: 1px solid #e2e2e2; 254 | left: -25px; 255 | position: relative; 256 | width: 100%; 257 | padding-top: 10px; 258 | padding-bottom: 5px; } 259 | 260 | .aside, .language { 261 | padding: 6px 12px; 262 | margin: 12px 0; 263 | border-left: 5px solid #dddddd; 264 | overflow-y: hidden; } 265 | .aside .aside-title, .language .aside-title { 266 | font-size: 9px; 267 | letter-spacing: 2px; 268 | text-transform: uppercase; 269 | padding-bottom: 0; 270 | margin: 0; 271 | color: #aaa; 272 | -webkit-user-select: none; } 273 | .aside p:last-child, .language p:last-child { 274 | margin-bottom: 0; } 275 | 276 | .language { 277 | border-left: 5px solid #cde9f4; } 278 | .language .aside-title { 279 | color: #4b8afb; } 280 | 281 | .aside-warning { 282 | border-left: 5px solid #ff6666; } 283 | .aside-warning .aside-title { 284 | color: #ff0000; } 285 | 286 | .graybox { 287 | border-collapse: collapse; 288 | width: 100%; } 289 | .graybox p { 290 | margin: 0; 291 | word-break: break-word; 292 | min-width: 50px; } 293 | .graybox td { 294 | border: 1px solid #e2e2e2; 295 | padding: 5px 25px 5px 10px; 296 | vertical-align: middle; } 297 | .graybox tr td:first-of-type { 298 | text-align: right; 299 | padding: 7px; 300 | vertical-align: top; 301 | word-break: normal; 302 | width: 40px; } 303 | 304 | .slightly-smaller { 305 | font-size: 0.9em; } 306 | 307 | #footer { 308 | position: absolute; 309 | bottom: 10px; 310 | margin-left: 25px; } 311 | #footer p { 312 | margin: 0; 313 | color: #aaa; 314 | font-size: 0.8em; } 315 | 316 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 317 | display: none; } 318 | html.dash .main-content { 319 | width: 980px; 320 | margin-left: 0; 321 | border: none; 322 | width: 100%; 323 | top: 0; 324 | padding-bottom: 0; } 325 | html.dash .height-container { 326 | display: block; } 327 | html.dash .item .token { 328 | margin-left: 0; } 329 | html.dash .content-wrapper { 330 | width: auto; } 331 | html.dash #footer { 332 | position: static; } 333 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | 168 | .section { 169 | padding: 0 25px; } 170 | 171 | .highlight { 172 | background-color: #eee; 173 | padding: 10px 12px; 174 | border: 1px solid #e2e2e2; 175 | border-radius: 4px; 176 | overflow-x: auto; } 177 | 178 | .declaration .highlight { 179 | overflow-x: initial; 180 | padding: 0 40px 40px 0; 181 | margin-bottom: -25px; 182 | background-color: transparent; 183 | border: none; } 184 | 185 | .section-name { 186 | margin: 0; 187 | margin-left: 18px; } 188 | 189 | .task-group-section { 190 | padding-left: 6px; 191 | border-top: 1px solid #e2e2e2; } 192 | 193 | .task-group { 194 | padding-top: 0px; } 195 | 196 | .task-name-container a[name]:before { 197 | content: ""; 198 | display: block; 199 | padding-top: 70px; 200 | margin: -70px 0 0; } 201 | 202 | .item { 203 | padding-top: 8px; 204 | width: 100%; 205 | list-style-type: none; } 206 | .item a[name]:before { 207 | content: ""; 208 | display: block; 209 | padding-top: 70px; 210 | margin: -70px 0 0; } 211 | .item code { 212 | background-color: transparent; 213 | padding: 0; } 214 | .item .token { 215 | padding-left: 3px; 216 | margin-left: 15px; 217 | font-size: 11.9px; } 218 | .item .declaration-note { 219 | font-size: .85em; 220 | color: gray; 221 | font-style: italic; } 222 | 223 | .pointer-container { 224 | border-bottom: 1px solid #e2e2e2; 225 | left: -23px; 226 | padding-bottom: 13px; 227 | position: relative; 228 | width: 110%; } 229 | 230 | .pointer { 231 | background: #f9f9f9; 232 | border-left: 1px solid #e2e2e2; 233 | border-top: 1px solid #e2e2e2; 234 | height: 12px; 235 | left: 21px; 236 | top: -7px; 237 | -webkit-transform: rotate(45deg); 238 | -moz-transform: rotate(45deg); 239 | -o-transform: rotate(45deg); 240 | transform: rotate(45deg); 241 | position: absolute; 242 | width: 12px; } 243 | 244 | .height-container { 245 | display: none; 246 | left: -25px; 247 | padding: 0 25px; 248 | position: relative; 249 | width: 100%; 250 | overflow: hidden; } 251 | .height-container .section { 252 | background: #f9f9f9; 253 | border-bottom: 1px solid #e2e2e2; 254 | left: -25px; 255 | position: relative; 256 | width: 100%; 257 | padding-top: 10px; 258 | padding-bottom: 5px; } 259 | 260 | .aside, .language { 261 | padding: 6px 12px; 262 | margin: 12px 0; 263 | border-left: 5px solid #dddddd; 264 | overflow-y: hidden; } 265 | .aside .aside-title, .language .aside-title { 266 | font-size: 9px; 267 | letter-spacing: 2px; 268 | text-transform: uppercase; 269 | padding-bottom: 0; 270 | margin: 0; 271 | color: #aaa; 272 | -webkit-user-select: none; } 273 | .aside p:last-child, .language p:last-child { 274 | margin-bottom: 0; } 275 | 276 | .language { 277 | border-left: 5px solid #cde9f4; } 278 | .language .aside-title { 279 | color: #4b8afb; } 280 | 281 | .aside-warning { 282 | border-left: 5px solid #ff6666; } 283 | .aside-warning .aside-title { 284 | color: #ff0000; } 285 | 286 | .graybox { 287 | border-collapse: collapse; 288 | width: 100%; } 289 | .graybox p { 290 | margin: 0; 291 | word-break: break-word; 292 | min-width: 50px; } 293 | .graybox td { 294 | border: 1px solid #e2e2e2; 295 | padding: 5px 25px 5px 10px; 296 | vertical-align: middle; } 297 | .graybox tr td:first-of-type { 298 | text-align: right; 299 | padding: 7px; 300 | vertical-align: top; 301 | word-break: normal; 302 | width: 40px; } 303 | 304 | .slightly-smaller { 305 | font-size: 0.9em; } 306 | 307 | #footer { 308 | position: absolute; 309 | bottom: 10px; 310 | margin-left: 25px; } 311 | #footer p { 312 | margin: 0; 313 | color: #aaa; 314 | font-size: 0.8em; } 315 | 316 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 317 | display: none; } 318 | html.dash .main-content { 319 | width: 980px; 320 | margin-left: 0; 321 | border: none; 322 | width: 100%; 323 | top: 0; 324 | padding-bottom: 0; } 325 | html.dash .height-container { 326 | display: block; } 327 | html.dash .item .token { 328 | margin-left: 0; } 329 | html.dash .content-wrapper { 330 | width: auto; } 331 | html.dash #footer { 332 | position: static; } 333 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Sources/PerfectSQLite/SQLiteCRUD.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SQLiteCRUD.swift 3 | // 4 | // Created by Kyle Jessup on 2017-11-28. 5 | // 6 | 7 | import Foundation 8 | import PerfectCRUD 9 | // Apple platforms have SQLite3 built-in. Linux? No. 10 | #if os(Linux) 11 | import PerfectCSQLite3 12 | #else 13 | import SQLite3 14 | #endif 15 | 16 | public struct SQLiteCRUDError: Error, CustomStringConvertible { 17 | public let description: String 18 | init(_ m: String) { 19 | description = m 20 | CRUDLogging.log(.error, m) 21 | } 22 | } 23 | 24 | // maps column name to position which must be computed once before row reading action 25 | typealias SQLiteCRUDColumnMap = [String:Int] 26 | 27 | class SQLiteCRUDRowReader: KeyedDecodingContainerProtocol { 28 | typealias Key = K 29 | var codingPath: [CodingKey] = [] 30 | var allKeys: [Key] = [] 31 | let database: SQLite 32 | let statement: SQLiteStmt 33 | let columns: SQLiteCRUDColumnMap 34 | // the SQLiteStmt has been successfully step()ed to the next row 35 | init(_ db: SQLite, stat: SQLiteStmt, columns cols: SQLiteCRUDColumnMap) { 36 | database = db 37 | statement = stat 38 | columns = cols 39 | } 40 | func columnPosition(_ key: Key) throws -> Int { 41 | guard let pos = columns[key.stringValue] else { 42 | throw CRUDDecoderError("Unrecognized key: \(key.stringValue)") 43 | } 44 | return pos 45 | } 46 | func contains(_ key: Key) -> Bool { 47 | return nil != columns[key.stringValue] 48 | } 49 | func decodeNil(forKey key: Key) throws -> Bool { 50 | return statement.isNull(position: try columnPosition(key)) 51 | } 52 | func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { 53 | return statement.columnInt(position: try columnPosition(key)) == 1 54 | } 55 | func decode(_ type: Int.Type, forKey key: Key) throws -> Int { 56 | return statement.columnInt(position: try columnPosition(key)) 57 | } 58 | func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { 59 | return type.init(statement.columnInt(position: try columnPosition(key))) 60 | } 61 | func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { 62 | return type.init(statement.columnInt(position: try columnPosition(key))) 63 | } 64 | func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { 65 | return statement.columnInt32(position: try columnPosition(key)) 66 | } 67 | func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { 68 | return statement.columnInt64(position: try columnPosition(key)) 69 | } 70 | func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { 71 | return type.init(statement.columnInt(position: try columnPosition(key))) 72 | } 73 | func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { 74 | return type.init(statement.columnInt(position: try columnPosition(key))) 75 | } 76 | func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { 77 | return type.init(statement.columnInt(position: try columnPosition(key))) 78 | } 79 | func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { 80 | return type.init(statement.columnInt(position: try columnPosition(key))) 81 | } 82 | func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { 83 | return type.init(statement.columnInt(position: try columnPosition(key))) 84 | } 85 | func decode(_ type: Float.Type, forKey key: Key) throws -> Float { 86 | return type.init(statement.columnDouble(position: try columnPosition(key))) 87 | } 88 | func decode(_ type: Double.Type, forKey key: Key) throws -> Double { 89 | return statement.columnDouble(position: try columnPosition(key)) 90 | } 91 | func decode(_ type: String.Type, forKey key: Key) throws -> String { 92 | return statement.columnText(position: try columnPosition(key)) 93 | } 94 | func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { 95 | let position = try columnPosition(key) 96 | guard let special = SpecialType(type) else { 97 | throw CRUDDecoderError("Unsupported type: \(type) for key: \(key.stringValue)") 98 | } 99 | switch special { 100 | case .uint8Array: 101 | let ret: [UInt8] = statement.columnIntBlob(position: position) 102 | return ret as! T 103 | case .int8Array: 104 | let ret: [Int8] = statement.columnIntBlob(position: position) 105 | return ret as! T 106 | case .data: 107 | let bytes: [UInt8] = statement.columnIntBlob(position: position) 108 | return Data(bytes) as! T 109 | case .uuid: 110 | let str = statement.columnText(position: position) 111 | guard let uuid = UUID(uuidString: str) else { 112 | throw CRUDDecoderError("Invalid UUID string \(str).") 113 | } 114 | return uuid as! T 115 | case .date: 116 | let str = statement.columnText(position: position) 117 | guard let date = Date(fromISO8601: str) else { 118 | throw CRUDDecoderError("Invalid Date string \(str).") 119 | } 120 | return date as! T 121 | case .url: 122 | let str = statement.columnText(position: position) 123 | guard let url = URL(string: str) else { 124 | throw CRUDDecoderError("Invalid URL string \(str).") 125 | } 126 | return url as! T 127 | case .codable: 128 | guard let data = statement.columnText(position: position).data(using: .utf8) else { 129 | throw CRUDDecoderError("Unsupported type: \(type) for key: \(key.stringValue)") 130 | } 131 | return try JSONDecoder().decode(type, from: data) 132 | case .wrapped: 133 | let decoder = CRUDColumnValueDecoder(source: KeyedDecodingContainer(self), key: key) 134 | return try T(from: decoder) 135 | } 136 | } 137 | func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { 138 | throw CRUDDecoderError("Unimplimented nestedContainer") 139 | } 140 | func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { 141 | throw CRUDDecoderError("Unimplimented nestedUnkeyedContainer") 142 | } 143 | func superDecoder() throws -> Decoder { 144 | throw CRUDDecoderError("Unimplimented superDecoder") 145 | } 146 | func superDecoder(forKey key: Key) throws -> Decoder { 147 | throw CRUDDecoderError("Unimplimented superDecoder") 148 | } 149 | } 150 | 151 | struct SQLiteColumnInfo: Codable { 152 | let cid: Int 153 | let name: String 154 | let type: String 155 | let notnull: Int 156 | let dflt_value: String 157 | let pk: Bool 158 | } 159 | 160 | class SQLiteGenDelegate: SQLGenDelegate { 161 | let database: SQLite 162 | var parentTableStack: [TableStructure] = [] 163 | var bindings: Bindings = [] 164 | var extraCreate: [String] = [] 165 | 166 | init(_ db: SQLite) { 167 | database = db 168 | } 169 | 170 | func getCreateIndexSQL(forTable name: String, on columns: [String], unique: Bool) throws -> [String] { 171 | let stat = 172 | """ 173 | CREATE \(unique ? "UNIQUE " : "")INDEX IF NOT EXISTS \(try quote(identifier: "index_\(columns.joined(separator: "_"))")) 174 | ON \(try quote(identifier: name)) (\(try columns.map{try quote(identifier: $0)}.joined(separator: ","))) 175 | """ 176 | return [stat] 177 | } 178 | 179 | func getCreateTableSQL(forTable: TableStructure, policy: TableCreatePolicy) throws -> [String] { 180 | parentTableStack.append(forTable) 181 | defer { 182 | parentTableStack.removeLast() 183 | } 184 | var sub: [String] = [] 185 | if policy.contains(.dropTable) { 186 | sub += ["DROP TABLE IF EXISTS \(try quote(identifier: forTable.tableName))"] 187 | } 188 | if !policy.contains(.dropTable), 189 | policy.contains(.reconcileTable), 190 | let existingColumns = getExistingColumnData(forTable: forTable.tableName), 191 | !existingColumns.isEmpty { 192 | let existingColumnMap: [String:SQLiteColumnInfo] = .init(uniqueKeysWithValues: existingColumns.map { ($0.name, $0) }) 193 | let newColumnMap: [String:TableStructure.Column] = .init(uniqueKeysWithValues: forTable.columns.map { ($0.name, $0) }) 194 | 195 | let addColumns = newColumnMap.keys.filter { existingColumnMap[$0] == nil } 196 | let removeColumns: [String] = existingColumnMap.keys.filter { newColumnMap[$0] == nil } 197 | 198 | if !removeColumns.isEmpty { 199 | let nameQ = try quote(identifier: forTable.tableName) 200 | let tempNameQ = try quote(identifier: "temp_\(forTable.tableName)_temp") 201 | let sharedColumns = existingColumns.map { $0.name }.filter { !removeColumns.contains($0) } 202 | sub += [ // sqlite does not have 'drop column' 203 | "ALTER TABLE \(nameQ) RENAME TO \(tempNameQ)", 204 | """ 205 | CREATE TABLE IF NOT EXISTS \(nameQ) ( 206 | \(try forTable.columns.map { try getColumnDefinition($0) }.joined(separator: ",\n\t")) 207 | ) 208 | """, 209 | """ 210 | INSERT INTO \(nameQ) (\(sharedColumns.joined(separator: ","))) 211 | SELECT \(sharedColumns.joined(separator: ",")) 212 | FROM \(tempNameQ) 213 | """, 214 | "DROP TABLE \(tempNameQ)" 215 | ] 216 | } else { 217 | sub += try addColumns.compactMap { newColumnMap[$0] }.map { 218 | let nameType = try getColumnDefinition($0) 219 | return """ 220 | ALTER TABLE \(try quote(identifier: forTable.tableName)) ADD COLUMN \(nameType) 221 | """ 222 | } 223 | } 224 | return sub 225 | } else { 226 | sub += [ 227 | """ 228 | CREATE TABLE IF NOT EXISTS \(try quote(identifier: forTable.tableName)) ( 229 | \((try forTable.columns.map { try getColumnDefinition($0) } + extraCreate).joined(separator: ",\n\t")) 230 | ) 231 | """] 232 | } 233 | if !policy.contains(.shallow) { 234 | sub += try forTable.subTables.flatMap { 235 | try getCreateTableSQL(forTable: $0, policy: policy) 236 | } 237 | } 238 | return sub 239 | } 240 | 241 | func getExistingColumnData(forTable: String) -> [SQLiteColumnInfo]? { 242 | do { 243 | let prep = try database.prepare(statement: "PRAGMA table_info(\"\(forTable)\")") 244 | let exeDelegate = SQLiteExeDelegate(database, stat: prep) 245 | var ret: [SQLiteColumnInfo] = [] 246 | while try exeDelegate.hasNext() { 247 | let rowDecoder = CRUDRowDecoder(delegate: exeDelegate) 248 | ret.append(try SQLiteColumnInfo(from: rowDecoder)) 249 | } 250 | return ret 251 | } catch { 252 | return nil 253 | } 254 | } 255 | private func getTypeName(_ type: Any.Type) throws -> String { 256 | let typeName: String 257 | switch type { 258 | case is Int.Type: 259 | typeName = "INT" 260 | case is Int8.Type: 261 | typeName = "INT" 262 | case is Int16.Type: 263 | typeName = "INT" 264 | case is Int32.Type: 265 | typeName = "INT" 266 | case is Int64.Type: 267 | typeName = "INT" 268 | case is UInt.Type: 269 | typeName = "INT" 270 | case is UInt8.Type: 271 | typeName = "INT" 272 | case is UInt16.Type: 273 | typeName = "INT" 274 | case is UInt32.Type: 275 | typeName = "INT" 276 | case is UInt64.Type: 277 | typeName = "INT" 278 | case is Double.Type: 279 | typeName = "REAL" 280 | case is Float.Type: 281 | typeName = "REAL" 282 | case is Bool.Type: 283 | typeName = "INT" 284 | case is String.Type: 285 | typeName = "TEXT" 286 | default: 287 | guard let special = SpecialType(type) else { 288 | throw SQLiteCRUDError("Unsupported SQL column type \(type)") 289 | } 290 | switch special { 291 | case .uint8Array: 292 | typeName = "BLOB" 293 | case .int8Array: 294 | typeName = "BLOB" 295 | case .data: 296 | typeName = "BLOB" 297 | case .uuid: 298 | typeName = "TEXT" 299 | case .date: 300 | typeName = "TEXT" 301 | case .url: 302 | typeName = "TEXT" 303 | case .codable: 304 | typeName = "TEXT" 305 | case .wrapped: 306 | guard let w = type as? WrappedCodableProvider.Type else { 307 | throw SQLiteCRUDError("Unsupported SQL column type \(type)") 308 | } 309 | return try getTypeName(w) 310 | } 311 | } 312 | return typeName 313 | } 314 | func getColumnDefinition(_ column: TableStructure.Column) throws -> String { 315 | let name = column.name 316 | let type = column.type 317 | let typeName = try getTypeName(type) 318 | var addendum = "" 319 | for prop in column.properties { 320 | switch prop { 321 | case .primaryKey: 322 | addendum += " PRIMARY KEY" 323 | case .foreignKey(let table, let column, let onDelete, let onUpdate): 324 | var str = "FOREIGN KEY(\(name)) REFERENCES \(table)(\(column))" 325 | let scenarios = [(" ON DELETE ", onDelete), (" ON UPDATE ", onUpdate)] 326 | for (scenario, action) in scenarios { 327 | str += scenario 328 | switch action { 329 | case .ignore: 330 | str += "NO ACTION" 331 | case .restrict: 332 | str += "RESTRICT" 333 | case .setNull: 334 | str += "SET NULL" 335 | case .setDefault: 336 | str += "SET DEFAULT" 337 | case .cascade: 338 | str += "CASCADE" 339 | } 340 | } 341 | extraCreate.append(str) 342 | } 343 | } 344 | if !column.properties.contains(.primaryKey) && !column.optional { 345 | addendum += " NOT NULL" 346 | } 347 | return "\(name) \(typeName)\(addendum)" 348 | } 349 | func getBinding(for expr: Expression) throws -> String { 350 | bindings.append(("?", expr)) 351 | return "?" 352 | } 353 | func quote(identifier: String) throws -> String { 354 | return "\"\(identifier)\"" 355 | } 356 | } 357 | 358 | // maps column name to position which must be computed once before row reading action 359 | typealias SQLiteColumnMap = [String:Int] 360 | 361 | class SQLiteExeDelegate: SQLExeDelegate { 362 | let database: SQLite 363 | let statement: SQLiteStmt 364 | let columnMap: SQLiteColumnMap 365 | init(_ db: SQLite, stat: SQLiteStmt) { 366 | database = db 367 | statement = stat 368 | var m = SQLiteColumnMap() 369 | let count = statement.columnCount() 370 | for i in 0.. Bool { 386 | let step = statement.step() 387 | guard step == SQLITE_ROW || step == SQLITE_DONE else { 388 | throw SQLiteCRUDError(database.errMsg()) 389 | } 390 | return step == SQLITE_ROW 391 | } 392 | func next() -> KeyedDecodingContainer? where A : CodingKey { 393 | return KeyedDecodingContainer(SQLiteCRUDRowReader(database, stat: statement, columns: columnMap)) 394 | } 395 | private func bindOne(position: Int, expr: CRUDExpression) throws { 396 | switch expr { 397 | case .lazy(let e): 398 | try bindOne(position: position, expr: e()) 399 | case .decimal(let d): 400 | try statement.bind(position: position, d) 401 | case .string(let s): 402 | try statement.bind(position: position, s) 403 | case .blob(let b): 404 | try statement.bind(position: position, b) 405 | case .bool(let b): 406 | try statement.bind(position: position, b ? 1 : 0) 407 | case .null: 408 | try statement.bindNull(position: position) 409 | case .date(let d): 410 | try statement.bind(position: position, d.iso8601()) 411 | case .url(let u): 412 | try statement.bind(position: position, u.absoluteString) 413 | case .uuid(let u): 414 | try statement.bind(position: position, u.uuidString) 415 | case .column(_), .and(_, _), .or(_, _), 416 | .equality(_, _), .inequality(_, _), 417 | .not(_), .lessThan(_, _), .lessThanEqual(_, _), 418 | .greaterThan(_, _), .greaterThanEqual(_, _), 419 | .keyPath(_), .in(_, _), .like(_, _, _, _): 420 | throw SQLiteCRUDError("Asked to bind unsupported expression type: \(expr)") 421 | case .integer(let i): 422 | try statement.bind(position: position, i) 423 | case .uinteger(let i): 424 | try statement.bind(position: position, Int(i)) 425 | case .integer64(let i): 426 | try statement.bind(position: position, Int(i)) 427 | case .uinteger64(let i): 428 | try statement.bind(position: position, Int(i)) 429 | case .integer32(let i): 430 | try statement.bind(position: position, Int(i)) 431 | case .uinteger32(let i): 432 | try statement.bind(position: position, Int(i)) 433 | case .integer16(let i): 434 | try statement.bind(position: position, Int(i)) 435 | case .uinteger16(let i): 436 | try statement.bind(position: position, Int(i)) 437 | case .integer8(let i): 438 | try statement.bind(position: position, Int(i)) 439 | case .uinteger8(let i): 440 | try statement.bind(position: position, Int(i)) 441 | case .float(let d): 442 | try statement.bind(position: position, Double(d)) 443 | case .sblob(let b): 444 | try statement.bind(position: position, b.map{UInt8(bitPattern: $0)}) 445 | } 446 | } 447 | } 448 | 449 | public struct SQLiteDatabaseConfiguration: DatabaseConfigurationProtocol { 450 | public var sqlGenDelegate: SQLGenDelegate { 451 | return SQLiteGenDelegate(sqlite) 452 | } 453 | public func sqlExeDelegate(forSQL sql: String) throws -> SQLExeDelegate { 454 | let prep = try sqlite.prepare(statement: sql) 455 | return SQLiteExeDelegate(sqlite, stat: prep) 456 | } 457 | public let name: String 458 | public let sqlite: SQLite 459 | public init(_ n: String, _ pragmas: [String] = ["PRAGMA foreign_keys = ON"]) throws { 460 | name = n 461 | sqlite = try SQLite(n) 462 | for pragma in pragmas { 463 | try sqlite.execute(statement: pragma) 464 | } 465 | } 466 | public init(url: String?, 467 | name: String?, 468 | host: String?, 469 | port: Int?, 470 | user: String?, 471 | pass: String?) throws { 472 | guard let n = name else { 473 | throw SQLiteCRUDError("Database name must be provided.") 474 | } 475 | try self.init(n) 476 | } 477 | } 478 | 479 | public extension Insert { 480 | func lastInsertId() throws -> Int? { 481 | let exeDelegate = try databaseConfiguration.sqlExeDelegate(forSQL: "SELECT last_insert_rowid()") 482 | guard try exeDelegate.hasNext(), let next: KeyedDecodingContainer = try exeDelegate.next() else { 483 | throw CRUDSQLGenError("Did not get return value from statement \"SELECT last_insert_rowid()\".") 484 | } 485 | let value = try next.decode(Int.self, forKey: ColumnKey(stringValue: "last_insert_rowid()")!) 486 | return value 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /Sources/PerfectSQLite/SQLite.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SQLite.swift 3 | // PerfectLib 4 | // 5 | // Created by Kyle Jessup on 7/14/15. 6 | // Copyright (C) 2015 PerfectlySoft, Inc. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This source file is part of the Perfect.org open source project 11 | // 12 | // Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors 13 | // Licensed under Apache License v2.0 14 | // 15 | // See http://perfect.org/licensing.html for license information 16 | // 17 | //===----------------------------------------------------------------------===// 18 | // 19 | 20 | // Apple platforms have SQLite3 built-in. Linux? No. 21 | #if os(Linux) 22 | import PerfectCSQLite3 23 | import SwiftGlibc 24 | #else 25 | import SQLite3 26 | #endif 27 | 28 | /// This enum type indicates an exception when dealing with a SQLite database 29 | public struct SQLiteError : Error, CustomStringConvertible { 30 | public let code: Int 31 | public let description: String 32 | public init(code: Int, description: String) { 33 | self.code = code 34 | self.description = description 35 | } 36 | } 37 | 38 | /// A SQLite database 39 | public class SQLite { 40 | 41 | let path: String 42 | var sqlite3 = OpaquePointer(bitPattern: 0) 43 | 44 | /// Create or open a SQLite database given a file path. 45 | /// 46 | /// - parameter path: String path to SQLite database 47 | /// - parameter readOnly: Optional, Bool flag for read/write setting, defaults to false 48 | /// - throws: SQLiteError 49 | public init(_ path: String, readOnly: Bool = false, busyTimeoutMillis: Int = 600000) throws { 50 | self.path = path 51 | let flags = readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE 52 | let res = sqlite3_open_v2(path, &self.sqlite3, flags, nil) 53 | if res != SQLITE_OK { 54 | throw SQLiteError(code: Int(res), description: "Unable to open database "+path) 55 | } 56 | sqlite3_busy_timeout(self.sqlite3, Int32(busyTimeoutMillis)) 57 | } 58 | 59 | /// Close the SQLite database. 60 | public func close() { 61 | if self.sqlite3 != nil { 62 | sqlite3_close(self.sqlite3) 63 | self.sqlite3 = nil 64 | } 65 | } 66 | 67 | /// Close the SQLite database. 68 | public func close(after: (SQLite) -> T) -> T { 69 | defer { 70 | close() 71 | } 72 | return after(self) 73 | } 74 | 75 | deinit { 76 | close() 77 | } 78 | 79 | /// Compile the SQL statement. 80 | /// 81 | /// - returns: A SQLiteStmt object representing the compiled statement. 82 | public func prepare(statement stat: String) throws -> SQLiteStmt { 83 | var statPtr = OpaquePointer(bitPattern: 0) 84 | let tail = UnsafeMutablePointer?>(nil as OpaquePointer?) 85 | let res = sqlite3_prepare_v2(self.sqlite3, stat, Int32(stat.utf8.count), &statPtr, tail) 86 | try checkRes(res) 87 | return SQLiteStmt(db: self.sqlite3, stat: statPtr) 88 | } 89 | 90 | /// Returns the value of `sqlite3_last_insert_rowid`. 91 | /// 92 | /// - returns: Int last inserted row ID 93 | public func lastInsertRowID() -> Int { 94 | let res = sqlite3_last_insert_rowid(self.sqlite3) 95 | return Int(res) 96 | } 97 | 98 | /// Returns the value of `sqlite3_total_changes`. 99 | /// 100 | /// - returns: Int total changes 101 | public func totalChanges() -> Int { 102 | let res = sqlite3_total_changes(self.sqlite3) 103 | return Int(res) 104 | } 105 | 106 | /// Returns the value of `sqlite3_changes`. 107 | /// 108 | /// - returns: Int number of changes 109 | public func changes() -> Int { 110 | let res = sqlite3_changes(self.sqlite3) 111 | return Int(res) 112 | } 113 | 114 | /// Returns the value of `sqlite3_errcode`. 115 | /// 116 | /// - returns: Int error code 117 | public func errCode() -> Int { 118 | let res = sqlite3_errcode(self.sqlite3) 119 | return Int(res) 120 | } 121 | 122 | /// Returns the value of `sqlite3_errmsg`. 123 | /// 124 | /// - returns: String error message 125 | public func errMsg() -> String { 126 | return String(validatingUTF8: sqlite3_errmsg(self.sqlite3))! 127 | } 128 | 129 | /// Execute the given statement. Assumes there will be no parameter binding or resulting row data. 130 | /// 131 | /// - parameter statement: String statement to be executed 132 | /// - throws: () 133 | public func execute(statement: String) throws { 134 | try forEachRow(statement: statement, doBindings: { (SQLiteStmt) throws -> () in () }) { 135 | _, _ in 136 | // nothing 137 | } 138 | } 139 | 140 | /// Execute the given statement. Calls the provided callback one time for parameter binding. Assumes there will be no resulting row data. 141 | /// 142 | /// - parameter statement: String statement to be executed 143 | /// - parameter doBindings: Block used for bindings 144 | /// - throws: () 145 | public func execute(statement: String, doBindings: (SQLiteStmt) throws -> ()) throws { 146 | try forEachRow(statement: statement, doBindings: doBindings) { 147 | _, _ in 148 | // nothing 149 | } 150 | } 151 | 152 | /// Execute the given statement `count` times. Calls the provided callback on each execution for parameter binding. Assumes there will be no resulting row data. 153 | /// 154 | /// - parameter statement: String statement to be executed 155 | /// - parameter count: Int number of times to execute 156 | /// - parameter doBindings: Block to be executed for binding on each call 157 | /// - throws: () 158 | public func execute(statement: String, count: Int, doBindings: (SQLiteStmt, Int) throws -> ()) throws { 159 | let stat = try prepare(statement: statement) 160 | defer { stat.finalize() } 161 | 162 | for idx in 1...count { 163 | try doBindings(stat, idx) 164 | try forEachRowBody(stat: stat) { 165 | _, _ in 166 | // nothing 167 | } 168 | let _ = try stat.reset() 169 | } 170 | } 171 | 172 | /// Executes a BEGIN, calls the provided closure and executes a ROLLBACK if an exception occurs or a COMMIT if no exception occurs. 173 | /// 174 | /// - parameter closure: Block to be executed inside transaction 175 | /// - throws: ErrorType 176 | public func doWithTransaction(closure: () throws -> ()) throws { 177 | try execute(statement: "BEGIN") 178 | do { 179 | try closure() 180 | try execute(statement: "COMMIT") 181 | } catch let e { 182 | try execute(statement: "ROLLBACK") 183 | throw e 184 | } 185 | } 186 | 187 | /// Executes the statement and calls the closure for each resulting row. 188 | /// 189 | /// - parameter statement: String statement to be executed 190 | /// - parameter handleRow: Block to be executed for each row 191 | /// - throws: () 192 | public func forEachRow(statement: String, handleRow: (SQLiteStmt, Int) throws -> ()) throws { 193 | let stat = try prepare(statement: statement) 194 | defer { stat.finalize() } 195 | 196 | try forEachRowBody(stat: stat, handleRow: handleRow) 197 | } 198 | 199 | /// Executes the statement, calling `doBindings` to handle parameter bindings and calling `handleRow` for each resulting row. 200 | /// 201 | /// - parameter statement: String statement to be executed 202 | /// - parameter doBindings: Block to perform bindings on statement 203 | /// - parameter handleRow: Block to execute for each row 204 | /// - throws: () 205 | public func forEachRow(statement: String, doBindings: (SQLiteStmt) throws -> (), handleRow: (SQLiteStmt, Int) throws -> ()) throws { 206 | let stat = try prepare(statement: statement) 207 | defer { stat.finalize() } 208 | 209 | try doBindings(stat) 210 | 211 | try forEachRowBody(stat: stat, handleRow: handleRow) 212 | } 213 | 214 | func forEachRowBody(stat: SQLiteStmt, handleRow: (SQLiteStmt, Int) throws -> ()) throws { 215 | var r = stat.step() 216 | guard r == SQLITE_ROW || r == SQLITE_DONE else { 217 | try checkRes(r) 218 | return 219 | } 220 | 221 | var rowNum = 1 222 | while r == SQLITE_ROW { 223 | try handleRow(stat, rowNum) 224 | rowNum += 1 225 | r = stat.step() 226 | } 227 | } 228 | 229 | func miniSleep(millis: Int) { 230 | var tv = timeval() 231 | tv.tv_sec = millis / 1000 232 | #if os(Linux) 233 | tv.tv_usec = Int((millis % 1000) * 1000) 234 | #else 235 | tv.tv_usec = Int32((millis % 1000) * 1000) 236 | #endif 237 | select(0, nil, nil, nil, &tv) 238 | } 239 | 240 | func checkRes(_ res: Int32) throws { 241 | try checkRes(Int(res)) 242 | } 243 | 244 | func checkRes(_ res: Int) throws { 245 | if res != Int(SQLITE_OK) { 246 | throw SQLiteError(code: res, description: String(validatingUTF8: sqlite3_errmsg(self.sqlite3))!) 247 | } 248 | } 249 | } 250 | 251 | /// A compiled SQLite statement 252 | public class SQLiteStmt { 253 | 254 | let db: OpaquePointer? 255 | var stat: OpaquePointer? 256 | 257 | typealias sqlite_destructor = @convention(c) (UnsafeMutableRawPointer?) -> Void 258 | 259 | init(db: OpaquePointer?, stat: OpaquePointer?) { 260 | self.db = db 261 | self.stat = stat 262 | } 263 | 264 | /// Close or "finalize" the statement. 265 | public func close() { 266 | finalize() 267 | } 268 | 269 | /// Close the statement. 270 | public func finalize() { 271 | if self.stat != nil { 272 | sqlite3_finalize(self.stat!) 273 | self.stat = nil 274 | } 275 | } 276 | 277 | /// Advance to the next row. 278 | public func step() -> Int32 { 279 | guard self.stat != nil else { 280 | return SQLITE_MISUSE 281 | } 282 | return sqlite3_step(self.stat!) 283 | } 284 | 285 | /// Bind the Double value to the indicated parameter. 286 | /// 287 | /// - parameter position: Int position of binding 288 | /// - parameter d: Double to be bound 289 | /// - throws: () 290 | public func bind(position: Int, _ d: Double) throws { 291 | try checkRes(sqlite3_bind_double(self.stat!, Int32(position), d)) 292 | } 293 | 294 | /// Bind the Int32 value to the indicated parameter. 295 | /// 296 | /// - parameter position: Int position of binding 297 | /// - parameter i: Int32 to be bound 298 | /// - throws: () 299 | public func bind(position: Int, _ i: Int32) throws { 300 | try checkRes(sqlite3_bind_int(self.stat!, Int32(position), Int32(i))) 301 | } 302 | 303 | /// Bind the Int value to the indicated parameter. 304 | /// 305 | /// - parameter position: Int position of binding 306 | /// - parameter i: Int to be bound 307 | /// - throws: () 308 | public func bind(position: Int, _ i: Int) throws { 309 | try checkRes(sqlite3_bind_int64(self.stat!, Int32(position), Int64(i))) 310 | } 311 | 312 | /// Bind the Int64 value to the indicated parameter. 313 | /// 314 | /// - parameter position: Int position of binding 315 | /// - parameter i: Int64 to be bound 316 | /// - throws: () 317 | public func bind(position: Int, _ i: Int64) throws { 318 | try checkRes(sqlite3_bind_int64(self.stat!, Int32(position), i)) 319 | } 320 | 321 | /// Bind the String value to the indicated parameter. 322 | /// 323 | /// - parameter position: Int position of binding 324 | /// - parameter s: String to be bound 325 | /// - throws: () 326 | public func bind(position: Int, _ s: String) throws { 327 | try checkRes(sqlite3_bind_text(self.stat!, Int32(position), s, Int32(s.utf8.count), unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite_destructor.self))) 328 | } 329 | 330 | /// Bind the [Int8] blob value to the indicated parameter. 331 | /// 332 | /// - parameter position: Int position of binding 333 | /// - parameter b: [Int8] blob to be bound 334 | /// - throws: () 335 | public func bind(position: Int, _ b: [Int8]) throws { 336 | try checkRes(sqlite3_bind_blob(self.stat!, Int32(position), b, Int32(b.count), unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite_destructor.self))) 337 | } 338 | 339 | /// Bind the [UInt8] blob value to the indicated parameter. 340 | /// 341 | /// - parameter position: Int position of binding 342 | /// - parameter b: [UInt8] blob to be bound 343 | /// - throws: () 344 | public func bind(position: Int, _ b: [UInt8]) throws { 345 | try checkRes(sqlite3_bind_blob(self.stat!, Int32(position), b, Int32(b.count), unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite_destructor.self))) 346 | } 347 | 348 | /// Bind a blob of `count` zero values to the indicated parameter. 349 | /// 350 | /// - parameter position: Int position of binding 351 | /// - parameter count: Int number of zero values in blob to be bound 352 | /// - throws: () 353 | public func bindZeroBlob(position: Int, count: Int) throws { 354 | try checkRes(sqlite3_bind_zeroblob(self.stat!, Int32(position), Int32(count))) 355 | } 356 | 357 | /// Bind a null to the indicated parameter. 358 | /// 359 | /// - parameter position: Int position of binding 360 | /// - throws: () 361 | public func bindNull(position: Int) throws { 362 | try checkRes(sqlite3_bind_null(self.stat!, Int32(position))) 363 | } 364 | 365 | /// Bind the Double value to the indicated parameter. 366 | /// 367 | /// - parameter name: String name of binding 368 | /// - parameter d: Double to be bound 369 | /// - throws: () 370 | public func bind(name: String, _ d: Double) throws { 371 | try checkRes(sqlite3_bind_double(self.stat!, Int32(bindParameterIndex(name: name)), d)) 372 | } 373 | 374 | /// Bind the Int32 value to the indicated parameter. 375 | /// 376 | /// - parameter name: String name of binding 377 | /// - parameter i: Int32 to be bound 378 | /// - throws: () 379 | public func bind(name: String, _ i: Int32) throws { 380 | try checkRes(sqlite3_bind_int(self.stat!, Int32(bindParameterIndex(name: name)), Int32(i))) 381 | } 382 | 383 | /// Bind the Int value to the indicated parameter. 384 | /// 385 | /// - parameter name: String name of binding 386 | /// - parameter i: Int to be bound 387 | /// - throws: () 388 | public func bind(name: String, _ i: Int) throws { 389 | try checkRes(sqlite3_bind_int64(self.stat!, Int32(bindParameterIndex(name: name)), Int64(i))) 390 | } 391 | 392 | /// Bind the Int64 value to the indicated parameter. 393 | /// 394 | /// - parameter name: String name of binding 395 | /// - parameter i: Int64 to be bound 396 | /// - throws: () 397 | public func bind(name: String, _ i: Int64) throws { 398 | try checkRes(sqlite3_bind_int64(self.stat!, Int32(bindParameterIndex(name: name)), i)) 399 | } 400 | 401 | /// Bind the String value to the indicated parameter. 402 | /// 403 | /// - parameter name: String name of binding 404 | /// - parameter s: String to be bound 405 | /// - throws: () 406 | public func bind(name: String, _ s: String) throws { 407 | try checkRes(sqlite3_bind_text(self.stat!, Int32(bindParameterIndex(name: name)), s, Int32(s.utf8.count), unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite_destructor.self))) 408 | } 409 | 410 | /// Bind the [Int8] blob value to the indicated parameter. 411 | /// 412 | /// - parameter name: String name of binding 413 | /// - parameter b: [Int8] blob to be bound 414 | /// - throws: () 415 | public func bind(name: String, _ b: [Int8]) throws { 416 | try checkRes(sqlite3_bind_text(self.stat!, Int32(bindParameterIndex(name: name)), b, Int32(b.count), unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite_destructor.self))) 417 | } 418 | 419 | /// Bind a blob of `count` zero values to the indicated parameter. 420 | /// 421 | /// - parameter name: String name of binding 422 | /// - parameter count: Int number of zero values in blob to be bound 423 | /// - throws: () 424 | public func bindZeroBlob(name: String, count: Int) throws { 425 | try checkRes(sqlite3_bind_zeroblob(self.stat!, Int32(bindParameterIndex(name: name)), Int32(count))) 426 | } 427 | 428 | /// Bind a null to the indicated parameter. 429 | /// 430 | /// - parameter name: String name of binding 431 | /// - throws: () 432 | public func bindNull(name: String) throws { 433 | try checkRes(sqlite3_bind_null(self.stat!, Int32(bindParameterIndex(name: name)))) 434 | } 435 | 436 | /// Returns the index for the named parameter. 437 | /// 438 | /// - parameter name: String name of binding 439 | /// - throws: () 440 | /// - returns: Int index of parameter 441 | public func bindParameterIndex(name: String) throws -> Int { 442 | let idx = sqlite3_bind_parameter_index(self.stat!, name) 443 | guard idx != 0 else { 444 | throw SQLiteError(code: Int(SQLITE_MISUSE), description: "The indicated bind parameter name was not found.") 445 | } 446 | return Int(idx) 447 | } 448 | 449 | /// Resets the SQL statement. 450 | /// 451 | /// - returns: Int result 452 | public func reset() throws -> Int { 453 | let res = sqlite3_reset(self.stat!) 454 | try checkRes(res) 455 | return Int(res) 456 | } 457 | 458 | /// Return the number of columns in mthe result set. 459 | /// 460 | /// - returns: Int count of columns in result set 461 | public func columnCount() -> Int { 462 | let res = sqlite3_column_count(self.stat!) 463 | return Int(res) 464 | } 465 | 466 | /// Returns the name for the indicated column. 467 | /// 468 | /// - parameter position: Int position of column 469 | /// - returns: String name of column 470 | public func columnName(position: Int) -> String { 471 | return String(validatingUTF8: sqlite3_column_name(self.stat!, Int32(position)))! 472 | } 473 | 474 | /// Returns the name of the declared type for the indicated column. 475 | /// 476 | /// - parameter position: Int position of column 477 | /// - returns: String name of declared type 478 | public func columnDeclType(position: Int) -> String { 479 | return String(validatingUTF8: sqlite3_column_decltype(self.stat!, Int32(position)))! 480 | } 481 | 482 | /// Returns the blob data for the indicated column. 483 | /// 484 | /// - parameter position: Int position of column 485 | /// - returns: [Int8] blob 486 | @available(*, deprecated, renamed:"columnIntBlob") 487 | public func columnBlob(position: Int) -> [Int8] { 488 | return columnIntBlob(position: position) 489 | } 490 | 491 | /// Returns the blob data for the indicated column. 492 | /// 493 | /// - parameter position: Int position of column 494 | /// - returns: [I: BinaryInteger] blob 495 | public func columnIntBlob(position: Int) -> [I] { 496 | let vp = sqlite3_column_blob(self.stat!, Int32(position)) 497 | let vpLen = Int(sqlite3_column_bytes(self.stat!, Int32(position))) 498 | 499 | guard vpLen > 0 else { 500 | return [] 501 | } 502 | 503 | var ret = [I]() 504 | if var bytesPtr = vp?.bindMemory(to: I.self, capacity: vpLen) { 505 | for _ in 0.. Double { 518 | return Double(sqlite3_column_double(self.stat!, Int32(position))) 519 | } 520 | 521 | /// Returns the Int value for the indicated column. 522 | /// 523 | /// - parameter: Int position of column 524 | /// - returns: Int value for column 525 | public func columnInt(position: Int) -> Int { 526 | return Int(sqlite3_column_int64(self.stat!, Int32(position))) 527 | } 528 | 529 | /// Returns the Int32 value for the indicated column. 530 | /// 531 | /// - parameter: Int position of column 532 | /// - returns: Int32 value for column 533 | public func columnInt32(position: Int) -> Int32 { 534 | return sqlite3_column_int(self.stat!, Int32(position)) 535 | } 536 | 537 | /// Returns the Int64 value for the indicated column. 538 | /// 539 | /// - parameter: Int position of column 540 | /// - returns: Int64 value for column 541 | public func columnInt64(position: Int) -> Int64 { 542 | return sqlite3_column_int64(self.stat!, Int32(position)) 543 | } 544 | 545 | /// Returns the String value for the indicated column. 546 | /// 547 | /// - parameter: Int position of column 548 | /// - returns: String value for column 549 | public func columnText(position: Int) -> String { 550 | if let res = sqlite3_column_text(self.stat!, Int32(position)) { 551 | return res.withMemoryRebound(to: Int8.self, capacity: 0) { 552 | String(validatingUTF8: $0) ?? "" 553 | } 554 | } 555 | return "" 556 | } 557 | 558 | /// Returns the type for the indicated column. 559 | /// 560 | /// - parameter: Int position of column 561 | /// - returns: Int32 562 | public func columnType(position: Int) -> Int32 { 563 | return sqlite3_column_type(self.stat!, Int32(position)) 564 | } 565 | 566 | /// Test if the indicated column is an integer 567 | /// 568 | /// - parameter: Int position of column 569 | /// - returns: Bool 570 | public func isInteger(position: Int) -> Bool { 571 | return SQLITE_INTEGER == columnType(position: position) 572 | } 573 | 574 | /// Test if the indicated column is a Float 575 | /// 576 | /// - parameter: Int position of column 577 | /// - returns: Bool 578 | public func isFloat(position: Int) -> Bool { 579 | return SQLITE_FLOAT == columnType(position: position) 580 | } 581 | 582 | /// Test if the indicated column is Text 583 | /// 584 | /// - parameter: Int position of column 585 | /// - returns: Bool 586 | public func isText(position: Int) -> Bool { 587 | return SQLITE_TEXT == columnType(position: position) 588 | } 589 | 590 | /// Test if the indicated column is a Blob 591 | /// 592 | /// - parameter: Int position of column 593 | /// - returns: Bool 594 | public func isBlob(position: Int) -> Bool { 595 | return SQLITE_BLOB == columnType(position: position) 596 | } 597 | 598 | /// Test if the indicated column is NULL 599 | /// 600 | /// - parameter: Int position of column 601 | /// - returns: Bool 602 | public func isNull(position: Int) -> Bool { 603 | return SQLITE_NULL == columnType(position: position) 604 | } 605 | 606 | func checkRes(_ res: Int32) throws { 607 | try checkRes(Int(res)) 608 | } 609 | 610 | func checkRes(_ res: Int) throws { 611 | if res != Int(SQLITE_OK) { 612 | throw SQLiteError(code: res, description: String(validatingUTF8: sqlite3_errmsg(self.db!))!) 613 | } 614 | } 615 | 616 | deinit { 617 | finalize() 618 | } 619 | } 620 | 621 | #if !swift(>=4.1) 622 | // Added for Swift 4.0/4.1 compat 623 | extension Collection { 624 | func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { 625 | return try flatMap(transform) 626 | } 627 | } 628 | #endif 629 | 630 | -------------------------------------------------------------------------------- /docs/Classes/SQLite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SQLite Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 51 |
52 |
53 |
54 |

SQLite

55 |
56 |
57 |
public class SQLite
58 | 59 |
60 |
61 |

A SQLite database

62 | 63 |
64 |
65 |
66 |
    67 |
  • 68 |
    69 | 70 | 71 | 72 | init(_:readOnly:) 73 | 74 |
    75 |
    76 |
    77 |
    78 |
    79 |
    80 |

    Create or open a SQLite database given a file path.

    81 | 82 |
    83 |

    Throws

    84 | SQLiteError 85 | 86 |
    87 | 88 |
    89 |
    90 |

    Declaration

    91 |
    92 |

    Swift

    93 |
    public init(_ path: String, readOnly: Bool = false) throws
    94 | 95 |
    96 |
    97 |
    98 |

    Parameters

    99 | 100 | 101 | 102 | 107 | 113 | 114 | 115 | 120 | 126 | 127 | 128 |
    103 | 104 | path 105 | 106 | 108 |
    109 |

    String path to SQLite database

    110 | 111 |
    112 |
    116 | 117 | readOnly 118 | 119 | 121 |
    122 |

    Optional, Bool flag for read/write setting, defaults to false

    123 | 124 |
    125 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | close() 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 |

    Close the SQLite database.

    147 | 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public func close()
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
  • 161 |
    162 | 163 | 164 | 165 | prepare(statement:) 166 | 167 |
    168 |
    169 |
    170 |
    171 |
    172 |
    173 |

    Compile the SQL statement.

    174 | 175 |
    176 |
    177 |

    Declaration

    178 |
    179 |

    Swift

    180 |
    public func prepare(statement stat: String) throws -> SQLiteStmt
    181 | 182 |
    183 |
    184 |
    185 |

    Return Value

    186 |

    A SQLiteStmt object representing the compiled statement.

    187 | 188 |
    189 |
    190 |
    191 |
  • 192 |
  • 193 |
    194 | 195 | 196 | 197 | lastInsertRowID() 198 | 199 |
    200 |
    201 |
    202 |
    203 |
    204 |
    205 |

    Returns the value of sqlite3_last_insert_rowid.

    206 | 207 |
    208 |
    209 |

    Declaration

    210 |
    211 |

    Swift

    212 |
    public func lastInsertRowID() -> Int
    213 | 214 |
    215 |
    216 |
    217 |

    Return Value

    218 |

    Int last inserted row ID

    219 | 220 |
    221 |
    222 |
    223 |
  • 224 |
  • 225 |
    226 | 227 | 228 | 229 | totalChanges() 230 | 231 |
    232 |
    233 |
    234 |
    235 |
    236 |
    237 |

    Returns the value of sqlite3_total_changes.

    238 | 239 |
    240 |
    241 |

    Declaration

    242 |
    243 |

    Swift

    244 |
    public func totalChanges() -> Int
    245 | 246 |
    247 |
    248 |
    249 |

    Return Value

    250 |

    Int total changes

    251 | 252 |
    253 |
    254 |
    255 |
  • 256 |
  • 257 |
    258 | 259 | 260 | 261 | changes() 262 | 263 |
    264 |
    265 |
    266 |
    267 |
    268 |
    269 |

    Returns the value of sqlite3_changes.

    270 | 271 |
    272 |
    273 |

    Declaration

    274 |
    275 |

    Swift

    276 |
    public func changes() -> Int
    277 | 278 |
    279 |
    280 |
    281 |

    Return Value

    282 |

    Int number of changes

    283 | 284 |
    285 |
    286 |
    287 |
  • 288 |
  • 289 |
    290 | 291 | 292 | 293 | errCode() 294 | 295 |
    296 |
    297 |
    298 |
    299 |
    300 |
    301 |

    Returns the value of sqlite3_errcode.

    302 | 303 |
    304 |
    305 |

    Declaration

    306 |
    307 |

    Swift

    308 |
    public func errCode() -> Int
    309 | 310 |
    311 |
    312 |
    313 |

    Return Value

    314 |

    Int error code

    315 | 316 |
    317 |
    318 |
    319 |
  • 320 |
  • 321 |
    322 | 323 | 324 | 325 | errMsg() 326 | 327 |
    328 |
    329 |
    330 |
    331 |
    332 |
    333 |

    Returns the value of sqlite3_errmsg.

    334 | 335 |
    336 |
    337 |

    Declaration

    338 |
    339 |

    Swift

    340 |
    public func errMsg() -> String
    341 | 342 |
    343 |
    344 |
    345 |

    Return Value

    346 |

    String error message

    347 | 348 |
    349 |
    350 |
    351 |
  • 352 |
  • 353 |
    354 | 355 | 356 | 357 | execute(statement:) 358 | 359 |
    360 |
    361 |
    362 |
    363 |
    364 |
    365 |

    Execute the given statement. Assumes there will be no parameter binding or resulting row data.

    366 | 367 |
    368 |

    Throws

    369 | () 370 | 371 |
    372 | 373 |
    374 |
    375 |

    Declaration

    376 |
    377 |

    Swift

    378 |
    public func execute(statement statement: String) throws
    379 | 380 |
    381 |
    382 |
    383 |

    Parameters

    384 | 385 | 386 | 387 | 392 | 398 | 399 | 400 |
    388 | 389 | statement 390 | 391 | 393 |
    394 |

    String statement to be executed

    395 | 396 |
    397 |
    401 |
    402 |
    403 |
    404 |
  • 405 |
  • 406 |
    407 | 408 | 409 | 410 | execute(statement:doBindings:) 411 | 412 |
    413 |
    414 |
    415 |
    416 |
    417 |
    418 |

    Execute the given statement. Calls the provided callback one time for parameter binding. Assumes there will be no resulting row data.

    419 | 420 |
    421 |

    Throws

    422 | () 423 | 424 |
    425 | 426 |
    427 |
    428 |

    Declaration

    429 |
    430 |

    Swift

    431 |
    public func execute(statement statement: String, doBindings: (SQLiteStmt) throws -> ()) throws
    432 | 433 |
    434 |
    435 |
    436 |

    Parameters

    437 | 438 | 439 | 440 | 445 | 451 | 452 | 453 | 458 | 464 | 465 | 466 |
    441 | 442 | statement 443 | 444 | 446 |
    447 |

    String statement to be executed

    448 | 449 |
    450 |
    454 | 455 | doBindings 456 | 457 | 459 |
    460 |

    Block used for bindings

    461 | 462 |
    463 |
    467 |
    468 |
    469 |
    470 |
  • 471 |
  • 472 |
    473 | 474 | 475 | 476 | execute(statement:count:doBindings:) 477 | 478 |
    479 |
    480 |
    481 |
    482 |
    483 |
    484 |

    Execute the given statement count times. Calls the provided callback on each execution for parameter binding. Assumes there will be no resulting row data.

    485 | 486 |
    487 |

    Throws

    488 | () 489 | 490 |
    491 | 492 |
    493 |
    494 |

    Declaration

    495 |
    496 |

    Swift

    497 |
    public func execute(statement statement: String, count: Int, doBindings: (SQLiteStmt, Int) throws -> ()) throws
    498 | 499 |
    500 |
    501 |
    502 |

    Parameters

    503 | 504 | 505 | 506 | 511 | 517 | 518 | 519 | 524 | 530 | 531 | 532 | 537 | 543 | 544 | 545 |
    507 | 508 | statement 509 | 510 | 512 |
    513 |

    String statement to be executed

    514 | 515 |
    516 |
    520 | 521 | count 522 | 523 | 525 |
    526 |

    Int number of times to execute

    527 | 528 |
    529 |
    533 | 534 | doBindings 535 | 536 | 538 |
    539 |

    Block to be executed for binding on each call

    540 | 541 |
    542 |
    546 |
    547 |
    548 |
    549 |
  • 550 |
  • 551 |
    552 | 553 | 554 | 555 | doWithTransaction(_:) 556 | 557 |
    558 |
    559 |
    560 |
    561 |
    562 |
    563 |

    Executes a BEGIN, calls the provided closure and executes a ROLLBACK if an exception occurs or a COMMIT if no exception occurs.

    564 | 565 |
    566 |

    Throws

    567 | ErrorType 568 | 569 |
    570 | 571 |
    572 |
    573 |

    Declaration

    574 |
    575 |

    Swift

    576 |
    public func doWithTransaction(closure: () throws -> ()) throws
    577 | 578 |
    579 |
    580 |
    581 |

    Parameters

    582 | 583 | 584 | 585 | 590 | 596 | 597 | 598 |
    586 | 587 | closure 588 | 589 | 591 |
    592 |

    Block to be executed inside transaction

    593 | 594 |
    595 |
    599 |
    600 |
    601 |
    602 |
  • 603 |
  • 604 |
    605 | 606 | 607 | 608 | forEachRow(statement:handleRow:) 609 | 610 |
    611 |
    612 |
    613 |
    614 |
    615 |
    616 |

    Executes the statement and calls the closure for each resulting row.

    617 | 618 |
    619 |

    Throws

    620 | () 621 | 622 |
    623 | 624 |
    625 |
    626 |

    Declaration

    627 |
    628 |

    Swift

    629 |
    public func forEachRow(statement statement: String, handleRow: (SQLiteStmt, Int) -> ()) throws
    630 | 631 |
    632 |
    633 |
    634 |

    Parameters

    635 | 636 | 637 | 638 | 643 | 649 | 650 | 651 | 656 | 662 | 663 | 664 |
    639 | 640 | statement 641 | 642 | 644 |
    645 |

    String statement to be executed

    646 | 647 |
    648 |
    652 | 653 | handleRow 654 | 655 | 657 |
    658 |

    Block to be executed for each row

    659 | 660 |
    661 |
    665 |
    666 |
    667 |
    668 |
  • 669 |
  • 670 |
    671 | 672 | 673 | 674 | forEachRow(statement:doBindings:handleRow:) 675 | 676 |
    677 |
    678 |
    679 |
    680 |
    681 |
    682 |

    Executes the statement, calling doBindings to handle parameter bindings and calling handleRow for each resulting row.

    683 | 684 |
    685 |

    Throws

    686 | () 687 | 688 |
    689 | 690 |
    691 |
    692 |

    Declaration

    693 |
    694 |

    Swift

    695 |
    public func forEachRow(statement statement: String, doBindings: (SQLiteStmt) throws -> (), handleRow: (SQLiteStmt, Int) -> ()) throws
    696 | 697 |
    698 |
    699 |
    700 |

    Parameters

    701 | 702 | 703 | 704 | 709 | 715 | 716 | 717 | 722 | 728 | 729 | 730 | 735 | 741 | 742 | 743 |
    705 | 706 | statement 707 | 708 | 710 |
    711 |

    String statement to be executed

    712 | 713 |
    714 |
    718 | 719 | doBindings 720 | 721 | 723 |
    724 |

    Block to perform bindings on statement

    725 | 726 |
    727 |
    731 | 732 | handleRow 733 | 734 | 736 |
    737 |

    Block to execute for each row

    738 | 739 |
    740 |
    744 |
    745 |
    746 |
    747 |
  • 748 |
749 |
750 |
751 |
752 | 756 |
757 |
758 | 759 | 760 | 761 | -------------------------------------------------------------------------------- /docs/docsets/.docset/Contents/Resources/Documents/Classes/SQLite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SQLite Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 51 |
52 |
53 |
54 |

SQLite

55 |
56 |
57 |
public class SQLite
58 | 59 |
60 |
61 |

A SQLite database

62 | 63 |
64 |
65 |
66 |
    67 |
  • 68 |
    69 | 70 | 71 | 72 | init(_:readOnly:) 73 | 74 |
    75 |
    76 |
    77 |
    78 |
    79 |
    80 |

    Create or open a SQLite database given a file path.

    81 | 82 |
    83 |

    Throws

    84 | SQLiteError 85 | 86 |
    87 | 88 |
    89 |
    90 |

    Declaration

    91 |
    92 |

    Swift

    93 |
    public init(_ path: String, readOnly: Bool = false) throws
    94 | 95 |
    96 |
    97 |
    98 |

    Parameters

    99 | 100 | 101 | 102 | 107 | 113 | 114 | 115 | 120 | 126 | 127 | 128 |
    103 | 104 | path 105 | 106 | 108 |
    109 |

    String path to SQLite database

    110 | 111 |
    112 |
    116 | 117 | readOnly 118 | 119 | 121 |
    122 |

    Optional, Bool flag for read/write setting, defaults to false

    123 | 124 |
    125 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | close() 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 |

    Close the SQLite database.

    147 | 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public func close()
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
  • 161 |
    162 | 163 | 164 | 165 | prepare(statement:) 166 | 167 |
    168 |
    169 |
    170 |
    171 |
    172 |
    173 |

    Compile the SQL statement.

    174 | 175 |
    176 |
    177 |

    Declaration

    178 |
    179 |

    Swift

    180 |
    public func prepare(statement stat: String) throws -> SQLiteStmt
    181 | 182 |
    183 |
    184 |
    185 |

    Return Value

    186 |

    A SQLiteStmt object representing the compiled statement.

    187 | 188 |
    189 |
    190 |
    191 |
  • 192 |
  • 193 |
    194 | 195 | 196 | 197 | lastInsertRowID() 198 | 199 |
    200 |
    201 |
    202 |
    203 |
    204 |
    205 |

    Returns the value of sqlite3_last_insert_rowid.

    206 | 207 |
    208 |
    209 |

    Declaration

    210 |
    211 |

    Swift

    212 |
    public func lastInsertRowID() -> Int
    213 | 214 |
    215 |
    216 |
    217 |

    Return Value

    218 |

    Int last inserted row ID

    219 | 220 |
    221 |
    222 |
    223 |
  • 224 |
  • 225 |
    226 | 227 | 228 | 229 | totalChanges() 230 | 231 |
    232 |
    233 |
    234 |
    235 |
    236 |
    237 |

    Returns the value of sqlite3_total_changes.

    238 | 239 |
    240 |
    241 |

    Declaration

    242 |
    243 |

    Swift

    244 |
    public func totalChanges() -> Int
    245 | 246 |
    247 |
    248 |
    249 |

    Return Value

    250 |

    Int total changes

    251 | 252 |
    253 |
    254 |
    255 |
  • 256 |
  • 257 |
    258 | 259 | 260 | 261 | changes() 262 | 263 |
    264 |
    265 |
    266 |
    267 |
    268 |
    269 |

    Returns the value of sqlite3_changes.

    270 | 271 |
    272 |
    273 |

    Declaration

    274 |
    275 |

    Swift

    276 |
    public func changes() -> Int
    277 | 278 |
    279 |
    280 |
    281 |

    Return Value

    282 |

    Int number of changes

    283 | 284 |
    285 |
    286 |
    287 |
  • 288 |
  • 289 |
    290 | 291 | 292 | 293 | errCode() 294 | 295 |
    296 |
    297 |
    298 |
    299 |
    300 |
    301 |

    Returns the value of sqlite3_errcode.

    302 | 303 |
    304 |
    305 |

    Declaration

    306 |
    307 |

    Swift

    308 |
    public func errCode() -> Int
    309 | 310 |
    311 |
    312 |
    313 |

    Return Value

    314 |

    Int error code

    315 | 316 |
    317 |
    318 |
    319 |
  • 320 |
  • 321 |
    322 | 323 | 324 | 325 | errMsg() 326 | 327 |
    328 |
    329 |
    330 |
    331 |
    332 |
    333 |

    Returns the value of sqlite3_errmsg.

    334 | 335 |
    336 |
    337 |

    Declaration

    338 |
    339 |

    Swift

    340 |
    public func errMsg() -> String
    341 | 342 |
    343 |
    344 |
    345 |

    Return Value

    346 |

    String error message

    347 | 348 |
    349 |
    350 |
    351 |
  • 352 |
  • 353 |
    354 | 355 | 356 | 357 | execute(statement:) 358 | 359 |
    360 |
    361 |
    362 |
    363 |
    364 |
    365 |

    Execute the given statement. Assumes there will be no parameter binding or resulting row data.

    366 | 367 |
    368 |

    Throws

    369 | () 370 | 371 |
    372 | 373 |
    374 |
    375 |

    Declaration

    376 |
    377 |

    Swift

    378 |
    public func execute(statement statement: String) throws
    379 | 380 |
    381 |
    382 |
    383 |

    Parameters

    384 | 385 | 386 | 387 | 392 | 398 | 399 | 400 |
    388 | 389 | statement 390 | 391 | 393 |
    394 |

    String statement to be executed

    395 | 396 |
    397 |
    401 |
    402 |
    403 |
    404 |
  • 405 |
  • 406 |
    407 | 408 | 409 | 410 | execute(statement:doBindings:) 411 | 412 |
    413 |
    414 |
    415 |
    416 |
    417 |
    418 |

    Execute the given statement. Calls the provided callback one time for parameter binding. Assumes there will be no resulting row data.

    419 | 420 |
    421 |

    Throws

    422 | () 423 | 424 |
    425 | 426 |
    427 |
    428 |

    Declaration

    429 |
    430 |

    Swift

    431 |
    public func execute(statement statement: String, doBindings: (SQLiteStmt) throws -> ()) throws
    432 | 433 |
    434 |
    435 |
    436 |

    Parameters

    437 | 438 | 439 | 440 | 445 | 451 | 452 | 453 | 458 | 464 | 465 | 466 |
    441 | 442 | statement 443 | 444 | 446 |
    447 |

    String statement to be executed

    448 | 449 |
    450 |
    454 | 455 | doBindings 456 | 457 | 459 |
    460 |

    Block used for bindings

    461 | 462 |
    463 |
    467 |
    468 |
    469 |
    470 |
  • 471 |
  • 472 |
    473 | 474 | 475 | 476 | execute(statement:count:doBindings:) 477 | 478 |
    479 |
    480 |
    481 |
    482 |
    483 |
    484 |

    Execute the given statement count times. Calls the provided callback on each execution for parameter binding. Assumes there will be no resulting row data.

    485 | 486 |
    487 |

    Throws

    488 | () 489 | 490 |
    491 | 492 |
    493 |
    494 |

    Declaration

    495 |
    496 |

    Swift

    497 |
    public func execute(statement statement: String, count: Int, doBindings: (SQLiteStmt, Int) throws -> ()) throws
    498 | 499 |
    500 |
    501 |
    502 |

    Parameters

    503 | 504 | 505 | 506 | 511 | 517 | 518 | 519 | 524 | 530 | 531 | 532 | 537 | 543 | 544 | 545 |
    507 | 508 | statement 509 | 510 | 512 |
    513 |

    String statement to be executed

    514 | 515 |
    516 |
    520 | 521 | count 522 | 523 | 525 |
    526 |

    Int number of times to execute

    527 | 528 |
    529 |
    533 | 534 | doBindings 535 | 536 | 538 |
    539 |

    Block to be executed for binding on each call

    540 | 541 |
    542 |
    546 |
    547 |
    548 |
    549 |
  • 550 |
  • 551 |
    552 | 553 | 554 | 555 | doWithTransaction(_:) 556 | 557 |
    558 |
    559 |
    560 |
    561 |
    562 |
    563 |

    Executes a BEGIN, calls the provided closure and executes a ROLLBACK if an exception occurs or a COMMIT if no exception occurs.

    564 | 565 |
    566 |

    Throws

    567 | ErrorType 568 | 569 |
    570 | 571 |
    572 |
    573 |

    Declaration

    574 |
    575 |

    Swift

    576 |
    public func doWithTransaction(closure: () throws -> ()) throws
    577 | 578 |
    579 |
    580 |
    581 |

    Parameters

    582 | 583 | 584 | 585 | 590 | 596 | 597 | 598 |
    586 | 587 | closure 588 | 589 | 591 |
    592 |

    Block to be executed inside transaction

    593 | 594 |
    595 |
    599 |
    600 |
    601 |
    602 |
  • 603 |
  • 604 |
    605 | 606 | 607 | 608 | forEachRow(statement:handleRow:) 609 | 610 |
    611 |
    612 |
    613 |
    614 |
    615 |
    616 |

    Executes the statement and calls the closure for each resulting row.

    617 | 618 |
    619 |

    Throws

    620 | () 621 | 622 |
    623 | 624 |
    625 |
    626 |

    Declaration

    627 |
    628 |

    Swift

    629 |
    public func forEachRow(statement statement: String, handleRow: (SQLiteStmt, Int) -> ()) throws
    630 | 631 |
    632 |
    633 |
    634 |

    Parameters

    635 | 636 | 637 | 638 | 643 | 649 | 650 | 651 | 656 | 662 | 663 | 664 |
    639 | 640 | statement 641 | 642 | 644 |
    645 |

    String statement to be executed

    646 | 647 |
    648 |
    652 | 653 | handleRow 654 | 655 | 657 |
    658 |

    Block to be executed for each row

    659 | 660 |
    661 |
    665 |
    666 |
    667 |
    668 |
  • 669 |
  • 670 |
    671 | 672 | 673 | 674 | forEachRow(statement:doBindings:handleRow:) 675 | 676 |
    677 |
    678 |
    679 |
    680 |
    681 |
    682 |

    Executes the statement, calling doBindings to handle parameter bindings and calling handleRow for each resulting row.

    683 | 684 |
    685 |

    Throws

    686 | () 687 | 688 |
    689 | 690 |
    691 |
    692 |

    Declaration

    693 |
    694 |

    Swift

    695 |
    public func forEachRow(statement statement: String, doBindings: (SQLiteStmt) throws -> (), handleRow: (SQLiteStmt, Int) -> ()) throws
    696 | 697 |
    698 |
    699 |
    700 |

    Parameters

    701 | 702 | 703 | 704 | 709 | 715 | 716 | 717 | 722 | 728 | 729 | 730 | 735 | 741 | 742 | 743 |
    705 | 706 | statement 707 | 708 | 710 |
    711 |

    String statement to be executed

    712 | 713 |
    714 |
    718 | 719 | doBindings 720 | 721 | 723 |
    724 |

    Block to perform bindings on statement

    725 | 726 |
    727 |
    731 | 732 | handleRow 733 | 734 | 736 |
    737 |

    Block to execute for each row

    738 | 739 |
    740 |
    744 |
    745 |
    746 |
    747 |
  • 748 |
749 |
750 |
751 |
752 | 756 |
757 |
758 | 759 | 760 | 761 | --------------------------------------------------------------------------------