aliyun-odps 0.1.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +31 -0
- data/Gemfile +3 -0
- data/README.md +55 -12
- data/Rakefile +15 -5
- data/aliyun-odps.gemspec +22 -11
- data/bin/console +10 -3
- data/lib/aliyun/odps.rb +69 -2
- data/lib/aliyun/odps/authorization.rb +90 -0
- data/lib/aliyun/odps/client.rb +40 -0
- data/lib/aliyun/odps/configuration.rb +16 -0
- data/lib/aliyun/odps/error.rb +97 -0
- data/lib/aliyun/odps/http.rb +138 -0
- data/lib/aliyun/odps/list.rb +40 -0
- data/lib/aliyun/odps/model/function.rb +16 -0
- data/lib/aliyun/odps/model/functions.rb +113 -0
- data/lib/aliyun/odps/model/instance.rb +130 -0
- data/lib/aliyun/odps/model/instance_task.rb +30 -0
- data/lib/aliyun/odps/model/instances.rb +119 -0
- data/lib/aliyun/odps/model/projects.rb +73 -0
- data/lib/aliyun/odps/model/resource.rb +26 -0
- data/lib/aliyun/odps/model/resources.rb +144 -0
- data/lib/aliyun/odps/model/table.rb +37 -0
- data/lib/aliyun/odps/model/table_column.rb +13 -0
- data/lib/aliyun/odps/model/table_partition.rb +9 -0
- data/lib/aliyun/odps/model/table_partitions.rb +90 -0
- data/lib/aliyun/odps/model/table_schema.rb +13 -0
- data/lib/aliyun/odps/model/tables.rb +125 -0
- data/lib/aliyun/odps/model/task_result.rb +9 -0
- data/lib/aliyun/odps/modelable.rb +16 -0
- data/lib/aliyun/odps/project.rb +47 -0
- data/lib/aliyun/odps/service_object.rb +27 -0
- data/lib/aliyun/odps/struct.rb +126 -0
- data/lib/aliyun/odps/tunnel/download_session.rb +98 -0
- data/lib/aliyun/odps/tunnel/router.rb +15 -0
- data/lib/aliyun/odps/tunnel/snappy_reader.rb +19 -0
- data/lib/aliyun/odps/tunnel/snappy_writer.rb +45 -0
- data/lib/aliyun/odps/tunnel/table_tunnels.rb +81 -0
- data/lib/aliyun/odps/tunnel/upload_block.rb +9 -0
- data/lib/aliyun/odps/tunnel/upload_session.rb +132 -0
- data/lib/aliyun/odps/utils.rb +102 -0
- data/lib/aliyun/odps/version.rb +1 -1
- data/requirements.png +0 -0
- data/wiki/error.md +188 -0
- data/wiki/functions.md +39 -0
- data/wiki/get_start.md +34 -0
- data/wiki/installation.md +15 -0
- data/wiki/instances.md +32 -0
- data/wiki/projects.md +51 -0
- data/wiki/resources.md +62 -0
- data/wiki/ssl.md +7 -0
- data/wiki/tables.md +75 -0
- data/wiki/tunnels.md +80 -0
- metadata +195 -13
- data/requirements.mindnode/QuickLook/Preview.jpg +0 -0
- data/requirements.mindnode/contents.xml +0 -10711
- data/requirements.mindnode/viewState.plist +0 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class TablePartitions < ServiceObject
|
4
|
+
# List partitions for table
|
5
|
+
#
|
6
|
+
# @see http://repo.aliyun.com/api-doc/Table/get_table_partition/index.html Get table partitions
|
7
|
+
#
|
8
|
+
# @param options [Hash] options
|
9
|
+
# @option options [String] :marker specify marker for paginate
|
10
|
+
# @option options [String] :maxitems (1000) specify maxitems in this request
|
11
|
+
#
|
12
|
+
# @return [List]
|
13
|
+
def list(options = {})
|
14
|
+
Utils.stringify_keys!(options)
|
15
|
+
path = "/projects/#{project.name}/tables/#{master.name}"
|
16
|
+
query = {
|
17
|
+
partitions: true,
|
18
|
+
expectmarker: true
|
19
|
+
}.merge(Utils.hash_slice(options, 'marker', 'maxitems'))
|
20
|
+
|
21
|
+
result = client.get(path, query: query).parsed_response
|
22
|
+
Aliyun::Odps::List.build(result, %w(Partitions Partition)) do |hash|
|
23
|
+
build_table_partition(hash)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create Partition
|
28
|
+
#
|
29
|
+
# @param partition [Hash<name, value>] specify the partition you want to create
|
30
|
+
#
|
31
|
+
# @raise InstanceTaskNotSuccessError if instance task failed
|
32
|
+
#
|
33
|
+
# @return [Hash] the partition you create
|
34
|
+
def create(partition)
|
35
|
+
sql = generate_create_sql(partition)
|
36
|
+
|
37
|
+
task = InstanceTask.new(
|
38
|
+
name: 'SQLCreatePartitionTask',
|
39
|
+
type: 'SQL',
|
40
|
+
query: sql
|
41
|
+
)
|
42
|
+
|
43
|
+
instance = project.instances.create([task])
|
44
|
+
|
45
|
+
instance.wait_for_success
|
46
|
+
|
47
|
+
partition
|
48
|
+
end
|
49
|
+
|
50
|
+
# Delete Partition
|
51
|
+
#
|
52
|
+
# @params partitions [Hash<name, value>] specify the partition you want to delete
|
53
|
+
#
|
54
|
+
# @raise InstanceTaskNotSuccessError if instance task failed
|
55
|
+
#
|
56
|
+
# @return [true]
|
57
|
+
def delete(partition)
|
58
|
+
sql = generate_drop_sql(partition)
|
59
|
+
|
60
|
+
task = InstanceTask.new(
|
61
|
+
name: 'SQLDropPartitionTask',
|
62
|
+
type: 'SQL',
|
63
|
+
query: sql
|
64
|
+
)
|
65
|
+
|
66
|
+
instance = project.instances.create([task])
|
67
|
+
|
68
|
+
instance.wait_for_success
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def generate_create_sql(partition)
|
76
|
+
spec = partition.map { |k, v| "#{k} = '#{v}'" }.join(',')
|
77
|
+
"ALTER TABLE #{project.name}.`#{master.name}` ADD PARTITION (#{spec});"
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_drop_sql(partition)
|
81
|
+
spec = partition.map { |k, v| "#{k} = '#{v}'" }.join(',')
|
82
|
+
"ALTER TABLE #{project.name}.`#{master.name}`DROP IF EXISTS PARTITION (#{spec});"
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_table_partition(hash)
|
86
|
+
Hash[Utils.wrap(hash['Column']).map(&:values)]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class TableSchema < Struct::Base
|
4
|
+
property :columns, Array, init_with: ->(value) do
|
5
|
+
value.map { |v| TableColumn.new(v) }
|
6
|
+
end
|
7
|
+
|
8
|
+
property :partitions, Array, init_with: ->(value) do
|
9
|
+
value.map { |v| TablePartition.new(v) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
# Methods for Tables
|
4
|
+
class Tables < ServiceObject
|
5
|
+
# List tables in this project
|
6
|
+
#
|
7
|
+
# @see http://repo.aliyun.com/api-doc/Table/get_tables/index.html Get tables
|
8
|
+
#
|
9
|
+
# @params options [Hash] options
|
10
|
+
# @option options [String] :name specify the table name
|
11
|
+
# @option options [String] :owner specify the table owner
|
12
|
+
# @option options [String] :marker
|
13
|
+
# @option options [String] :maxitems (1000)
|
14
|
+
def list(options = {})
|
15
|
+
Utils.stringify_keys!(options)
|
16
|
+
path = "/projects/#{project.name}/tables"
|
17
|
+
query = Utils.hash_slice(options, 'name', 'owner', 'marker', 'maxitems')
|
18
|
+
query.merge!(tables: true, expectmarker: true)
|
19
|
+
result = client.get(path, query: query).parsed_response
|
20
|
+
|
21
|
+
Aliyun::Odps::List.build(result, %w(Tables Table)) do |hash|
|
22
|
+
build_table(hash)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get Table
|
27
|
+
#
|
28
|
+
# @see http://repo.aliyun.com/api-doc/Table/get_table/index.html Get Table
|
29
|
+
#
|
30
|
+
# @params name [String] specify the table name
|
31
|
+
def get(name)
|
32
|
+
path = "/projects/#{project.name}/tables/#{name}"
|
33
|
+
resp = client.get(path)
|
34
|
+
|
35
|
+
build_table(
|
36
|
+
Utils.dig_value(resp.parsed_response, 'Table')
|
37
|
+
.merge(
|
38
|
+
'creation_time' => resp.headers['x-odps-creation-time'],
|
39
|
+
'last_modified' => resp.headers['Last-Modified'],
|
40
|
+
'owner' => resp.headers['x-odps-owner']
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
alias_method :table, :get
|
45
|
+
|
46
|
+
# Create Table
|
47
|
+
#
|
48
|
+
# @params name [String] specify table name
|
49
|
+
# @params schema [Struct::TableSchema] specify table schema
|
50
|
+
# @params options [Hash] options
|
51
|
+
# @option options [String] :comment specify table comment
|
52
|
+
#
|
53
|
+
# @raise InstanceTaskNotSuccessError if instance task failed
|
54
|
+
#
|
55
|
+
# @return Table
|
56
|
+
def create(name, schema, options = {})
|
57
|
+
Utils.stringify_keys!(options)
|
58
|
+
table = Table.new(name: name, schema: schema, project: project)
|
59
|
+
table.comment = options['comment'] if options.key?('comment')
|
60
|
+
|
61
|
+
task = InstanceTask.new(name: 'SQLCreateTableTask', type: 'SQL', query: generate_create_sql(table))
|
62
|
+
|
63
|
+
instance = project.instances.create([task])
|
64
|
+
instance.wait_for_success
|
65
|
+
table
|
66
|
+
end
|
67
|
+
|
68
|
+
# Delete Table
|
69
|
+
#
|
70
|
+
# @params name [String]
|
71
|
+
#
|
72
|
+
# @raise InstanceTaskNotSuccessError if instance task failed
|
73
|
+
#
|
74
|
+
# @return true
|
75
|
+
def delete(name)
|
76
|
+
table = Table.new(name: name, project: project)
|
77
|
+
|
78
|
+
task = InstanceTask.new(
|
79
|
+
name: 'SQLDropTableTask',
|
80
|
+
type: 'SQL',
|
81
|
+
query: generate_drop_sql(table)
|
82
|
+
)
|
83
|
+
|
84
|
+
instance = project.instances.create([task])
|
85
|
+
instance.wait_for_success
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def generate_create_sql(table)
|
92
|
+
sql = "CREATE TABLE #{project.name}.`#{table.name}`"
|
93
|
+
sql += generate_table_coumns_sql(table.schema.columns) if table.schema && table.schema.columns
|
94
|
+
sql += " COMMENT '#{table.comment}'" if table.comment
|
95
|
+
sql += generate_table_partitions_sql(table.schema.partitions) if table.schema && table.schema.partitions
|
96
|
+
sql += ';'
|
97
|
+
sql
|
98
|
+
end
|
99
|
+
|
100
|
+
def generate_table_coumns_sql(columns)
|
101
|
+
' (' + columns.map do |column|
|
102
|
+
generate_table_column_sql(column)
|
103
|
+
end.join(', ') + ')'
|
104
|
+
end
|
105
|
+
|
106
|
+
def generate_table_partitions_sql(partitions)
|
107
|
+
' PARTITIONED BY (' + partitions.map do |column|
|
108
|
+
generate_table_column_sql(column)
|
109
|
+
end.join(', ') + ')'
|
110
|
+
end
|
111
|
+
|
112
|
+
def generate_table_column_sql(column)
|
113
|
+
"`#{column.name}` #{column.type}" + (column.comment ? " COMMENT '#{column.comment}'" : '')
|
114
|
+
end
|
115
|
+
|
116
|
+
def generate_drop_sql(table)
|
117
|
+
"DROP TABLE IF EXISTS #{project.name}.`#{table.name}`;"
|
118
|
+
end
|
119
|
+
|
120
|
+
def build_table(result)
|
121
|
+
Table.new(result.merge(project: project))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'aliyun/odps/service_object'
|
3
|
+
|
4
|
+
module Aliyun
|
5
|
+
module Odps
|
6
|
+
module Modelable
|
7
|
+
def has_many(models, _opts = {})
|
8
|
+
mod = models.to_s.singularize
|
9
|
+
klass = "Aliyun::Odps::#{mod.camelize}s".constantize
|
10
|
+
define_method(models) do
|
11
|
+
klass.build(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'aliyun/odps/model/instances'
|
2
|
+
require 'aliyun/odps/model/tables'
|
3
|
+
require 'aliyun/odps/model/functions'
|
4
|
+
require 'aliyun/odps/model/resources'
|
5
|
+
require 'aliyun/odps/tunnel/table_tunnels'
|
6
|
+
require 'aliyun/odps/client'
|
7
|
+
|
8
|
+
module Aliyun
|
9
|
+
module Odps
|
10
|
+
class Project < Struct::Base
|
11
|
+
extend Aliyun::Odps::Modelable
|
12
|
+
|
13
|
+
# @!method instances
|
14
|
+
# @return [Instances]
|
15
|
+
has_many :instances
|
16
|
+
|
17
|
+
# @!method functions
|
18
|
+
# @return [Functions]
|
19
|
+
has_many :functions
|
20
|
+
|
21
|
+
# @!method tables
|
22
|
+
# @return [Tables]
|
23
|
+
has_many :tables
|
24
|
+
|
25
|
+
# @!method resources
|
26
|
+
# @return [Resources]
|
27
|
+
has_many :resources
|
28
|
+
|
29
|
+
# @!method table_tunnels
|
30
|
+
# @return [TableTunnels]
|
31
|
+
has_many :table_tunnels
|
32
|
+
|
33
|
+
property :client, Client, required: true
|
34
|
+
|
35
|
+
property :name, String, required: true
|
36
|
+
property :comment, String
|
37
|
+
property :project_group_name, String
|
38
|
+
property :state, String
|
39
|
+
property :clusters, Hash
|
40
|
+
property :property, String
|
41
|
+
property :properties, Hash
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Dir[File.join(File.dirname(__FILE__), 'model/*.rb')].each { |f| require f }
|
47
|
+
Dir[File.join(File.dirname(__FILE__), 'tunnel/*.rb')].each { |f| require f }
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class ServiceObject
|
4
|
+
def client
|
5
|
+
master.is_a?(Client) ? master : project.client
|
6
|
+
end
|
7
|
+
|
8
|
+
def project
|
9
|
+
@master.is_a?(Project) ? @master : @master.try(:project)
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :master
|
13
|
+
|
14
|
+
def initialize(master, _options = {})
|
15
|
+
@master = master
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.service_pool
|
19
|
+
@service_pool ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.build(master, options = {})
|
23
|
+
service_pool[master] ||= new(master, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
module Struct
|
4
|
+
class Base
|
5
|
+
def initialize(attributes = {})
|
6
|
+
attributes.each do |key, value|
|
7
|
+
m = "#{Utils.underscore(key)}=".to_sym
|
8
|
+
send(m, value) if self.respond_to?(m)
|
9
|
+
end
|
10
|
+
|
11
|
+
validate_required
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_required
|
15
|
+
missing_attrs = []
|
16
|
+
(self.class.required_attrs || []).each do |attr|
|
17
|
+
missing_attrs.push(attr) if send(attr).nil?
|
18
|
+
end
|
19
|
+
fail "Missing attribute: #{missing_attrs.join(',')}" unless missing_attrs.empty?
|
20
|
+
end
|
21
|
+
private :validate_required
|
22
|
+
|
23
|
+
def update_attrs(attrs)
|
24
|
+
attrs.each do |k, v|
|
25
|
+
send("#{Utils.underscore(k)}=", v)
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def client
|
31
|
+
project.client
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
attr_reader :required_attrs
|
36
|
+
|
37
|
+
# @!macro [attach] property
|
38
|
+
# @!attribute [rw] $1
|
39
|
+
# @return [$2]
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
#
|
43
|
+
# property :name, String, required: true, init_with: proc {|value| value.upcase }, within: %w{value1 value2}
|
44
|
+
#
|
45
|
+
# @params options [Hash] options
|
46
|
+
# @option options [Boolean] :required required or optional
|
47
|
+
# @option options [block] :init_with block used to init attr
|
48
|
+
def property(attr, type, options = {})
|
49
|
+
@required_attrs ||= []
|
50
|
+
@required_attrs << attr.to_s if options[:required]
|
51
|
+
|
52
|
+
define_reader_method(attr)
|
53
|
+
define_writer_method(attr, type, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def define_reader_method(attr)
|
59
|
+
attr_reader attr
|
60
|
+
end
|
61
|
+
|
62
|
+
def define_writer_method(attr, type, options)
|
63
|
+
init_with_block =
|
64
|
+
if options.key?(:init_with) && options[:init_with].respond_to?(:call)
|
65
|
+
options[:init_with]
|
66
|
+
else
|
67
|
+
build_block_with_type(attr, type, options)
|
68
|
+
end
|
69
|
+
define_writer_method_with_block(attr, init_with_block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_block_with_type(attr, type, options)
|
73
|
+
case type.to_s
|
74
|
+
when 'Integer'
|
75
|
+
build_integer_block(attr, options)
|
76
|
+
when 'DateTime'
|
77
|
+
build_datetime_block(attr, options)
|
78
|
+
when 'String'
|
79
|
+
build_string_block(attr, options)
|
80
|
+
else
|
81
|
+
build_default_block(attr, options)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_string_block(attr, options)
|
86
|
+
if options.key?(:within) && options[:within].is_a?(Array)
|
87
|
+
build_block_with_within(attr, options)
|
88
|
+
else
|
89
|
+
build_default_block(attr, options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_block_with_within(attr, options)
|
94
|
+
proc do |value|
|
95
|
+
if options[:within].include?(value.to_s)
|
96
|
+
value
|
97
|
+
else
|
98
|
+
fail ValueNotSupportedError.new(attr, options[:within])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_integer_block(attr, options)
|
104
|
+
proc { |value| value.to_i }
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_datetime_block(attr, options)
|
108
|
+
proc { |value| DateTime.parse(value) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def build_default_block(attr, options)
|
112
|
+
proc { |value| value }
|
113
|
+
end
|
114
|
+
|
115
|
+
def define_writer_method_with_block(attr, block)
|
116
|
+
define_method("#{attr}=") do |value|
|
117
|
+
instance_eval do
|
118
|
+
instance_variable_set("@#{attr}", block.call(value))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|