dumbo 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +61 -0
  6. data/Rakefile +9 -0
  7. data/bin/dumbo +58 -0
  8. data/config/boot.rb +15 -0
  9. data/config/database.yml +31 -0
  10. data/dumbo.gemspec +31 -0
  11. data/lib/dumbo.rb +21 -0
  12. data/lib/dumbo/aggregate.rb +57 -0
  13. data/lib/dumbo/base_type.rb +71 -0
  14. data/lib/dumbo/cast.rb +49 -0
  15. data/lib/dumbo/composite_type.rb +31 -0
  16. data/lib/dumbo/db_task.rb +57 -0
  17. data/lib/dumbo/dependency_resolver.rb +105 -0
  18. data/lib/dumbo/enum_type.rb +28 -0
  19. data/lib/dumbo/extension.rb +73 -0
  20. data/lib/dumbo/extension_migrator.rb +66 -0
  21. data/lib/dumbo/extension_version.rb +25 -0
  22. data/lib/dumbo/function.rb +101 -0
  23. data/lib/dumbo/operator.rb +74 -0
  24. data/lib/dumbo/pg_object.rb +80 -0
  25. data/lib/dumbo/rake_task.rb +121 -0
  26. data/lib/dumbo/range_type.rb +43 -0
  27. data/lib/dumbo/type.rb +31 -0
  28. data/lib/dumbo/version.rb +3 -0
  29. data/lib/tasks/db.rake +52 -0
  30. data/lib/tasks/dumbo.rake +23 -0
  31. data/spec/Makefile +6 -0
  32. data/spec/aggregate_spec.rb +41 -0
  33. data/spec/cast_spec.rb +20 -0
  34. data/spec/dumbo_sample--0.0.1.sql +5 -0
  35. data/spec/dumbo_sample--0.0.2.sql +5 -0
  36. data/spec/dumbo_sample.control +5 -0
  37. data/spec/extension_migrator_spec.rb +40 -0
  38. data/spec/extension_spec.rb +19 -0
  39. data/spec/operator_spec.rb +42 -0
  40. data/spec/spec_helper.rb +28 -0
  41. data/spec/support/sql_helper.rb +23 -0
  42. data/spec/type_spec.rb +95 -0
  43. data/template/Gemfile +3 -0
  44. data/template/Makefile.erb +6 -0
  45. data/template/Rakefile +15 -0
  46. data/template/config/database.yml.erb +31 -0
  47. data/template/spec/sample_spec.rb.erb +13 -0
  48. data/template/sql/sample.sql +5 -0
  49. metadata +230 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8c38d6d2545804ea840a234c51c3d912fc2988a3
4
+ data.tar.gz: a1ace87c6b8469126e95a1eb94f9a503bcd93483
5
+ SHA512:
6
+ metadata.gz: 6043bb12bfee32add950dd79093d41c3ea70732028749ccf8db79413d2e2219e8b3d5b197695255c4cba3d24ce4e38b3e3a2bdfc83522095ba9b85466fbf4623
7
+ data.tar.gz: ac5757b0c2dee69ecd5c0d962d3e0f4557b1937b5c08f63c0d3d3210134ef11975803a675e01f2770df35e250865e1331404577a42b246d8043406492394c778
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dumbo.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Manuel Kniep
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # Dumbo
2
+
3
+ postgres extension with fun
4
+
5
+ ![](http://img1.wikia.nocookie.net/__cb20091210033559/disney/images/7/76/Dumbo-HQ.JPG)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'dumbo'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dumbo
20
+
21
+ ## Getting Started
22
+
23
+ At the command prompt, create a new extension:
24
+
25
+ dumbo new myextention
26
+
27
+ where "myextention" is the extension name.
28
+
29
+ Change directory to myextention to start hacking:
30
+
31
+ cd myapp
32
+
33
+ As a stating point take a look at the sample function in
34
+
35
+ sql/sample.sql
36
+
37
+ and the corresponding test file
38
+
39
+ spec/sample_spec.rb
40
+
41
+ build the extension and run the specs
42
+
43
+ rake
44
+
45
+ if you start working on a new version run
46
+
47
+ rake dumbo:new_version [level]
48
+
49
+ where level is new version level (major, minor patch)
50
+
51
+ when you are done you can create the migration files with
52
+
53
+ rake dumbo:migrations
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it ( http://github.com/adeven/dumbo/fork )
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create new Pull Request
@@ -0,0 +1,9 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'dumbo/db_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ Dumbo::DbTask.new(:db)
8
+
9
+ task :default => ['db:test:prepare', :spec]
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require 'thor'
3
+ require 'thor/group'
4
+ require 'erubis'
5
+ require 'fileutils'
6
+
7
+ module Cli
8
+ class Dumbo < Thor
9
+
10
+ desc "new name", "creates a new extension skeleton"
11
+
12
+ def new(name, initial_version='0.0.1')
13
+ FileUtils.mkdir_p("#{name}/sql")
14
+ FileUtils.mkdir_p("#{name}/src")
15
+ FileUtils.mkdir_p("#{name}/spec/support")
16
+ FileUtils.mkdir_p("#{name}/config")
17
+ FileUtils.mkdir_p("#{name}/lib/tasks")
18
+
19
+ spec_helper = Dir.glob(File.expand_path('../../spec/spec_helper.rb', __FILE__))
20
+ spec_helper += Dir.glob(File.expand_path('../../spec/support', __FILE__))
21
+
22
+ FileUtils.cp_r spec_helper, "#{name}/spec/"
23
+
24
+ FileUtils.cp File.expand_path('../../config/boot.rb', __FILE__), "#{name}/config/"
25
+
26
+ template_path = File.expand_path('../../template', __FILE__)
27
+
28
+ Dir.glob(File.expand_path('../../template/**/*', __FILE__)).each do |template|
29
+ pathname = Pathname.new(template)
30
+ dest_name = pathname.relative_path_from Pathname.new(template_path)
31
+
32
+ if pathname.directory?
33
+ FileUtils.mkdir_p("#{name}/#{dest_name}")
34
+ next
35
+ end
36
+
37
+ if dest_name.extname =='.erb'
38
+ eruby = Erubis::Eruby.new(File.read(template))
39
+ File.open("#{name}/#{dest_name.sub_ext('')}",'w') do |f|
40
+ f.puts eruby.result({ext_name: name})
41
+ end
42
+ else
43
+ FileUtils.cp template, "#{name}/#{dest_name}"
44
+ end
45
+ end
46
+
47
+ File.open("#{name}/#{name}.control",'w') do |f|
48
+ f.puts "# #{name} extension"
49
+ f.puts "comment = 'my awesome extension'"
50
+ f.puts "default_version = '#{initial_version}'"
51
+ f.puts "relocatable = true"
52
+ f.puts "requires = ''"
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ Cli::Dumbo.start(ARGV)
@@ -0,0 +1,15 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
+ ENV['DUMBO_ENV'] ||= 'development'
6
+
7
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
8
+ Bundler.require(:default, ENV['DUMBO_ENV'].to_sym)
9
+
10
+ def db_config
11
+ @config ||= YAML.load_file('config/database.yml')
12
+ end
13
+
14
+
15
+ ActiveRecord::Base.establish_connection db_config[ENV['DUMBO_ENV']]
@@ -0,0 +1,31 @@
1
+ # general postgres settings
2
+ # Connect on a TCP socket. Omitted by default since the client uses a
3
+ # domain socket that doesn't need configuration. Windows does not have
4
+ # domain sockets, so uncomment these lines.
5
+ # host: localhost
6
+ # port: 5432
7
+
8
+ # Schema search path. The server defaults to $user,public
9
+ # schema_search_path: myapp,sharedapp,public
10
+
11
+ # Minimum log levels, in increasing order:
12
+ # debug5, debug4, debug3, debug2, debug1,
13
+ # log, notice, warning, error, fatal, and panic
14
+ # The server defaults to notice.
15
+ # min_messages: warning
16
+
17
+ postgres: &postgres
18
+ adapter: postgresql
19
+ encoding: utf8
20
+ pool: 5
21
+ username: postgres
22
+ password:
23
+ host: localhost
24
+
25
+ development:
26
+ <<: *postgres
27
+ database: dumbo_development
28
+
29
+ test:
30
+ <<: *postgres
31
+ database: dumbo_test
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dumbo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dumbo"
8
+ spec.version = Dumbo::VERSION
9
+ spec.authors = ["Manuel Kniep"]
10
+ spec.email = ["m.kniep@web.de"]
11
+ spec.summary = %q{postgres extension with fun}
12
+ spec.homepage = "https://github.com/adjust/dumbo"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "rake"
21
+ spec.add_dependency 'erubis'
22
+ spec.add_dependency 'rspec', '~> 2.14.0'
23
+ spec.add_dependency'factory_girl', '~> 4.0'
24
+ spec.add_dependency 'activerecord'
25
+ spec.add_dependency 'pg', '> 0.17'
26
+
27
+ spec.add_dependency 'thor'
28
+ spec.add_dependency 'activesupport'
29
+
30
+ spec.add_dependency "bundler", "~> 1.5"
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_record'
2
+ require "dumbo/version"
3
+ require "dumbo/pg_object"
4
+ require "dumbo/type"
5
+ require "dumbo/function"
6
+ require "dumbo/cast"
7
+ require "dumbo/base_type"
8
+ require "dumbo/aggregate"
9
+ require "dumbo/composite_type"
10
+ require "dumbo/dependency_resolver"
11
+ require "dumbo/enum_type"
12
+ require "dumbo/extension"
13
+ require "dumbo/extension_migrator"
14
+ require "dumbo/extension_version"
15
+ require "dumbo/operator"
16
+ require "dumbo/range_type"
17
+ require "dumbo/version"
18
+
19
+ module Dumbo
20
+ # Your code goes here...
21
+ end
@@ -0,0 +1,57 @@
1
+ module Dumbo
2
+ class Aggregate < PgObject
3
+ attr_accessor :name, :sfunc, :transname, :ffunc, :input_data_type, :state_data_type,
4
+ :initial_condition, :sort_operator
5
+
6
+ def load_attributes
7
+ result = execute <<-SQL
8
+ SELECT
9
+ proname AS name,
10
+ pg_get_function_arguments(pr.oid) AS input_data_type,
11
+ aggtransfn AS sfunc,
12
+ aggfinalfn AS ffunc,
13
+ agginitval AS initial_condition,
14
+ op.oprname AS sort_operator,
15
+ proargtypes,
16
+ aggtranstype AS state_data_type , proacl,
17
+ CASE WHEN (tt.typlen = -1 AND tt.typelem != 0) THEN (SELECT at.typname FROM pg_type at WHERE at.oid = tt.typelem) || '[]' ELSE tt.typname END as state_data_type,
18
+ prorettype AS aggfinaltype,
19
+ --CASE WHEN (tf.typlen = -1 AND tf.typelem != 0) THEN (SELECT at.typname FROM pg_type at WHERE at.oid = tf.typelem) || '[]' ELSE tf.typname END as ffunc,
20
+ description,
21
+ (SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=aggfnoid) AS labels,
22
+ (SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=aggfnoid) AS providers, oprname, opn.nspname as oprnsp
23
+ FROM pg_aggregate ag
24
+ LEFT OUTER JOIN pg_operator op ON op.oid=aggsortop
25
+ LEFT OUTER JOIN pg_namespace opn ON opn.oid=op.oprnamespace
26
+ JOIN pg_proc pr ON pr.oid = ag.aggfnoid
27
+ JOIN pg_type tt on tt.oid=aggtranstype
28
+ JOIN pg_type tf on tf.oid=prorettype
29
+ LEFT OUTER JOIN pg_description des ON (des.objoid=aggfnoid::oid AND des.classoid='pg_aggregate'::regclass)
30
+ WHERE aggfnoid = #{oid}
31
+ SQL
32
+
33
+ result.first.each do |k,v|
34
+ send("#{k}=",v) rescue nil
35
+ end
36
+
37
+ result.first
38
+ end
39
+
40
+
41
+ def to_sql
42
+ attributes = []
43
+ attributes << "SFUNC = #{sfunc}"
44
+ attributes << "STYPE = #{state_data_type}"
45
+ attributes << "FINALFUNC = #{ffunc}" if ffunc && ffunc != '-'
46
+ attributes << "INITCOND = '#{initial_condition}'" if initial_condition
47
+ attributes << "SORTOP = #{sort_operator}" if sort_operator
48
+
49
+ <<-SQL.gsub(/^ {6}/, '')
50
+ CREATE AGGREGATE #{name}(#{input_data_type}) (
51
+ #{attributes.join(",\n ")}
52
+ );
53
+ SQL
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,71 @@
1
+ module Dumbo
2
+ class BaseType < Type
3
+ attr_accessor :input_function,
4
+ :output_function,
5
+ :receive_function,
6
+ :send_function,
7
+ :analyze_function,
8
+ :category,
9
+ :default,
10
+ :alignment,
11
+ :storage,
12
+ :type,
13
+ :internallength,
14
+ :attribute_name,
15
+ :typrelid
16
+
17
+ def load_attributes
18
+ sql = <<-SQL
19
+ SELECT
20
+ t.typname AS name,
21
+ t.typinput AS input_function,
22
+ t.typoutput AS output_function,
23
+ t.typreceive AS receive_function,
24
+ t.typsend AS send_function,
25
+ t.typanalyze AS analyze_function,
26
+ t.typcategory AS category,
27
+ t.typdefault AS default,
28
+ t.typrelid,
29
+ CASE WHEN t.typalign = 'i' THEN 'int' WHEN t.typalign = 'c' THEN 'char' WHEN t.typalign = 's' THEN 'short' WHEN t.typalign = 'd' THEN 'double' ELSE NULL END AS alignment,
30
+ CASE WHEN t.typstorage = 'p' THEN 'PLAIN' WHEN t.typstorage = 'e' THEN 'EXTENDED' WHEN t.typstorage = 'm' THEN 'MAIN' WHEN t.typstorage = 'x' THEN 'EXTENDED' ELSE NULL END AS storage,
31
+ t.typtype AS type,
32
+ t.typlen AS internallength,
33
+ format_type(t.oid, null) AS alias, e.typname as element,
34
+ description, ct.oid AS taboid,
35
+ (SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=t.oid) AS labels,
36
+ (SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=t.oid) AS providers
37
+ FROM pg_type t
38
+ LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
39
+ LEFT OUTER JOIN pg_class ct ON ct.oid = t.typrelid AND ct.relkind <> 'c'
40
+ LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
41
+ WHERE t.typtype != 'd' AND t.typnamespace = 2200::oid
42
+ AND ct.oid IS NULL
43
+ AND t.oid = #{oid}
44
+ SQL
45
+
46
+ result = execute sql
47
+ result.first.each do |k,v|
48
+ send("#{k}=",v) rescue nil
49
+ end
50
+
51
+ result.first
52
+ end
53
+
54
+ def to_sql
55
+ <<-SQL.gsub(/^ {8}/, '')
56
+ CREATE TYPE #{name}(
57
+ INPUT=#{input_function},
58
+ OUTPUT=#{output_function},
59
+ RECEIVE=#{receive_function},
60
+ SEND=#{send_function},
61
+ ANALYZE=#{analyze_function},
62
+ CATEGORY='#{category}',
63
+ DEFAULT='#{default}',
64
+ INTERNALLENGTH=#{internallength},
65
+ ALIGNMENT=#{alignment},
66
+ STORAGE=#{storage}
67
+ );
68
+ SQL
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,49 @@
1
+ module Dumbo
2
+ class Cast < PgObject
3
+ attr_accessor :source_type, :target_type, :function_name, :argument_type, :context
4
+ identfied_by :source_type, :target_type
5
+
6
+ def load_attributes
7
+ result = execute <<-SQL
8
+ SELECT
9
+ format_type(st.oid,NULL) AS source_type,
10
+ format_type(st.oid,NULL) AS argument_type,
11
+ format_type(tt.oid,tt.typtypmod) AS target_type,
12
+ proname AS function_name,
13
+ CASE WHEN ca.castcontext = 'e' THEN NULL
14
+ WHEN ca.castcontext = 'a' THEN 'ASSIGNMENT'
15
+ ELSE 'IMPLICIT'
16
+ END AS context
17
+
18
+ FROM pg_cast ca
19
+ JOIN pg_type st ON st.oid=castsource
20
+ JOIN pg_type tt ON tt.oid=casttarget
21
+ LEFT JOIN pg_proc pr ON pr.oid=castfunc
22
+ LEFT OUTER JOIN pg_description des ON (des.objoid=ca.oid AND des.objsubid=0 AND des.classoid='pg_cast'::regclass)
23
+ WHERE ca.oid = #{oid}
24
+ SQL
25
+
26
+ result.first.each do |k,v|
27
+ send("#{k}=",v) rescue nil
28
+ end
29
+
30
+ result.first
31
+ end
32
+
33
+ def drop
34
+ "DROP CAST (#{source_type} AS #{target_type})"
35
+ end
36
+
37
+ def to_sql
38
+ attributes = []
39
+ attributes << "WITH FUNCTION #{function_name}(#{source_type})" if function_name
40
+ attributes << "WITHOUT FUNCTION" unless function_name
41
+ attributes << context if context
42
+
43
+ <<-SQL.gsub(/^ {6}/, '')
44
+ CREATE CAST (#{source_type} AS #{target_type})
45
+ #{attributes.join("\nAS ")};
46
+ SQL
47
+ end
48
+ end
49
+ end