motion-sqlite3 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60363684d12e16e0ccb74acc26918d1548972762
4
+ data.tar.gz: b79313617ce0179fc585320b48d22d6d765a34c9
5
+ SHA512:
6
+ metadata.gz: cc32f386588abeaf391a715d1f65deb5e359ed50f3fac8eebbc8be52ddc7bd4a17704f31c8c6279086d956392e847efcaa3d08bc75c23783906b354f2006b6e0
7
+ data.tar.gz: 0c1aed2f2d261d4f72a2b1397df1aeec5a54c30fd4973f2d7768ff355c57c9bd8d9fbc3b2a4782bd09c1977bb209f8b505ccd38fe9a8361c3a98a820dfcbcec4
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ .repl_history
2
+ build
3
+ tags
4
+ app/pixate_code.rb
5
+ resources/*.nib
6
+ resources/*.momd
7
+ resources/*.storyboardc
8
+ vendor/sqlite3/build-*
9
+ .DS_Store
10
+ nbproject
11
+ .redcar
12
+ #*#
13
+ *~
14
+ *.sw[po]
15
+ .eprj
16
+ .sass-cache
17
+ .idea
data/.rvmrc ADDED
@@ -0,0 +1,4 @@
1
+ rvm ruby-1.9.3-p194@rubymotion --create
2
+
3
+ [[ -s "config/rvm_env.sh" ]] && . "config/rvm_env.sh"
4
+ [[ -s ".rvm_env" ]] && . ".rvm_env"
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gem 'rake', '~> 0.9.0'
5
+
6
+ gem 'cocoapods'#, '~> 0.16.0'
7
+ gem 'motion-cocoapods'#, '~> 1.2.1'
8
+
9
+ gem 'guard-motion'
10
+ gem 'rb-fsevent', '~> 0.9.1'
data/Gemfile.lock ADDED
@@ -0,0 +1,74 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.11)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ addressable (2.3.2)
8
+ cocoapods (0.16.1)
9
+ activesupport (~> 3.2.6)
10
+ colored (~> 1.2)
11
+ escape (~> 0.0.4)
12
+ faraday (~> 0.8.1)
13
+ json (~> 1.7.3)
14
+ octokit (~> 1.7)
15
+ open4 (~> 1.3.0)
16
+ rake (~> 0.9.4)
17
+ xcodeproj (~> 0.4.1)
18
+ coderay (1.0.8)
19
+ colored (1.2)
20
+ escape (0.0.4)
21
+ faraday (0.8.4)
22
+ multipart-post (~> 1.1)
23
+ faraday_middleware (0.9.0)
24
+ faraday (>= 0.7.4, < 0.9)
25
+ guard (1.6.2)
26
+ listen (>= 0.6.0)
27
+ lumberjack (>= 1.0.2)
28
+ pry (>= 0.9.10)
29
+ terminal-table (>= 1.4.3)
30
+ thor (>= 0.14.6)
31
+ guard-motion (0.1.1)
32
+ guard (>= 1.1.0)
33
+ rake (>= 0.9)
34
+ hashie (1.2.0)
35
+ i18n (0.6.1)
36
+ json (1.7.6)
37
+ listen (0.7.2)
38
+ lumberjack (1.0.2)
39
+ method_source (0.8.1)
40
+ motion-cocoapods (1.2.1)
41
+ cocoapods (>= 0.14.0)
42
+ multi_json (1.5.0)
43
+ multipart-post (1.1.5)
44
+ netrc (0.7.7)
45
+ octokit (1.22.0)
46
+ addressable (~> 2.2)
47
+ faraday (~> 0.8)
48
+ faraday_middleware (~> 0.9)
49
+ hashie (~> 1.2)
50
+ multi_json (~> 1.3)
51
+ netrc (~> 0.7.7)
52
+ open4 (1.3.0)
53
+ pry (0.9.11.4)
54
+ coderay (~> 1.0.5)
55
+ method_source (~> 0.8)
56
+ slop (~> 3.4)
57
+ rake (0.9.6)
58
+ rb-fsevent (0.9.3)
59
+ slop (3.4.3)
60
+ terminal-table (1.4.5)
61
+ thor (0.17.0)
62
+ xcodeproj (0.4.2)
63
+ activesupport (~> 3.2.6)
64
+ colored (~> 1.2)
65
+
66
+ PLATFORMS
67
+ ruby
68
+
69
+ DEPENDENCIES
70
+ cocoapods
71
+ guard-motion
72
+ motion-cocoapods
73
+ rake (~> 0.9.0)
74
+ rb-fsevent (~> 0.9.1)
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'motion', :all_after_pass => false do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+
7
+ # RubyMotion gem example
8
+ watch(%r{^lib/[^/]+/(.+)\.rb$}) { |m| "./spec/#{m[1]}_spec.rb" }
9
+ end
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ Introduction
2
+ ------------
3
+ This is a tiny wrapper around the SQLite C API that's written in RubyMotion. It is intentionally bare so as to limit the surface area of code that interacts with the raw C API (misuse of the C API can cause resource leaks and seg faults). Think of it more as a driver for SQLite than anything else.
4
+
5
+ Whenever possible, it uses Ruby idioms like blocks and exceptions.
6
+
7
+ Sample code
8
+ -----------
9
+
10
+ #### DB in memory
11
+
12
+ ```ruby
13
+ db = SQLite3::Database.new(":memory:")
14
+ db.execute("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)")
15
+ db.execute("INSERT INTO test (name, age) VALUES (?, ?)", ["brad", 28])
16
+ db.execute("INSERT INTO test (name, age) VALUES (?, ?)", ["sparky", 24])
17
+
18
+ rows = []
19
+ db.execute("SELECT * FROM test") do |row|
20
+ rows << row
21
+ end
22
+
23
+ rows.should == [
24
+ { id: 1, name: "brad", age: 28 },
25
+ { id: 2, name: "sparky", age: 24 }
26
+ ]
27
+ ```
28
+
29
+ #### DB in your resources folder
30
+
31
+ ```ruby
32
+ # File is stored in your /project/resources/ folder
33
+ db = SQLite3::Database.new(File.join(App.resources_path, "my_db.sqlite"))
34
+
35
+ rows = []
36
+ db.execute("SELECT * FROM test ORDER BY id") do |row|
37
+ rows << row
38
+ end
39
+ ```
40
+
41
+ *this code assumes you're using BubbleWrap for access to `App.resources_path`.
42
+
43
+ Usage
44
+ ----------
45
+ * Pass a filename to the constructor, or ":memory:". The database is held open for the lifetime of the object.
46
+ * Use `execute` to run SQL statements. All SQL statements are first prepared, and parameters can be passed as an Array or a Hash. If a Hash is passed, then the SQLite named parameter syntax is assumed to be in use.
47
+ * Use `execute_debug` to see the SQL statement and paramaters passed in the REPL. You should not use this method in production.
48
+ * Use `execute_scalar` to run SQL statements and return the first column of the first row. This is useful for queries like `SELECT COUNT(*) FROM posts`.
49
+
50
+ Caveats
51
+ -------
52
+ * The way it links with libsqlite3.dylib is hacky: a blank .m file in the vendor folder. Will need to fix this.
53
+
54
+ Status
55
+ ----------
56
+ Still in early stages. I'm hacking on it.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift("/Library/RubyMotion/lib")
3
+ require 'motion/project/template/ios'
4
+
5
+ require "bundler/gem_tasks"
6
+ require "bundler/setup"
7
+ Bundler.require :default
8
+
9
+ Motion::Project::App.setup do |app|
10
+ app.name = 'motion-sqlite3'
11
+
12
+ base_dir = File.dirname(__FILE__)
13
+ app.files += Dir.glob(File.join(base_dir, "lib/motion-sqlite3/**/*.rb"))
14
+
15
+ if ENV["DEFAULT_PROVISIONING_PROFILE"]
16
+ app.provisioning_profile = ENV["DEFAULT_PROVISIONING_PROFILE"]
17
+ end
18
+
19
+ app.libs << "/usr/lib/libsqlite3.dylib"
20
+ app.vendor_project('vendor/sqlite3', :static, :products => [])
21
+ end
@@ -0,0 +1,5 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'motion-sqlite3/version'
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+ Dir.glob(File.join(File.dirname(__FILE__), "motion-sqlite3/**/*.rb")).each do |file|
9
+ app.files.unshift(file)
10
+ end
11
+
12
+ app.libs << "/usr/lib/libsqlite3.dylib"
13
+
14
+ vendor_dir = File.expand_path(File.join(File.dirname(__FILE__), "../vendor/sqlite3"))
15
+ app.vendor_project(vendor_dir, :static, :products => [])
16
+ end
@@ -0,0 +1,62 @@
1
+ module SQLite3
2
+ class Database
3
+ def initialize(filename)
4
+ @handle = Pointer.new(::Sqlite3.type)
5
+
6
+ result = sqlite3_open(filename, @handle)
7
+ raise SQLite3Error, sqlite3_errmsg(@handle.value) if result != SQLITE_OK
8
+ end
9
+
10
+ def execute(sql, params = nil, &block)
11
+ raise ArgumentError if sql.nil?
12
+
13
+ #puts "*** #{sql}"
14
+ #puts " #{params.inspect}" if params
15
+
16
+ prepare(sql, params) do |statement|
17
+ results = statement.execute
18
+
19
+ if block_given?
20
+ results.each do |result|
21
+ yield result
22
+ end
23
+ else
24
+ rows = []
25
+
26
+ results.each do |result|
27
+ rows << result
28
+ end
29
+
30
+ rows
31
+ end
32
+ end
33
+ end
34
+
35
+ def execute_debug(*args, &block)
36
+ puts "*** #{args[0]}"
37
+ puts " #{args[1].inspect}" if args[1]
38
+
39
+ execute(*args, &block)
40
+ end
41
+
42
+ def execute_scalar(*args)
43
+ execute(*args).first.values.first
44
+ end
45
+
46
+ private
47
+
48
+ def prepare(sql, params, &block)
49
+ statement = Statement.new(@handle, sql, params)
50
+ result = nil
51
+
52
+ begin
53
+ result = yield statement
54
+
55
+ ensure
56
+ statement.finalize
57
+ end
58
+
59
+ result
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ module SQLite3
2
+ class SQLite3Error < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,57 @@
1
+ module SQLite3
2
+ class ResultSet
3
+ def initialize(statement, handle)
4
+ @statement = statement
5
+ @handle = handle
6
+ end
7
+
8
+ def each(&block)
9
+ until @statement.done?
10
+ yield current_row
11
+
12
+ @statement.step
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def columns
19
+ @result_columns ||= begin
20
+ columns = {}
21
+
22
+ count = sqlite3_column_count(@handle.value)
23
+ 0.upto(count-1) do |i|
24
+ name = sqlite3_column_name(@handle.value, i).to_sym
25
+ type = sqlite3_column_type(@handle.value, i)
26
+
27
+ columns[name] = ColumnMetadata.new(i, type)
28
+ end
29
+
30
+ columns
31
+ end
32
+ end
33
+
34
+ def current_row
35
+ row = {}
36
+
37
+ columns.each do |name, metadata|
38
+ case metadata.type
39
+ when SQLITE_NULL
40
+ row[name] = nil
41
+ when SQLITE_TEXT
42
+ row[name] = sqlite3_column_text(@handle.value, metadata.index)
43
+ when SQLITE_BLOB
44
+ row[name] = NSData.dataWithBytes(sqlite3_column_blob(@handle.value, metadata.index), length: sqlite3_column_bytes(@handle.value, metadata.index))
45
+ when SQLITE_INTEGER
46
+ row[name] = sqlite3_column_int(@handle.value, metadata.index)
47
+ when SQLITE_FLOAT
48
+ row[name] = sqlite3_column_double(@handle.value, metadata.index)
49
+ end
50
+ end
51
+
52
+ row
53
+ end
54
+ end
55
+
56
+ class ColumnMetadata < Struct.new(:index, :type); end
57
+ end
@@ -0,0 +1,86 @@
1
+ module SQLite3
2
+ class Statement
3
+ def initialize(db, sql, params)
4
+ @db = db
5
+ @handle = Pointer.new(::Sqlite3_stmt.type)
6
+ @result = nil
7
+
8
+ prepare(sql)
9
+ bind(params)
10
+ end
11
+
12
+ def done?
13
+ @result == SQLITE_DONE
14
+ end
15
+
16
+ def execute
17
+ step
18
+
19
+ ResultSet.new(self, @handle)
20
+ end
21
+
22
+ def finalize
23
+ sqlite3_finalize(@handle.value)
24
+ end
25
+
26
+ def step
27
+ @result = sqlite3_step(@handle.value)
28
+ unless @result == SQLITE_DONE || @result == SQLITE_ROW
29
+ raise SQLite3Error, sqlite3_errmsg(@db.value)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def bind(params)
36
+ case params
37
+ when Hash
38
+ params.each { |name, value| bind_parameter(name, value) }
39
+ when Array
40
+ params.each_with_index { |value, i| bind_parameter(i+1, value) }
41
+ end
42
+ end
43
+
44
+ def bind_parameter(name, value)
45
+ index = column_index(name)
46
+
47
+ case value
48
+ when NilClass
49
+ result = sqlite3_bind_null(@handle.value, index)
50
+ when String
51
+ result = sqlite3_bind_text(@handle.value, index, value, -1, lambda { |arg| })
52
+ when Integer
53
+ result = sqlite3_bind_int(@handle.value, index, value)
54
+ when Float
55
+ result = sqlite3_bind_double(@handle.value, index, value)
56
+ when NSData
57
+ result = sqlite3_bind_blob(@handle.value, index, value.bytes, value.length, lambda { |arg| })
58
+ else
59
+ raise SQLite3Error, "unable to bind #{value} to #{name}: unexpected type #{value.class}"
60
+ end
61
+
62
+ raise SQLite3Error, sqlite3_errmsg(@db.value) if result != SQLITE_OK
63
+ end
64
+
65
+ def column_index(name)
66
+ index = 0
67
+
68
+ case name
69
+ when String, Symbol
70
+ index = sqlite3_bind_parameter_index(@handle.value, ":#{name}")
71
+ raise SQLite3Error, "couldn't find index for #{name}!" if index == 0
72
+
73
+ when Integer
74
+ index = name
75
+ end
76
+
77
+ index
78
+ end
79
+
80
+ def prepare(sql)
81
+ remainder = Pointer.new(:string)
82
+ result = sqlite3_prepare_v2(@db.value, sql, -1, @handle, remainder)
83
+ raise SQLite3Error, sqlite3_errmsg(@db.value) if result != SQLITE_OK
84
+ end
85
+ end
86
+ end