kandata 0.2.0 → 0.3.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
  SHA1:
3
- metadata.gz: 81234a446c42f891691c7c5d8130512c0a7eaa2b
4
- data.tar.gz: 03e57575d6a39b3f056f433fad9cb791ab21dafa
3
+ metadata.gz: 9841a7b354143f7fbdd512e7e1c84ee3cfe97622
4
+ data.tar.gz: 8f4a1bab20ab17cde5580e27ca0376edd6e53d42
5
5
  SHA512:
6
- metadata.gz: 87912e4ff0f911b3da0e8292877615cf5f8e1ad179d02f22f49ceb3e1eddde9b90965b37440a991aefa6131e94996888c6a6f278a918c79b88043537c82bb3ad
7
- data.tar.gz: 776f38b3353eab850e80c3af4d887d51947ad69f3329f72f8f8dfb9d225d47534c49229c73d48251e68b4169fb4f608850b571da60f6f129cbb5cf7f8d79ed07
6
+ metadata.gz: bb5391ce2ee2ac7112ce5320ebf7df616bee2d6baad69636c43342b50840148a465670796816713c7f1304bfc1e53170e6300d344852e75554e3ef5c0d086c2f
7
+ data.tar.gz: 5b29c796225cc9d6cf73b0fc70c77b5efc305c4c6a93ae2787dfe00d6be119b481b4440abf25148f76751e8496e5cef0a24ca210e55fdb276ce3ad4c991094ed
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Kandata
2
2
 
3
- [![CircleCI](https://circleci.com/gh/tamano/kandata.svg?style=svg)](https://circleci.com/gh/tamano/kandata)
3
+ [![CircleCI](https://circleci.com/gh/eLicenseSystems/kandata.svg?style=svg)](https://circleci.com/gh/eLicenseSystems/kandata)
4
4
  [![Gem Version](https://badge.fury.io/rb/kandata.svg)](https://badge.fury.io/rb/kandata)
5
5
 
6
6
  Kandataは、TSVファイルを自分のローカルのMySQLデータベース内に簡単にロードするためのツールです。
@@ -16,6 +16,22 @@ MySQLサーバーがローカルで動作している必要があります。
16
16
 
17
17
  ## 利用方法
18
18
 
19
+ ### Rubyスクリプト内から利用する場合
20
+
21
+ ```ruby
22
+ require 'kandata'
23
+
24
+ # TSVからデータ生成
25
+ # ローカルのMySQLサーバーのKandataデータベース内にuserテーブルを作成して、TSVでデータを流し込む
26
+ my_user = Kandata.build_from_tsv('./user.tsv')
27
+
28
+ # my_user はActiveRecordをextendしたクラスそのものなので、
29
+ # Railsのモデルクラスのように使って色々出来る。
30
+ # ex) my_user.where(last_login: nil).each do |v| v.disactivate end
31
+ ```
32
+
33
+ ### コマンドラインから実行する場合
34
+
19
35
  以下のように実行します。
20
36
 
21
37
  $ kandata load_tsv TSVファイル名 [--force]
@@ -37,7 +53,7 @@ MySQLサーバーがローカルで動作している必要があります。
37
53
  - 各カラムへのINDEXの追加には対応していません。必要な場合は自分でSQLで`CREATE INDEX`してください。
38
54
 
39
55
  ## 今後の予定
40
- - 作成したテーブルに応じたActiveRecordモデルを自動生成できるようにする。
56
+ - ~作成したテーブルに応じたActiveRecordモデルを自動生成できるようにする。~ **done**
41
57
  - `require`で非RailsなRubyスクリプトで読み込んで使えるように。
42
58
  - 作成したテーブルのバックアップなどの機能を追加する。
43
59
 
@@ -16,8 +16,8 @@ class Kandata
16
16
  end
17
17
 
18
18
  # テーブルを作成し、テーブルにデータを読み込み、テーブル名を戻す
19
- def self.load_tsv(filename, force_load)
19
+ def self.load_tsv(filename, force_load, headers = nil)
20
20
  client = Kandata::Database.new
21
- client.load_tsv(filename, force_load)
21
+ client.load_tsv(filename, force_load, headers)
22
22
  end
23
23
  end
@@ -3,6 +3,7 @@ require 'mysql2'
3
3
 
4
4
  class Kandata
5
5
  # ActiveRecordを使わないでKandataデータベースにアクセスするためのクラス
6
+ # ignore :reek:InstanceVariableAssumption:
6
7
  class Database < Mysql2::Client
7
8
  def initialize
8
9
  create_database_if_not_exists
@@ -15,8 +16,8 @@ class Kandata
15
16
  end
16
17
 
17
18
  # ignore :reek:ControlParameter:
18
- def load_tsv(filename, force_update)
19
- @tsv = Kandata::TsvFile.new(filename)
19
+ def load_tsv(filename, force_update, headers = nil)
20
+ @tsv = Kandata::TsvFile.new(filename, headers)
20
21
 
21
22
  drop_table if force_update
22
23
  create_table
@@ -30,18 +31,17 @@ class Kandata
30
31
  # ignore :reek:FeatureEnvy:
31
32
  def create_database_if_not_exists
32
33
  client = Mysql2::Client.new(Kandata::Database::ConnectionInfo.host_and_user)
33
- database_name = Kandata::Database::ConnectionInfo.database_name
34
34
 
35
35
  begin
36
- client.query("SHOW CREATE DATABASE #{database_name}")
36
+ client.query("SHOW CREATE DATABASE `#{database_name}`")
37
37
  rescue Mysql2::Error => error
38
38
  raise error unless error.message == "Unknown database '#{database_name}'"
39
- client.query("CREATE DATABASE #{database_name}")
39
+ client.query("CREATE DATABASE `#{database_name}`")
40
40
  end
41
41
  end
42
42
 
43
43
  def drop_table
44
- query("DROP TABLE IF EXISTS #{full_table_name}")
44
+ query("DROP TABLE IF EXISTS `#{database_name}`.`#{table_name}`")
45
45
  end
46
46
 
47
47
  def create_table
@@ -50,21 +50,30 @@ class Kandata
50
50
  # 後で追加するため一旦削除
51
51
  columns.delete('id')
52
52
 
53
- columns_text = columns.map { |column| "#{column} VARCHAR(128)" }.join(',')
53
+ columns_text = columns.map { |column| "#{column} TEXT" }.join(',')
54
54
  columns_text = 'id INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY,' + columns_text
55
55
 
56
- query("CREATE TABLE #{full_table_name} (#{columns_text})")
56
+ query("CREATE TABLE `#{database_name}`.`#{table_name}` (#{columns_text})")
57
57
  end
58
58
 
59
59
  def load_data
60
- sql = "LOAD DATA LOCAL INFILE '#{@tsv.filename}' INTO TABLE #{full_table_name} IGNORE 1 LINES "
61
- sql += "(#{@tsv.headers.join(',')})"
60
+ sql = "LOAD DATA LOCAL INFILE '#{@tsv.filename}' INTO TABLE `#{database_name}`.`#{table_name}` IGNORE 1 LINES "
61
+ sql += "(#{@tsv.headers.map { |column| "`#{column}`" }.join(',')})"
62
62
 
63
63
  query(sql)
64
64
  end
65
65
 
66
66
  def full_table_name
67
- "#{Kandata::Database::ConnectionInfo.database_name}.#{@tsv.table_name}"
67
+ "#{database_name}.#{table_name}"
68
+ end
69
+
70
+ # ignore :reek:UtilityFunction:
71
+ def database_name
72
+ Kandata::Database::ConnectionInfo.database_name
73
+ end
74
+
75
+ def table_name
76
+ @tsv.table_name if @tsv.present?
68
77
  end
69
78
  end
70
79
  end
@@ -2,9 +2,11 @@
2
2
 
3
3
  class Kandata
4
4
  class Database
5
+ # ignore :reek:Attribute:
5
6
  class ConnectionInfo
6
7
  class << self
7
- attr_reader :host, :user_name, :database_name
8
+ attr_reader :host, :user_name
9
+ attr_accessor :database_name
8
10
  end
9
11
 
10
12
  @host = 'localhost'
@@ -1,28 +1,37 @@
1
1
  # frozen_string_literal: true
2
+ require 'tempfile'
3
+ require 'nkf'
4
+
2
5
  class Kandata
3
6
  # 読み込み用TSVファイル
4
7
  class TsvFile
5
- attr_reader :filename, :headers
8
+ attr_reader :filename, :table_name, :headers
9
+
10
+ RESERVED_COLUMNS = ['type'].freeze
11
+
12
+ def initialize(filename, custom_headers = nil)
13
+ @table_name = File.basename(filename).sub('.tsv', '')
14
+ validate_table_name
6
15
 
7
- def initialize(filename)
8
- @filename = filename
9
- validate_filename
16
+ # TempFileにファイル内容をコピーしてパスを返す
17
+ @filename = copy_to_tempfile(filename)
18
+
19
+ @headers = custom_headers
20
+ @headers ||= File.open(@filename, 'r').first(&:readline).chomp.split("\t")
10
21
 
11
- @headers = File.open(@filename, 'r').first(&:readline).chomp.split("\t")
12
22
  validate_headers
13
23
  end
14
24
 
15
- def validate_filename
16
- raise 'テーブル名に使用できないファイル名です' unless table_name.match?(/^[0-9a-zA-Z$_]+$/)
25
+ def validate_table_name
26
+ raise 'テーブル名に使用できないファイル名です' unless @table_name.match?(/^[0-9a-zA-Z$_]+$/)
17
27
  true
18
28
  end
19
29
 
20
30
  def validate_headers
21
- duplicated_columns = @headers.group_by { |value| value }.reject { |_key, value| value.one? }.keys
22
31
  raise "以下のカラムが複数存在しています #{duplicated_columns}" unless duplicated_columns.empty?
23
32
 
24
- illegal_named_columns = @headers.reject { |value| value.match?(/^[0-9a-zA-Z$_]+$/) }
25
- raise "以下のカラム名は使用できません #{illegal_named_columns}" unless illegal_named_columns.empty?
33
+ raise "以下のカラム名は使用できません #{invalid_columns}" unless invalid_columns.empty?
34
+ raise "以下のカラム名は使用できません #{RESERVED_COLUMNS}" if include_reserved_name?
26
35
 
27
36
  # 現時点では、ミス防止のため、先頭以外にidカラムがあるとエラーとして処理する
28
37
  raise '先頭以外にidカラムがあります' if include_id_column? && @headers[0] != 'id'
@@ -30,12 +39,29 @@ class Kandata
30
39
  true
31
40
  end
32
41
 
33
- def table_name
34
- File.basename(@filename).sub('.tsv', '')
42
+ def duplicated_columns
43
+ @headers.group_by { |value| value }.reject { |_key, value| value.one? }.keys
44
+ end
45
+
46
+ def invalid_columns
47
+ @headers.reject { |value| value.match?(/^[0-9a-zA-Z$_]+$/) }
48
+ end
49
+
50
+ def include_reserved_name?
51
+ RESERVED_COLUMNS.any? { |name| @headers.include?(name) }
35
52
  end
36
53
 
37
54
  def include_id_column?
38
55
  @headers.include?('id')
39
56
  end
57
+
58
+ private
59
+
60
+ def copy_to_tempfile(filename)
61
+ Tempfile.open(basename: self.class.name) do |file|
62
+ file.write(NKF.nkf('-w', File.open(filename, 'r').read))
63
+ file.path
64
+ end
65
+ end
40
66
  end
41
67
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Kandata
3
- VERSION = '0.2.0'
3
+ VERSION = '0.3.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kandata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuya TAMANO
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-22 00:00:00.000000000 Z
11
+ date: 2018-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler