Class: ShopifyToolkit::Migrator

Inherits:
Object
  • Object
show all
Includes:
AdminClient, MetafieldStatements
Defined in:
lib/shopify_toolkit/migrator.rb

Overview

:nodoc:

Defined Under Namespace

Classes: MigrationProxy

Constant Summary

Constants included from AdminClient

AdminClient::API_VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MetafieldStatements

define, #get_metafield_gid, log_time

Methods included from AdminClient

#api_version, #handle_shopify_admin_client_errors, #shopify_admin_client

Methods included from ShopifyToolkit::Migration::Logging

#announce, #say, #say_with_time, #write

Constructor Details

#initialize(migrations_paths: self.class.migrations_paths) ⇒ Migrator

Returns a new instance of Migrator.



15
16
17
18
19
# File 'lib/shopify_toolkit/migrator.rb', line 15

def initialize(migrations_paths: self.class.migrations_paths)
  @migrations_paths  = migrations_paths
  @migrated_versions = read_or_create_metafield["migrated_versions"]
  @migrations        = load_migrations # [MigrationProxy<Migration1>, MigrationProxy<Migration2>, ...]
end

Instance Attribute Details

#migrated_versionsObject (readonly)

Returns the value of attribute migrated_versions.



13
14
15
# File 'lib/shopify_toolkit/migrator.rb', line 13

def migrated_versions
  @migrated_versions
end

#migrationsObject (readonly)

Returns the value of attribute migrations.



13
14
15
# File 'lib/shopify_toolkit/migrator.rb', line 13

def migrations
  @migrations
end

#migrations_pathsObject

Returns the value of attribute migrations_paths.



10
11
12
# File 'lib/shopify_toolkit/migrator.rb', line 10

def migrations_paths
  @migrations_paths
end

Instance Method Details

#current_versionObject



21
22
23
# File 'lib/shopify_toolkit/migrator.rb', line 21

def current_version
  migrated.max || 0
end

#downObject



40
41
42
43
44
45
46
47
48
# File 'lib/shopify_toolkit/migrator.rb', line 40

def down
  # For now we'll just rollback the last one
  executed_migrations.last(1).each do |migration|
    migration.migrate(:down)
    migrated_versions.delete(migration.version)
  end
ensure
  update_metafield
end

#executed_migrationsObject



36
37
38
# File 'lib/shopify_toolkit/migrator.rb', line 36

def executed_migrations
  migrations.select { migrated_versions.include?(_1.version) }
end

#load_migrationsObject



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/shopify_toolkit/migrator.rb', line 112

def load_migrations
  migrations = migration_files.map do |file|
    version, name, scope = parse_migration_filename(file)
    raise "missing version #{file}" unless version
    raise "missing name #{file}" unless name
    version = version.to_i
    name = name.camelize

    MigrationProxy.new(name, version, file, scope)
  end

  migrations.sort_by(&:version)
end

#migration_filesObject



103
104
105
106
# File 'lib/shopify_toolkit/migrator.rb', line 103

def migration_files
  paths = Array(migrations_paths)
  Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
end

#parse_migration_filename(filename) ⇒ Object



108
109
110
# File 'lib/shopify_toolkit/migrator.rb', line 108

def parse_migration_filename(filename)
  File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
end

#query(query, **variables) ⇒ Object



50
51
52
53
54
55
56
# File 'lib/shopify_toolkit/migrator.rb', line 50

def query(query, **variables)
  shopify_admin_client
    .query(query:, variables:)
    .tap { handle_shopify_admin_client_errors(_1) }
    .body
    .dig("data")
end

#read_or_create_metafieldObject



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/shopify_toolkit/migrator.rb', line 81

def read_or_create_metafield
  namespace = :shopify_toolkit
  key = :migrations

  value = query(
    "query ShopMetafield($namespace: String!, $key: String!) {shop {metafield(namespace: $namespace, key: $key) {value}}}",
    namespace:, key:,
  ).dig("shop", "metafield", "value")

  if value.nil?
    create_metafield :shop, key, :json, namespace:, name: "Migrations metadata"
    return { "migrated_versions" => [] }
  end

  JSON.parse(value)
end

#redoObject



98
99
100
101
# File 'lib/shopify_toolkit/migrator.rb', line 98

def redo
  down
  up
end

#upObject



25
26
27
28
29
30
31
32
33
34
# File 'lib/shopify_toolkit/migrator.rb', line 25

def up
  pending_migrations = migrations.reject { migrated_versions.include?(_1.version) }

  pending_migrations.each do |migration|
    migration.migrate(:up)
    migrated_versions << migration.version
  end
ensure
  update_metafield
end

#update_metafieldObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/shopify_toolkit/migrator.rb', line 58

def update_metafield
  namespace = :shopify_toolkit
  key = :migrations

  value = { "migrated_versions" => migrated_versions.to_a.sort }.to_json

  owner_id = query(%(query GetShopGId { shop { id } })).dig("shop", "id")

  query = <<~GRAPHQL
    mutation metafieldsSet($metafields: [MetafieldsSetInput!]!) {
      metafieldsSet(metafields: $metafields) {
        userErrors {
          field
          message
        }
      }
    }
  GRAPHQL
  query(query, metafields: [{ namespace:, key:, ownerId: owner_id, value: }])

  nil
end