activequery 0.1.0 → 0.2.0

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
  SHA256:
3
- metadata.gz: 604df6bd427cfff0873ed44e5812adf4fc61584a6c51dbba5ec92fb18f5cac11
4
- data.tar.gz: 3b99b1b2cc2b17bbaefcda6e89666dffa5ef9c99b68b6484012318e60cf6a6cb
3
+ metadata.gz: 72acf6bff5b58b74b7738ac87e50ca9aa520e4186a3d46b85294fc7671e5bce0
4
+ data.tar.gz: c6dd9784750fa6d6f8cefbe24bc5333c79b8e3d5a063a27f5f5acdbff89b832d
5
5
  SHA512:
6
- metadata.gz: ce0c3882bd16c514e661ce1942f2f028754e2a1995766a71da3080abfd50ce465619822b853a56b7e7186529cc90870590b70e1b5dc4d54dadc76f915461e958
7
- data.tar.gz: 35321a4999149a389919979d7f8363a786bd6f94a7d0fe825b8d36a70ecb8aff3394207fab5969967ee17c2e5ad41e335c937efaf78bd62f4c89015b76647836
6
+ metadata.gz: 86eaede33b0564252eef9216bdee12f9e62a5ee23417281ffa7aff6326fcd521545dcd2b3670ee9c5f38a0df9a4c891aaa8f80aa934eb4f96d46c3821f23f52b
7
+ data.tar.gz: 3e7423324da0a9733c87ee8b545b4852f1b20988b170fc1fb3a8aecc519b97d951aefccab7c4ed82fc805866cc25b70a92f52882af480f8819bd7de7970813f6
data/Gemfile.lock CHANGED
@@ -1,13 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activequery (0.1.0)
4
+ activequery (0.2.0)
5
5
  strscan (~> 1.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
+ benchmark-memory (0.1.2)
11
+ memory_profiler (~> 0.9)
10
12
  coderay (1.1.2)
13
+ memory_profiler (0.9.14)
11
14
  method_source (0.9.2)
12
15
  minitest (5.11.3)
13
16
  pg (1.1.4)
@@ -22,6 +25,7 @@ PLATFORMS
22
25
 
23
26
  DEPENDENCIES
24
27
  activequery!
28
+ benchmark-memory (~> 0.1.2)
25
29
  bundler (~> 1.17)
26
30
  minitest (~> 5.0)
27
31
  pg (~> 1.0)
data/README.md CHANGED
@@ -2,19 +2,28 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/mtunjic/activequery.svg?branch=master)](https://travis-ci.org/mtunjic/activequery)
4
4
  [![Gem Version](https://badge.fury.io/rb/activequery.svg)](https://badge.fury.io/rb/activequery)
5
+ [![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip)
5
6
 
6
- ### SQL & ruby
7
- Ideal for reports, large queries, separating SQL from code logic, command and query responsibility segregation (CQRS)
7
+
8
+ ### SQL & Ruby
9
+ Ideal for reports, large queries, separating SQL from code logic,
10
+ query optimization, command and query responsibility segregation (CQRS)
8
11
 
9
12
  > Ruby is a great language for writing DSLs, but we don't need a new one. SQL is already a mature DSL.
10
13
  > (Don't agree? Wait until this extra syntax layer breaks down and you start wrestling with a (raw-sql) function.)
11
14
  > ~ Kris Jenkins (yesql)
12
15
 
13
16
  ```SQL
14
- -- name: users_by_country
15
- SELECT *
16
- FROM users
17
- WHERE country_code = :country_code
17
+ -- name: find_product
18
+ -- example with params
19
+ SELECT * FROM products
20
+ WHERE units_in_stock > :units
21
+ AND product_name LIKE ':name';
22
+
23
+ -- name: insert_category
24
+ INSERT INTO categories (category_id, category_name, description)
25
+ VALUES(<%= rand 248...599 %>, 'books', 'ruby books');
26
+
18
27
  ```
19
28
 
20
29
  ```ruby
@@ -82,6 +91,21 @@ end
82
91
  - [ ] Generate CRUD
83
92
 
84
93
 
94
+ ## Dev Notes:
95
+ ```console
96
+ # create demo database (sudo su postgres)
97
+ rake db:create
98
+ rake db:import
99
+ rake db:drop
100
+
101
+ # tests
102
+ rake test:unit
103
+ rake test:integration
104
+ rake test:system
105
+ rake test:bench
106
+ ```
107
+
108
+
85
109
  ## Contributing
86
110
 
87
111
  Bug reports and pull requests are welcome on GitHub at https://github.com/mtunjic/activequery.
data/Rakefile CHANGED
@@ -1,19 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
8
- end
4
+ FileList["lib/tasks/*.rake"].each { |f| load f }
9
5
 
10
- namespace :active_query do
11
- desc "Create config file for Rails"
12
- task :setup do
13
- rails_initializer_path = 'config/initializers/active_query.rb'
14
- open(rails_initializer_path, 'w') { |f| f << "This file contains great truths.\n" }
15
- puts 'The config file is created to config/initializers.'
16
- end
17
- end
18
-
19
- task :default => :test
6
+ task :default => "test:unit"
data/activequery.gemspec CHANGED
@@ -41,13 +41,13 @@ Gem::Specification.new do |spec|
41
41
 
42
42
 
43
43
  spec.add_runtime_dependency 'strscan', '~> 1.0'
44
-
44
+ #spec.add_runtime_dependency 'zscan', '~> 2.0.5'
45
45
 
46
46
  spec.add_development_dependency "bundler", "~> 1.17"
47
47
  spec.add_development_dependency "rake", "~> 10.0"
48
48
  spec.add_development_dependency "minitest", "~> 5.0"
49
49
  spec.add_development_dependency "pry"
50
50
  spec.add_development_dependency 'pg', '~> 1.0'
51
-
52
-
51
+ spec.add_development_dependency 'benchmark-memory', '~> 0.1.2'
52
+
53
53
  end
data/lib/active_query.rb CHANGED
@@ -32,6 +32,16 @@ module ActiveQuery
32
32
  PostgresqlAdapter.open(con_str) { |c| c.exec(query) }
33
33
  end
34
34
 
35
+ def self.run_params(query, params)
36
+ if query.is_a? Symbol
37
+ query = self.send(query)
38
+ end
39
+ con_str = ActiveQuery.config.connection
40
+ PostgresqlAdapter.open(con_str) do |conn|
41
+ conn.exec_params(query, params)
42
+ end
43
+ end
44
+
35
45
  # async_exec(sql) {|pg_result| block }
36
46
  # This function has the same behavior as sync_exec, but is implemented using the
37
47
  # asynchronous command processing API of libpq.
@@ -51,19 +61,6 @@ module ActiveQuery
51
61
  end
52
62
  end
53
63
 
54
- def self.reload!
55
- #t = ActiveQuery::SQLTemplate.new(ActiveQuery.config)
56
- t = ActiveQuery::SQLTemplate.new(self.config)
57
- t.load!
58
- t.templates.each do |qname, query|
59
- define_singleton_method("#{qname}") do
60
- query
61
- end
62
- end
63
- rescue ApplicationError => err
64
- $stderr.puts "%p ::SQLTemplate.load! %s" % [ err.class, err.message ]
65
- end
66
-
67
64
  # WIP Init config
68
65
  require "active_query/config"
69
66
  include ActiveQuery::Config
@@ -72,9 +69,10 @@ module ActiveQuery
72
69
  puts "Loading SQL templates from #{self.config.template_path}"
73
70
  t = ActiveQuery::SQLTemplate.new(self.config)
74
71
  t.load!
75
- t.templates.each do |qname, query|
76
- define_singleton_method("#{qname}") do
77
- query
72
+
73
+ t.templates.each do |query|
74
+ define_singleton_method(:"#{query.name}") do |params=nil|
75
+ query.query
78
76
  end
79
77
  end
80
78
 
@@ -82,7 +80,5 @@ module ActiveQuery
82
80
  rescue ApplicationError => err
83
81
  $stderr.puts "%p ::SQLTemplate.load! %s" % [ err.class, err.message ]
84
82
 
85
- end
86
-
87
-
88
83
 
84
+ end
@@ -7,9 +7,13 @@ module ActiveQuery
7
7
  @connection = connection
8
8
  end
9
9
 
10
- def exec(param)
10
+ def exec(conn)
11
11
  raise "Not implemented"
12
12
  end
13
+
14
+ def exec_params(params)
15
+ raise "Not implemented"
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -11,7 +11,7 @@ module ActiveQuery
11
11
  yield(conn)
12
12
  rescue PG::Error => err
13
13
  $stderr.puts "%p PgConn::open: %s" % [ err.class, err.message ]
14
- conn.reset
14
+ conn.reset if conn
15
15
  ensure
16
16
  conn.close if conn
17
17
  end
@@ -1,6 +1,6 @@
1
1
  module ActiveQuery
2
2
  module SQLParser
3
-
3
+
4
4
  require 'strscan'
5
5
  class SyntaxError < StandardError; end
6
6
 
@@ -9,35 +9,63 @@ module ActiveQuery
9
9
  WHITESPACE = /\s+/
10
10
  NAME = /^\s*--\s*name\s*:\s*(.+)/
11
11
  END_QUERY = /;/
12
+ PARAMS = /\(\:\s*([^)]+?)\s*\)/
13
+ ALL_COMMENTS = /(?-m:--.*)|(?m:--\*.--?\*\/)/
14
+ PARAM = /:\w+/
12
15
 
13
- def self.parse_file(text)
14
- @scanner = StringScanner.new(text)
16
+ def self.parse_query(query)
17
+ @scanner = StringScanner.new(query)
15
18
  @line = 0
16
- @queries = []
19
+ @query = Query.new
17
20
 
18
21
  until @scanner.eos? || @scanner.check_until(END_QUERY).nil?
19
22
  @line += 1
20
- @queries << parse_line
23
+ parse_line
21
24
  end
22
- @queries
25
+ @query.query = make_params(@query.query, @query.params)
26
+ @query
23
27
  end
24
28
 
25
29
  private
26
30
  def self.parse_line
27
- @scanner.skip(NAME)
31
+ @query.params = []
28
32
 
33
+ # Query name match: --name
34
+ @scanner.skip(NAME)
29
35
  qname = @scanner.captures
30
36
  if qname
31
- qname = qname.first
37
+ @query.name = qname.first
32
38
  else
33
39
  fail SyntaxError, "error on line #{@line} (pos. #{@scanner.pos})"
34
40
  end
35
41
 
36
- query = @scanner.scan_until(END_QUERY)
37
- unless query
38
- fail SyntaxError, "error on line #{@line} (pos. #{@scanner.pos})"
42
+ @query.query = @scanner.rest
43
+ fail SyntaxError unless @query.query
44
+
45
+ # All params
46
+ until @scanner.check_until(PARAM).nil?
47
+ @scanner.scan_until(PARAM)
48
+ @query.params.push @scanner.matched
49
+ end
50
+
51
+ # End of query match: ;
52
+ @scanner.scan_until(END_QUERY)
53
+ end
54
+
55
+ # and this only work for postgres - split transform from struct
56
+ def self.make_params(query, params)
57
+ if params && query
58
+ params.each_with_index do |param, i|
59
+ pos = "$#{i+1}"
60
+ query.gsub!(param, pos)
61
+ end
62
+ query.strip if query
63
+ else
64
+ query.strip if query
39
65
  end
40
- Query.new(qname, "", "", query)
41
66
  end
67
+
68
+
42
69
  end
43
70
  end
71
+
@@ -15,7 +15,7 @@ module ActiveQuery
15
15
 
16
16
  def initialize(config = Configuration.new)
17
17
  @config = config
18
- @templates = {}
18
+ @templates = []
19
19
  end
20
20
 
21
21
  def load!
@@ -25,18 +25,14 @@ module ActiveQuery
25
25
  else
26
26
  Find.find(template_path) do |path|
27
27
  if File.basename(path) =~ /sql$/
28
- parse_sql(path)
28
+ @templates << parse_sql(path)
29
29
  end
30
30
  end
31
31
  end
32
32
  end
33
33
 
34
34
  def templates
35
- @templates ||= Hash.new
36
- end
37
-
38
- def self.get(query)
39
- @templates[query.to_s]
35
+ @templates ||= []
40
36
  end
41
37
 
42
38
  private
@@ -46,8 +42,7 @@ module ActiveQuery
46
42
 
47
43
  def parse_sql(path)
48
44
  sql_template = read_sql_file(path: path)
49
- sql = ActiveQuery::SQLParser.parse_file(sql_template)
50
- sql.each {|q| @templates[q.name] = q.query.strip }
45
+ ActiveQuery::SQLParser.parse_query(sql_template)
51
46
  end
52
47
 
53
48
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveQuery
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/tasks/db.rake ADDED
@@ -0,0 +1,33 @@
1
+ namespace :db do
2
+ desc "Create test database "
3
+ task :create do
4
+ # or createuser --interactive joe
5
+ sh "sudo su postgres"
6
+ sh "dropdb --if-exists northwind"
7
+ sh "dropuser --if-exists northwind_user"
8
+ sh "createdb northwind"
9
+ puts 'The demo db is created.'
10
+ end
11
+
12
+ desc "Import data "
13
+ task :import do
14
+ cmds = %q{
15
+ psql northwind < ./test/integration/northwind/northwind.sql
16
+
17
+ psql --no-psqlrc template1 -c "create user northwind_user;"
18
+ psql --no-psqlrc template1 -c "alter user northwind_user password 'thewindisblowing';"
19
+ psql --no-psqlrc template1 -c "grant all on DATABASE northwind to northwind_user;"
20
+ psql --no-psqlrc northwind -c "GRANT ALL on ALL tables IN SCHEMA public to northwind_user"
21
+ }
22
+ sh cmds
23
+ puts 'The northwind db is imported.'
24
+ end
25
+
26
+ desc "Drop test database "
27
+ task :drop do
28
+ sh "dropdb --if-exists northwind"
29
+ sh "dropuser --if-exists northwind_user"
30
+ puts 'The demo db is droped.'
31
+ end
32
+
33
+ end
@@ -0,0 +1,31 @@
1
+ namespace :test do
2
+
3
+ desc "Run unit tests"
4
+ Rake::TestTask.new(:unit) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/*_test.rb"]
8
+ end
9
+
10
+ desc "Run system tests"
11
+ Rake::TestTask.new(:system) do |t|
12
+ t.libs << "test"
13
+ t.libs << "lib"
14
+ t.test_files = FileList["test/system/*_test.rb"]
15
+ end
16
+
17
+ desc "Run integration tests"
18
+ Rake::TestTask.new(:integration) do |t|
19
+ t.libs << "test"
20
+ t.libs << "lib"
21
+ t.test_files = FileList["test/integration/*_test.rb"]
22
+ end
23
+
24
+ desc "Run benchmark"
25
+ Rake::TestTask.new(:bench) do |t|
26
+ t.libs << "test"
27
+ t.libs << "lib"
28
+ t.test_files = FileList["test/benchmark/*_bench.rb"]
29
+ end
30
+
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activequery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-05 00:00:00.000000000 Z
11
+ date: 2019-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strscan
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: benchmark-memory
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.1.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.1.2
97
111
  description: Raw sql with ruby - ideal for reports, large queries, separating SQL
98
112
  from code logic and CQRS
99
113
  email:
@@ -123,6 +137,8 @@ files:
123
137
  - lib/active_query/sql_renderer.rb
124
138
  - lib/active_query/sql_template.rb
125
139
  - lib/active_query/version.rb
140
+ - lib/tasks/db.rake
141
+ - lib/tasks/test.rake
126
142
  homepage: https://github.com/mtunjic/activequery
127
143
  licenses:
128
144
  - MIT