static-record 1.0.0.pre → 1.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a8eb89ed57ec1a0a6fbc6574e1c1614cda528447
4
- data.tar.gz: ffffe730a97c3953064f7e2f517d840852ecf48e
3
+ metadata.gz: a561fe2ae524c134408db76ff95bad7e8b5f11c9
4
+ data.tar.gz: c0a00cf2f7342dfd97d5ebe4e18c650ba50abc81
5
5
  SHA512:
6
- metadata.gz: 0d93d7d7ebcc4b347ccad1863e4ce43d3a51688022b7e4b2292820292a3ff0eafa49f1713c1f12058da444517d6c1605ff7d0db57da3401bd630e1bab0efb731
7
- data.tar.gz: 40483219ffbe67bd87118e3d9175b5be8c7b681a6f8909b9188f1efc887f5fedc05c6a7594bdde42714fb5140d67b6be56dc099d50cfdb8bd5116330f7901b53
6
+ metadata.gz: 5f9aaf4e4bdeb208ea94137af0d1a2f0833792636c05d01aff82ccfb070e61e162e43decf9836bd1bc89e6c1b01b589b6eab058d8a74c2deb1837b506e4048f2
7
+ data.tar.gz: 9e62c0b5d76b45aec821bc2d588256bd49bf3cece1d322185c9eafb769263234b2a5a90abcdc14ba2f890f00d955d9e340579dc64dca91ff6f15fb067f4343d3
data/README.rdoc CHANGED
@@ -10,10 +10,13 @@ You can use it when you need several files inheriting a base class.
10
10
 
11
11
  Add this to your Gemfile:
12
12
 
13
- gem 'static-record'
13
+ gem 'static_record', require: 'static_record'
14
14
 
15
15
  and run the bundle install command.
16
16
 
17
+ The 'require' part is important so that Rails autoloads the library correctly.
18
+
19
+
17
20
  == Getting Started
18
21
 
19
22
  === Base class
data/lib/static_record.rb CHANGED
@@ -1,5 +1,13 @@
1
1
  require 'static_record/engine'
2
2
  require 'static_record/exceptions'
3
3
 
4
+ require 'static_record/concerns/query_building_concern'
5
+ require 'static_record/concerns/sqlite_storing_concern'
6
+
7
+ require 'static_record/models/predicates'
8
+ require 'static_record/models/querying'
9
+ require 'static_record/models/relation'
10
+ require 'static_record/models/base'
11
+
4
12
  module StaticRecord
5
13
  end
@@ -0,0 +1,105 @@
1
+ module StaticRecord
2
+ # Helps building SQL queries
3
+ module QueryBuildingConcern
4
+ extend ActiveSupport::Concern
5
+
6
+ def build_query
7
+ sql = sql_select_from
8
+ sql += sql_where unless @where_clauses.empty?
9
+ sql += sql_order unless @order_by.empty?
10
+ sql += sql_limit_offset if @sql_limit
11
+ sql
12
+ end
13
+
14
+ private
15
+
16
+ def sql_select_from
17
+ sql = "SELECT #{@columns} FROM #{@table}"
18
+ end
19
+
20
+ def sql_where
21
+ " WHERE #{where_clause_builder}"
22
+ end
23
+
24
+ def sql_order
25
+ ord_sql = ''
26
+ @order_by.each do |ord|
27
+ ord_sql += ord_sql.empty? ? ' ORDER BY' : ', '
28
+ case ord.class.name
29
+ when Hash.name
30
+ ord_sql += ord.map { |k, v| " #{@table}.#{k.to_s} #{v.to_s.upcase}" }.join(',')
31
+ when Array.name
32
+ ord_sql += ord.map { |sym| " #{@table}.#{sym.to_s} ASC" }.join(',')
33
+ when Symbol.name
34
+ ord_sql += " #{@table}.#{ord.to_s} ASC"
35
+ when String.name
36
+ ord_sql += " #{ord}"
37
+ end
38
+ end
39
+ ord_sql
40
+ end
41
+
42
+ def sql_limit_offset
43
+ sql = " LIMIT #{@sql_limit}"
44
+ sql += " OFFSET #{@sql_offset}" if @sql_offset
45
+ sql
46
+ end
47
+
48
+ def where_clause_builder
49
+ params = []
50
+ @where_clauses.map do |clause|
51
+ subquery = clause[:q]
52
+ if subquery.is_a?(Hash)
53
+ params << where_clause_from_hash(clause, subquery)
54
+ elsif subquery.is_a?(String)
55
+ params << where_clause_from_string(clause, subquery)
56
+ end
57
+
58
+ if params.size > 1
59
+ joint = clause[:chain] == :or ? 'OR' : 'AND'
60
+ params = [params.join(" #{joint} ")]
61
+ end
62
+ end
63
+
64
+ params.first
65
+ end
66
+
67
+ def where_clause_from_hash(clause, subquery)
68
+ parts = subquery.keys.map do |key|
69
+ value = subquery[key]
70
+ part = ''
71
+ if value.is_a?(Array)
72
+ # ex: where(name: ['John', 'Jack'])
73
+ # use IN operator
74
+ value.map! { |v| v =~ /^\d+$/ ? v : "\"#{v}\"" }
75
+ inverse = 'NOT ' if clause[:operator] == :not_eq
76
+ part = "#{key.to_s} #{inverse}IN (#{value.join(',')})"
77
+ else
78
+ # ex: where(name: 'John')
79
+ # use = operator
80
+ inverse = '!' if clause[:operator] == :not_eq
81
+ part = "#{key.to_s} #{inverse}= '#{value}'"
82
+ end
83
+ end
84
+ parts.join(' AND ')
85
+ end
86
+
87
+ def where_clause_from_string(clause, subquery)
88
+ final_string = subquery
89
+ if clause[:parameters].is_a?(Array)
90
+ # Anon parameters
91
+ # ex: where("name = ? OR name = ?", 'John', 'Jack')
92
+ clause[:parameters].each do |param|
93
+ final_string.sub!(/\?/, "\"#{param}\"")
94
+ end
95
+ elsif clause[:parameters].is_a?(Hash)
96
+ # Named parameters (placeholder condition)
97
+ # ex: where("name = :one OR name = :two", one: 'John', two: 'Smith')
98
+ clause[:parameters].each do |key, value|
99
+ final_string.sub!(":#{key}", "\"#{value}\"")
100
+ end
101
+ end
102
+ final_string
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,63 @@
1
+ module StaticRecord
2
+ # Reads ruby files whose path matches path pattern and store them
3
+ # as records in an SQLite3 database
4
+ module SqliteStoringConcern
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods # :nodoc:
8
+ def create_store
9
+ columns = class_variable_get(:@@_columns)
10
+ begin
11
+ dbname = Rails.root.join('db', "static_#{store}.sqlite3").to_s
12
+ SQLite3::Database.new(dbname)
13
+ db = SQLite3::Database.open(dbname)
14
+ db.execute("DROP TABLE IF EXISTS #{store}")
15
+ create_table(db, columns)
16
+ load_records.each_with_index do |record, index|
17
+ insert_into_database(db, record, index, columns)
18
+ end
19
+ rescue SQLite3::Exception => e
20
+ puts 'Exception occurred', e
21
+ ensure
22
+ db.close if db
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def create_table(db, columns)
29
+ cols = columns.map { |c| c.to_s + ' TEXT' }.join(', ')
30
+ sql = "CREATE TABLE #{store}(id INTEGER PRIMARY KEY, klass TEXT, #{cols})"
31
+ db.execute(sql)
32
+ end
33
+
34
+ def insert_into_database(db, record, index, columns)
35
+ attrs = record.constantize.new.attributes
36
+ sqlized = [index.to_s, "'#{record}'"] # id, klass
37
+ sqlized += columns.map { |c| "'#{attrs[c]}'" } # model's attributes
38
+ db.execute("INSERT INTO #{store} VALUES(#{sqlized.join(', ')})")
39
+ end
40
+
41
+ def load_records
42
+ records = []
43
+ Dir.glob(path_pattern) do |filepath|
44
+ klass = get_class_from_file(filepath)
45
+ if klass
46
+ require filepath
47
+ records << klass
48
+ end
49
+ end
50
+ records
51
+ end
52
+
53
+ def get_class_from_file(filepath)
54
+ klass = nil
55
+ File.open(filepath) do |file|
56
+ match = file.grep(/class\s+([a-zA-Z0-9_]+)/)
57
+ klass = match.first.chomp.gsub(/class\s+/, '').split(' ')[0] if match
58
+ end
59
+ klass
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,3 @@
1
1
  module StaticRecord
2
- VERSION = '1.0.0.pre'.freeze
2
+ VERSION = '1.0.0.pre.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: static-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre
4
+ version: 1.0.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hugo Chevalier
@@ -99,17 +99,17 @@ files:
99
99
  - app/assets/stylesheets/static_record/application.css
100
100
  - app/controllers/static_record/application_controller.rb
101
101
  - app/helpers/static_record/application_helper.rb
102
- - app/models/concerns/query_building_concern.rb
103
- - app/models/concerns/sqlite_storing_concern.rb
104
- - app/models/static_record/base.rb
105
- - app/models/static_record/predicates.rb
106
- - app/models/static_record/querying.rb
107
- - app/models/static_record/relation.rb
108
102
  - app/views/layouts/static_record/application.html.erb
109
103
  - config/routes.rb
110
104
  - lib/static_record.rb
105
+ - lib/static_record/concerns/query_building_concern.rb
106
+ - lib/static_record/concerns/sqlite_storing_concern.rb
111
107
  - lib/static_record/engine.rb
112
108
  - lib/static_record/exceptions.rb
109
+ - lib/static_record/models/base.rb
110
+ - lib/static_record/models/predicates.rb
111
+ - lib/static_record/models/querying.rb
112
+ - lib/static_record/models/relation.rb
113
113
  - lib/static_record/version.rb
114
114
  - lib/tasks/static_record_tasks.rake
115
115
  - spec/models/static_record/base_spec.rb
@@ -1,103 +0,0 @@
1
- # Helps building SQL queries
2
- module QueryBuildingConcern
3
- extend ActiveSupport::Concern
4
-
5
- def build_query
6
- sql = sql_select_from
7
- sql += sql_where unless @where_clauses.empty?
8
- sql += sql_order unless @order_by.empty?
9
- sql += sql_limit_offset if @sql_limit
10
- sql
11
- end
12
-
13
- private
14
-
15
- def sql_select_from
16
- sql = "SELECT #{@columns} FROM #{@table}"
17
- end
18
-
19
- def sql_where
20
- " WHERE #{where_clause_builder}"
21
- end
22
-
23
- def sql_order
24
- ord_sql = ''
25
- @order_by.each do |ord|
26
- ord_sql += ord_sql.empty? ? ' ORDER BY' : ', '
27
- case ord.class.name
28
- when Hash.name
29
- ord_sql += ord.map { |k, v| " #{@table}.#{k.to_s} #{v.to_s.upcase}" }.join(',')
30
- when Array.name
31
- ord_sql += ord.map { |sym| " #{@table}.#{sym.to_s} ASC" }.join(',')
32
- when Symbol.name
33
- ord_sql += " #{@table}.#{ord.to_s} ASC"
34
- when String.name
35
- ord_sql += " #{ord}"
36
- end
37
- end
38
- ord_sql
39
- end
40
-
41
- def sql_limit_offset
42
- sql = " LIMIT #{@sql_limit}"
43
- sql += " OFFSET #{@sql_offset}" if @sql_offset
44
- sql
45
- end
46
-
47
- def where_clause_builder
48
- params = []
49
- @where_clauses.map do |clause|
50
- subquery = clause[:q]
51
- if subquery.is_a?(Hash)
52
- params << where_clause_from_hash(clause, subquery)
53
- elsif subquery.is_a?(String)
54
- params << where_clause_from_string(clause, subquery)
55
- end
56
-
57
- if params.size > 1
58
- joint = clause[:chain] == :or ? 'OR' : 'AND'
59
- params = [params.join(" #{joint} ")]
60
- end
61
- end
62
-
63
- params.first
64
- end
65
-
66
- def where_clause_from_hash(clause, subquery)
67
- parts = subquery.keys.map do |key|
68
- value = subquery[key]
69
- part = ''
70
- if value.is_a?(Array)
71
- # ex: where(name: ['John', 'Jack'])
72
- # use IN operator
73
- value.map! { |v| v =~ /^\d+$/ ? v : "\"#{v}\"" }
74
- inverse = 'NOT ' if clause[:operator] == :not_eq
75
- part = "#{key.to_s} #{inverse}IN (#{value.join(',')})"
76
- else
77
- # ex: where(name: 'John')
78
- # use = operator
79
- inverse = '!' if clause[:operator] == :not_eq
80
- part = "#{key.to_s} #{inverse}= '#{value}'"
81
- end
82
- end
83
- parts.join(' AND ')
84
- end
85
-
86
- def where_clause_from_string(clause, subquery)
87
- final_string = subquery
88
- if clause[:parameters].is_a?(Array)
89
- # Anon parameters
90
- # ex: where("name = ? OR name = ?", 'John', 'Jack')
91
- clause[:parameters].each do |param|
92
- final_string.sub!(/\?/, "\"#{param}\"")
93
- end
94
- elsif clause[:parameters].is_a?(Hash)
95
- # Named parameters (placeholder condition)
96
- # ex: where("name = :one OR name = :two", one: 'John', two: 'Smith')
97
- clause[:parameters].each do |key, value|
98
- final_string.sub!(":#{key}", "\"#{value}\"")
99
- end
100
- end
101
- final_string
102
- end
103
- end
@@ -1,61 +0,0 @@
1
- # Reads ruby files whose path matches path pattern and store them
2
- # as records in an SQLite3 database
3
- module SqliteStoringConcern
4
- extend ActiveSupport::Concern
5
-
6
- module ClassMethods # :nodoc:
7
- def create_store
8
- columns = class_variable_get(:@@_columns)
9
- begin
10
- dbname = Rails.root.join('db', "static_#{store}.sqlite3").to_s
11
- SQLite3::Database.new(dbname)
12
- db = SQLite3::Database.open(dbname)
13
- db.execute("DROP TABLE IF EXISTS #{store}")
14
- create_table(db, columns)
15
- load_records.each_with_index do |record, index|
16
- insert_into_database(db, record, index, columns)
17
- end
18
- rescue SQLite3::Exception => e
19
- puts 'Exception occurred', e
20
- ensure
21
- db.close if db
22
- end
23
- end
24
-
25
- private
26
-
27
- def create_table(db, columns)
28
- cols = columns.map { |c| c.to_s + ' TEXT' }.join(', ')
29
- sql = "CREATE TABLE #{store}(id INTEGER PRIMARY KEY, klass TEXT, #{cols})"
30
- db.execute(sql)
31
- end
32
-
33
- def insert_into_database(db, record, index, columns)
34
- attrs = record.constantize.new.attributes
35
- sqlized = [index.to_s, "'#{record}'"] # id, klass
36
- sqlized += columns.map { |c| "'#{attrs[c]}'" } # model's attributes
37
- db.execute("INSERT INTO #{store} VALUES(#{sqlized.join(', ')})")
38
- end
39
-
40
- def load_records
41
- records = []
42
- Dir.glob(path_pattern) do |filepath|
43
- klass = get_class_from_file(filepath)
44
- if klass
45
- require filepath
46
- records << klass
47
- end
48
- end
49
- records
50
- end
51
-
52
- def get_class_from_file(filepath)
53
- klass = nil
54
- File.open(filepath) do |file|
55
- match = file.grep(/class\s+([a-zA-Z0-9_]+)/)
56
- klass = match.first.chomp.gsub(/class\s+/, '').split(' ')[0] if match
57
- end
58
- klass
59
- end
60
- end
61
- end