legion-data 0.2.0 → 1.2.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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop-analysis.yml +28 -0
  3. data/.github/workflows/sourcehawk-scan.yml +20 -0
  4. data/.gitignore +4 -2
  5. data/.rubocop.yml +6 -14
  6. data/CHANGELOG.md +2 -9
  7. data/CODE_OF_CONDUCT.md +75 -0
  8. data/CONTRIBUTING.md +55 -0
  9. data/Gemfile +7 -1
  10. data/INDIVIDUAL_CONTRIBUTOR_LICENSE.md +30 -0
  11. data/LICENSE +201 -0
  12. data/NOTICE.txt +9 -0
  13. data/README.md +60 -23
  14. data/SECURITY.md +9 -0
  15. data/attribution.txt +1 -0
  16. data/legion-data.gemspec +22 -38
  17. data/lib/legion/data.rb +18 -21
  18. data/lib/legion/data/connection.rb +29 -26
  19. data/lib/legion/data/migration.rb +3 -3
  20. data/lib/legion/data/migrations/001_add_schema_columns.rb +1 -1
  21. data/lib/legion/data/migrations/002_add_nodes.rb +20 -0
  22. data/lib/legion/data/migrations/003_add_settings.rb +18 -0
  23. data/lib/legion/data/migrations/004_add_extensions.rb +25 -0
  24. data/lib/legion/data/migrations/005_add_runners.rb +21 -0
  25. data/lib/legion/data/migrations/006_add_functions.rb +23 -0
  26. data/lib/legion/data/migrations/007_add_default_extensions.rb +25 -0
  27. data/lib/legion/data/migrations/008_add_tasks.rb +29 -0
  28. data/lib/legion/data/model.rb +5 -2
  29. data/lib/legion/data/models/extension.rb +0 -2
  30. data/lib/legion/data/models/function.rb +2 -6
  31. data/lib/legion/data/models/node.rb +1 -3
  32. data/lib/legion/data/models/runner.rb +0 -2
  33. data/lib/legion/data/models/setting.rb +0 -0
  34. data/lib/legion/data/models/task.rb +0 -2
  35. data/lib/legion/data/models/task_log.rb +0 -0
  36. data/lib/legion/data/settings.rb +25 -19
  37. data/lib/legion/data/version.rb +1 -1
  38. data/sonar-project.properties +12 -0
  39. data/sourcehawk.yml +4 -0
  40. metadata +41 -189
  41. data/.circleci/config.yml +0 -148
  42. data/.rspec +0 -1
  43. data/Rakefile +0 -55
  44. data/bin/console +0 -14
  45. data/bin/setup +0 -8
  46. data/bitbucket-pipelines.yml +0 -26
  47. data/lib/legion/data/connections/base.rb +0 -61
  48. data/lib/legion/data/connections/jdbc.rb +0 -21
  49. data/lib/legion/data/connections/mysql.rb +0 -26
  50. data/lib/legion/data/connections/mysql2.rb +0 -11
  51. data/lib/legion/data/connections/mysql_base.rb +0 -19
  52. data/lib/legion/data/migrations/002_add_users.rb +0 -17
  53. data/lib/legion/data/migrations/003_add_groups.rb +0 -16
  54. data/lib/legion/data/migrations/004_add_chains.rb +0 -25
  55. data/lib/legion/data/migrations/005_add_envs.rb +0 -24
  56. data/lib/legion/data/migrations/006_add_dcs.rb +0 -24
  57. data/lib/legion/data/migrations/007_add_nodes.rb +0 -26
  58. data/lib/legion/data/migrations/008_add_settings.rb +0 -18
  59. data/lib/legion/data/migrations/009_add_extensions.rb +0 -25
  60. data/lib/legion/data/migrations/010_add_runners.rb +0 -21
  61. data/lib/legion/data/migrations/011_add_functions.rb +0 -29
  62. data/lib/legion/data/migrations/012_add_tasks.rb +0 -25
  63. data/lib/legion/data/migrations/013_add_task_logs.rb +0 -17
  64. data/lib/legion/data/migrations/014_add_relationships.rb +0 -27
  65. data/lib/legion/data/models/chain.rb +0 -13
  66. data/lib/legion/data/models/datacenter.rb +0 -13
  67. data/lib/legion/data/models/environment.rb +0 -13
  68. data/lib/legion/data/models/group.rb +0 -10
  69. data/lib/legion/data/models/namespace.rb +0 -14
  70. data/lib/legion/data/models/relationship.rb +0 -18
  71. data/lib/legion/data/models/user.rb +0 -10
data/NOTICE.txt ADDED
@@ -0,0 +1,9 @@
1
+ Legion::Crypt(legion-crypt)
2
+ Copyright 2021 Optum
3
+
4
+ Project Description:
5
+ ====================
6
+ Manage
7
+
8
+ Author(s):
9
+ Esity
data/README.md CHANGED
@@ -1,37 +1,74 @@
1
- # Legion::Data
1
+ Legion::Data
2
+ =====
2
3
 
3
- Legion::Data is used by the framework to connect to a database. All database changes should be
4
- added as a migration with proper up/downs.
4
+ Legion::Data is a gem for the LegionIO framework to use persistent storage. Currently only MySQL is supported
5
5
 
6
- ## Installation
6
+ Supported Ruby versions and implementations
7
+ ------------------------------------------------
7
8
 
8
- Add this line to your application's Gemfile:
9
+ Legion::Json should work identically on:
9
10
 
10
- ```ruby
11
- gem 'legion-data'
12
- ```
11
+ * Ruby 2.5+
13
12
 
14
- And then execute:
15
13
 
16
- $ bundle
14
+ Installation and Usage
15
+ ------------------------
17
16
 
18
- Or install it yourself as:
17
+ You can verify your installation using this piece of code:
19
18
 
20
- $ gem install legion-data
19
+ ```bash
20
+ gem install legion-data
21
+ ```
21
22
 
22
- ## Usage
23
+ ```ruby
24
+ require 'legion/data'
23
25
 
24
- You can create a new connection to the database with the following example
25
- ``` Legion::Data::Connection.new.database.connection ```
26
- Keep in mind that if you need access to the database as part of a LEX, you should instead add it as a
27
- requirement inside your definitions with the following
26
+ Legion::Data.setup
27
+ Legion::Data.connected? # => true
28
+ Legion::Data::Model::Extension.all # Sequel::Dataset
28
29
  ```
29
- def requirements
30
- %w[legion-transport legion-data]
31
- end
30
+
31
+ Settings
32
+ ----------
33
+
34
+ ```json
35
+ {
36
+ "connected": false,
37
+ "cache": {
38
+ "connected": false,
39
+ "auto_enable": null,
40
+ "ttl": 60
41
+ },
42
+ "connection": {
43
+ "log": false,
44
+ "log_connection_info": false,
45
+ "log_warn_duration": 1,
46
+ "log_warn_duration": "debug",
47
+ "max_connections": 10,
48
+ "preconnect": false
49
+ },
50
+ "creds": {
51
+ "username": "legion",
52
+ "password": "legion",
53
+ "database": "legionio",
54
+ "host": "127.0.0.1",
55
+ "port": 3306
56
+ },
57
+ "migrations": {
58
+ "continue_on_fail": false,
59
+ "auto_migrate": true,
60
+ "ran": false,
61
+ "version": null
62
+ },
63
+ "models": {
64
+ "continue_on_load_fail": false,
65
+ "autoload": true
66
+ },
67
+ "connect_on_start": true
68
+ }
32
69
  ```
33
- and the framework will take care of the rest.
34
70
 
35
- ## Contributing
71
+ Authors
72
+ ----------
36
73
 
37
- Bug reports and pull requests are welcome on GitHub at https://bitbucket.org/legion-io/legion-data.
74
+ * [Matthew Iverson](https://github.com/Esity) - current maintainer
data/SECURITY.md ADDED
@@ -0,0 +1,9 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+ | Version | Supported |
5
+ | ------- | ------------------ |
6
+ | 1.x.x | :white_check_mark: |
7
+
8
+ ## Reporting a Vulnerability
9
+ To be added
data/attribution.txt ADDED
@@ -0,0 +1 @@
1
+ Add attributions here.
data/legion-data.gemspec CHANGED
@@ -1,49 +1,33 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'legion/data/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/legion/data/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = (RUBY_ENGINE == 'jruby' ? 'legion-data-java' : 'legion-data')
6
+ spec.name = 'legion-data'
7
7
  spec.version = Legion::Data::VERSION
8
8
  spec.authors = ['Esity']
9
- spec.email = ['matthewdiverson@gmail.com']
10
-
11
- spec.summary = 'Used by Legion to connect to the database'
12
- spec.description = 'The Legion connect gem'
13
- spec.homepage = 'https://bitbucket.org/legion-io/legion-data'
14
-
15
- spec.metadata['bug_tracker_uri'] = 'https://bitbucket.org/legion-io/legion-data/issues?status=new&status=open'
16
- spec.metadata['changelog_uri'] = 'https://bitbucket.org/legion-io/legion-data/src/CHANGELOG.md'
17
- spec.metadata['documentation_uri'] = 'https://bitbucket.org/legion-io/legion-data'
18
- spec.metadata['homepage_uri'] = 'https://bitbucket.org/legion-io/legion-data'
19
- spec.metadata['source_code_uri'] = 'https://bitbucket.org/legion-io/legion-data'
20
- spec.metadata['wiki_uri'] = 'https://bitbucket.org/legion-io/legion-data/wiki/Home'
9
+ spec.email = %w[matthewdiverson@gmail.com ruby@optum.com]
21
10
 
22
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
23
- f.match(%r{^(test|spec|features)/})
24
- end
25
- spec.bindir = 'bin'
26
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
11
+ spec.summary = 'Manages the connects to the backend database'
12
+ spec.description = 'A LegionIO gem to connect to a persistent data store'
13
+ spec.homepage = 'https://github.com/Optum/legion-data'
14
+ spec.license = 'Apache-2.0'
15
+ spec.required_ruby_version = '>= 2.5'
27
16
  spec.require_paths = ['lib']
28
-
29
- spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'codecov'
31
- spec.add_development_dependency 'rake'
32
- spec.add_development_dependency 'rspec'
33
- spec.add_development_dependency 'rspec_junit_formatter'
34
- spec.add_development_dependency 'rubocop'
35
- spec.add_development_dependency 'rubocop-md'
36
- spec.add_development_dependency 'rubocop-performance'
37
- spec.add_development_dependency 'rubocop-rspec'
38
- spec.add_development_dependency 'rubocop-sequel'
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.test_files = spec.files.select { |p| p =~ %r{^test/.*_test.rb} }
19
+ spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md]
20
+ spec.metadata = {
21
+ 'bug_tracker_uri' => 'https://github.com/Optum/legion-data/issues',
22
+ 'changelog_uri' => 'https://github.com/Optum/legion-data/src/main/CHANGELOG.md',
23
+ 'documentation_uri' => 'https://github.com/Optum/legion-data',
24
+ 'homepage_uri' => 'https://github.com/Optum/LegionIO',
25
+ 'source_code_uri' => 'https://github.com/Optum/legion-data',
26
+ 'wiki_uri' => 'https://github.com/Optum/legion-data/wiki'
27
+ }
39
28
 
40
29
  spec.add_dependency 'legion-logging'
41
30
  spec.add_dependency 'legion-settings'
42
-
43
- if RUBY_ENGINE == 'jruby'
44
- spec.add_dependency 'jdbc-mysql'
45
- else
46
- spec.add_dependency 'mysql2'
47
- end
31
+ spec.add_dependency 'mysql2'
48
32
  spec.add_dependency 'sequel'
49
33
  end
data/lib/legion/data.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'legion/data/version'
2
- require_relative 'data/settings'
2
+ require 'legion/data/settings'
3
3
  require 'sequel'
4
4
 
5
- require_relative 'data/connection'
6
- require_relative 'data/model'
7
- require_relative 'data/migration'
5
+ require 'legion/data/connection'
6
+ require 'legion/data/model'
7
+ require 'legion/data/migration'
8
8
 
9
9
  module Legion
10
10
  module Data
@@ -13,7 +13,7 @@ module Legion
13
13
  connection_setup
14
14
  migrate
15
15
  load_models
16
- # setup_cache
16
+ setup_cache
17
17
  end
18
18
 
19
19
  def connection_setup
@@ -34,25 +34,22 @@ module Legion
34
34
  Legion::Data::Connection.sequel
35
35
  end
36
36
 
37
- def setup_cache # rubocop:disable Metrics/AbcSize
38
- return if Legion::Settings[:data][:cache][:enable]
37
+ def setup_cache
38
+ return if Legion::Settings[:data][:cache][:enabled]
39
39
 
40
- unless Legion::Settings[:cache][:connected]
41
- Legion::Logging.warn 'Legion::Data has caching enabled but Legion::Cache is not started'
42
- end
43
- return unless Legion::Settings[:cache][:connected]
40
+ return unless defined?(::Legion::Cache)
44
41
 
45
42
  # Legion::Data::Model::Relationship.plugin :caching, Legion::Cache, ttl: 10
46
- Legion::Data::Model::Chain.plugin :caching, Legion::Cache, ttl: 60
47
- Legion::Data::Model::Datacenter.plugin :caching, Legion::Cache, ttl: 120
48
- Legion::Data::Model::Extension.plugin :caching, Legion::Cache, ttl: 120
49
- Legion::Data::Model::Function.plugin :caching, Legion::Cache, ttl: 120
50
- Legion::Data::Model::Namespace.plugin :caching, Legion::Cache, ttl: 120
51
- Legion::Data::Model::Node.plugin :caching, Legion::Cache, ttl: 10
52
- Legion::Data::Model::TaskLog.plugin :caching, Legion::Cache, ttl: 12
53
- Legion::Data::Model::Task.plugin :caching, Legion::Cache, ttl: 10
54
- Legion::Data::Model::User.plugin :caching, Legion::Cache, ttl: 120
55
- Legion::Data::Model::Group.plugin :caching, Legion::Cache, ttl: 120
43
+ # Legion::Data::Model::Runner.plugin :caching, Legion::Cache, ttl: 60
44
+ # Legion::Data::Model::Chain.plugin :caching, Legion::Cache, ttl: 60
45
+ # Legion::Data::Model::Function.plugin :caching, Legion::Cache, ttl: 120
46
+ # Legion::Data::Model::Extension.plugin :caching, Legion::Cache, ttl: 120
47
+ # Legion::Data::Model::Node.plugin :caching, Legion::Cache, ttl: 10
48
+ # Legion::Data::Model::TaskLog.plugin :caching, Legion::Cache, ttl: 12
49
+ # Legion::Data::Model::Task.plugin :caching, Legion::Cache, ttl: 10
50
+ # Legion::Data::Model::User.plugin :caching, Legion::Cache, ttl: 120
51
+ # Legion::Data::Model::Group.plugin :caching, Legion::Cache, ttl: 120
52
+ # Legion::Logging.info 'Legion::Data connected to Legion::Cache'
56
53
  end
57
54
 
58
55
  def shutdown
@@ -4,33 +4,41 @@ module Legion
4
4
  module Data
5
5
  module Connection
6
6
  class << self
7
- attr_reader :sequel
8
- if RUBY_ENGINE == 'jruby'
9
- require_relative 'connections/jdbc'
10
- include Legion::Data::Connections::JDBC
11
- else
12
- require_relative 'connections/mysql2'
13
- include Legion::Data::Connections::MySQL2
7
+ attr_accessor :sequel
8
+
9
+ def adapter
10
+ @adapter ||= RUBY_ENGINE == 'jruby' ? :jdbc : :mysql2
14
11
  end
15
12
 
16
13
  def setup
17
- @sequel = ::Sequel.connect(adapter: adapter, **creds_builder)
14
+ @sequel = if adapter == :mysql2
15
+ ::Sequel.connect(adapter: adapter, **creds_builder)
16
+ else
17
+ ::Sequel.connect("jdbc:mysql://#{creds_builder[:host]}:#{creds_builder[:port]}/#{creds_builder[:database]}?user=#{creds_builder[:username]}&password=#{creds_builder[:password]}&serverTimezone=UTC") # rubocop:disable Layout/LineLength
18
+ end
18
19
  Legion::Settings[:data][:connected] = true
19
- return unless Legion::Settings[:data][:connection][:log]
20
+ return if Legion::Settings[:data][:connection].nil? || Legion::Settings[:data][:connection][:log].nil?
20
21
 
21
- @sequel.logger = Legion::Logging::Logger.new(level: 'debug')
22
+ @sequel.logger = Legion::Logging
22
23
  @sequel.sql_log_level = Legion::Settings[:data][:connection][:sql_log_level]
23
24
  @sequel.log_warn_duration = Legion::Settings[:data][:connection][:log_warn_duration]
24
25
  end
25
26
 
26
27
  def shutdown
27
- @sequel.disconnect
28
+ @sequel&.disconnect
29
+ Legion::Settings[:data][:connected] = false
28
30
  end
29
31
 
30
- def creds_builder # rubocop:disable Metrics/AbcSize
31
- final_creds = {}
32
- final_creds.merge! default_creds
33
- final_creds.merge! Legion::Settings[:data][:creds]
32
+ def creds_builder(final_creds = {})
33
+ final_creds.merge! Legion::Data::Settings.creds
34
+ final_creds.merge! Legion::Settings[:data][:creds] if Legion::Settings[:data][:creds].is_a? Hash
35
+
36
+ # if Legion::Settings[:data][:connection][:max_connections].is_a? Integer
37
+ # final_creds[:max_connections] = Legion::Settings[:data][:connection][:max_connections]
38
+ # end
39
+
40
+ # final_creds[:preconnect] = :concurrently if Legion::Settings[:data][:connection][:preconnect]
41
+
34
42
  return final_creds if Legion::Settings[:vault].nil?
35
43
 
36
44
  if Legion::Settings[:vault][:connected] && ::Vault.sys.mounts.key?(:database)
@@ -44,19 +52,14 @@ module Legion
44
52
 
45
53
  def default_creds
46
54
  {
47
- host: '127.0.0.1',
48
- port: 3306,
49
- username: 'legion',
50
- password: 'legion',
51
- database: 'legion',
52
- max_connections: 32,
53
- preconnect: 'concurrently'
55
+ host: '127.0.0.1',
56
+ port: 3306,
57
+ username: 'legion',
58
+ password: 'legion',
59
+ database: 'legion',
60
+ max_connections: 4
54
61
  }
55
62
  end
56
-
57
- def adapter
58
- 'mysql2'
59
- end
60
63
  end
61
64
  end
62
65
  end
@@ -4,9 +4,9 @@ module Legion
4
4
  module Data
5
5
  module Migration
6
6
  class << self
7
- def migrate(connection = Legion::Data.connection, path = __dir__ + '/migrations')
8
- Legion::Settings[:data][:migrations][:version] = Sequel::Migrator.run(connection, path)
9
- Legion::Logging.info 'Legion::Data::Migration ran successfully to version ' + Legion::Settings[:data][:migrations][:version].to_s # rubocop:disable Layout/LineLength
7
+ def migrate(connection = Legion::Data.connection, path = "#{__dir__}/migrations", **opts)
8
+ Legion::Settings[:data][:migrations][:version] = Sequel::Migrator.run(connection, path, **opts)
9
+ Legion::Logging.info("Legion::Data::Migration ran successfully to version #{Legion::Settings[:data][:migrations][:version]}") # rubocop:disable Layout/LineLength
10
10
  Legion::Settings[:data][:migrations][:ran] = true
11
11
  end
12
12
  end
@@ -8,7 +8,7 @@ Sequel.migration do
8
8
  end
9
9
 
10
10
  down do
11
- alter_table(:schema) do
11
+ alter_table(:schema_info) do
12
12
  drop_column :catalog
13
13
  drop_column :updated_at
14
14
  drop_column :created_at
@@ -0,0 +1,20 @@
1
+ Sequel.migration do
2
+ up do
3
+ run "CREATE TABLE `nodes` (
4
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
5
+ `name` varchar(128) NOT NULL DEFAULT '',
6
+ `status` varchar(255) NOT NULL DEFAULT 'unknown',
7
+ `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
8
+ `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ `updated` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
10
+ PRIMARY KEY (`id`),
11
+ UNIQUE KEY `name` (`name`),
12
+ KEY `active` (`active`),
13
+ KEY `status` (`status`)
14
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
15
+ end
16
+
17
+ down do
18
+ drop_table :nodes
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ Sequel.migration do
2
+ up do
3
+ run "CREATE TABLE `settings` (
4
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
5
+ `key` varchar(128) NOT NULL,
6
+ `value` varchar(256) NOT NULL,
7
+ `encrypted` tinyint(1) unsigned NOT NULL DEFAULT '0',
8
+ `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ `updated` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
10
+ PRIMARY KEY (`id`),
11
+ UNIQUE KEY `key` (`key`)
12
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
13
+ end
14
+
15
+ down do
16
+ drop_table :settings
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ Sequel.migration do
2
+ up do
3
+ run "CREATE TABLE `extensions` (
4
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
5
+ `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
6
+ `name` varchar(128) NOT NULL,
7
+ `namespace` varchar(128) NOT NULL DEFAULT '',
8
+ `exchange` varchar(255) DEFAULT NULL,
9
+ `uri` varchar(256) DEFAULT NULL,
10
+ `schema_version` int(11) unsigned NOT NULL DEFAULT 0,
11
+ `updated` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
12
+ `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ PRIMARY KEY (`id`),
14
+ UNIQUE KEY `name_namespace` (`name`,`namespace`),
15
+ KEY `active` (`active`),
16
+ KEY `name` (`name`),
17
+ KEY `namespace` (`namespace`),
18
+ key `schema_version` (`schema_version`)
19
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
20
+ end
21
+
22
+ down do
23
+ drop_table :extensions
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ Sequel.migration do
2
+ up do
3
+ run "CREATE TABLE `runners` (
4
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
5
+ `extension_id` int(11) unsigned NOT NULL,
6
+ `name` varchar(256) NOT NULL DEFAULT '',
7
+ `namespace` varchar(256) NOT NULL DEFAULT '',
8
+ `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
9
+ `queue` varchar(256) DEFAULT NULL,
10
+ `uri` varchar(256) DEFAULT NULL,
11
+ `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
+ `updated` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
13
+ PRIMARY KEY (`id`),
14
+ CONSTRAINT `runner_extension_id` FOREIGN KEY (`extension_id`) REFERENCES `extensions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
15
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
16
+ end
17
+
18
+ down do
19
+ drop_table :runners
20
+ end
21
+ end