123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- # frozen_string_literal: true
- module ShopifyAPI
- class ApiVersion
- class UnknownVersion < StandardError; end
- class ApiVersionNotSetError < StandardError; end
- include Comparable
- UNSTABLE_HANDLE = 'unstable'
- HANDLE_FORMAT = /((\d{4}-\d{2})|#{UNSTABLE_HANDLE})/.freeze
- UNSTABLE_AS_DATE = Time.utc(3000, 1, 1)
- API_PREFIX = '/admin/api/'
- LOOKUP_MODES = [:raise_on_unknown, :define_on_unknown].freeze
- class << self
- attr_reader :versions
- def version_lookup_mode
- @version_lookup_mode ||= :define_on_unknown
- end
- def version_lookup_mode=(mode)
- raise ArgumentError, "Mode must be one of #{LOOKUP_MODES}" unless LOOKUP_MODES.include?(mode)
- sanitize_known_versions if mode == :raise_on_unknown
- @version_lookup_mode = mode
- end
- def find_version(version_or_handle)
- raise ArgumentError, "NullVersion is not a valid version or version handle." if version_or_handle == NullVersion
- return version_or_handle if version_or_handle.is_a?(ApiVersion)
- handle = version_or_handle.to_s
- @versions ||= {}
- @versions.fetch(handle) do
- if @version_lookup_mode == :raise_on_unknown
- raise UnknownVersion, unknown_version_error_message(handle)
- else
- add_to_known_versions(ApiVersion.new(handle: handle))
- end
- end
- end
- def coerce_to_version(version_or_handle)
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion.coerce_to_version be removed in a future version. ' \
- 'Use `find_version` instead.'
- )
- find_version(version_or_handle)
- end
- def fetch_known_versions
- @versions = Meta.admin_versions.map do |version|
- [version.handle, ApiVersion.new(version.attributes.merge(verified: version.persisted?))]
- end.to_h
- end
- def define_known_versions
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion.define_known_versions is deprecated and will be ' \
- 'removed in a future version. Use `fetch_known_versions` instead.'
- )
- fetch_known_versions
- end
- def add_to_known_versions(version)
- @versions[version.handle] = version
- end
- def clear_known_versions
- @versions = {}
- end
- def clear_defined_versions
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion.clear_defined_versions is deprecated and will be ' \
- 'removed in a future version. Use `clear_known_versions` instead.'
- )
- clear_known_versions
- end
- def latest_stable_version
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion.latest_stable_version is deprecated and will be ' \
- 'removed in a future version.'
- )
- versions.values.find(&:latest_supported?)
- end
- private
- def sanitize_known_versions
- return if @versions.nil?
- @versions = @versions.keys.map do |handle|
- next unless @versions[handle].verified?
- [handle, @versions[handle]]
- end.compact.to_h
- end
- def unknown_version_error_message(handle)
- msg = "ApiVersion.version_lookup_mode is set to `:raise_on_unknown`. \n"
- return msg + "No versions defined. You must call `ApiVersion.fetch_known_versions` first." if @versions.empty?
- msg + "`#{handle}` is not in the defined version set. Available versions: #{@versions.keys}"
- end
- end
- attr_reader :handle, :display_name, :supported, :latest_supported, :verified
- def initialize(attributes)
- attributes = ActiveSupport::HashWithIndifferentAccess.new(attributes)
- @handle = attributes[:handle].to_s
- @display_name = attributes.fetch(:display_name, attributes[:handle].to_s)
- @supported = attributes.fetch(:supported, false)
- @latest_supported = attributes.fetch(:latest_supported, false)
- @verified = attributes.fetch(:verified, false)
- end
- def to_s
- handle
- end
- def latest_supported?
- latest_supported
- end
- def supported?
- supported
- end
- def verified?
- verified
- end
- def <=>(other)
- handle_as_date <=> other.handle_as_date
- end
- def ==(other)
- other.class == self.class && handle == other.handle
- end
- def hash
- handle.hash
- end
- def construct_api_path(path)
- "#{API_PREFIX}#{handle}/#{path}"
- end
- def construct_graphql_path
- construct_api_path('graphql.json')
- end
- def name
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion#name is deprecated and will be removed in a future version. ' \
- 'Use `handle` instead.'
- )
- handle
- end
- def stable?
- warn(
- '[DEPRECATED] ShopifyAPI::ApiVersion#stable? is deprecated and will be removed in a future version. ' \
- 'Use `supported?` instead.'
- )
- supported?
- end
- def unstable?
- handle == UNSTABLE_HANDLE
- end
- def handle_as_date
- return UNSTABLE_AS_DATE if unstable?
- year, month, day = handle.split('-')
- Time.utc(year, month, day)
- end
- class NullVersion
- class << self
- def new(*_args)
- raise NoMethodError, "NullVersion is an abstract class and cannot be instantiated."
- end
- def matches?(version)
- version.nil? || version == self
- end
- def raise_not_set_error(*_args)
- raise ApiVersionNotSetError, "You must set ShopifyAPI::Base.api_version before making a request."
- end
- alias_method :stable?, :raise_not_set_error
- alias_method :construct_api_path, :raise_not_set_error
- alias_method :construct_graphql_path, :raise_not_set_error
- alias_method :latest_supported?, :raise_not_set_error
- alias_method :supported?, :raise_not_set_error
- alias_method :verified?, :raise_not_set_error
- alias_method :unstable?, :raise_not_set_error
- alias_method :handle, :raise_not_set_error
- alias_method :display_name, :raise_not_set_error
- alias_method :supported, :raise_not_set_error
- alias_method :verified, :raise_not_set_error
- alias_method :latest_supported, :raise_not_set_error
- alias_method :name, :raise_not_set_error
- end
- end
- end
- end
|