Skip to content

Commit

Permalink
Add Application::Urn
Browse files Browse the repository at this point in the history
This service will retreive the associated urn for an application that
exists in the database.

When the availabe urn set is exhausted it will increase its size automatically.
  • Loading branch information
fumimowdan committed Oct 31, 2023
1 parent 6e9281d commit 1d06010
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
81 changes: 81 additions & 0 deletions app/models/application/urn.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#
# build a pseudo random urns list with the existing urns removed from that list
# and we calculate the global index of the current application based on list sorted by created_at
# then we get the urn located at the determined application index
#

class Application::Urn
class << self
def reset_urns
const_set(:URNS, build_urns)
nil
end

def build_urns
{
"teacher" => build_list("TE"),
"salaried_trainee" => build_list("ST"),
}.freeze
end

def build_list(code)
su_size = LENGTH.to_s.size
Array
.new(LENGTH) { [PREFIX, code, sprintf("%0##{su_size}d", _1)].join }
.drop(1)
.shuffle!
end
end

LENGTH = 99_999
PREFIX = "IRP".freeze
URNS = build_urns

def initialize(application)
@application = application
end

def urn
MUTEX.synchronize do
increase_suffix if urns_exhausted?
available_urns[application_index]
end
end

private

def increase_suffix
self.class.const_set(:LENGTH, "#{self.class::LENGTH}9".to_i)
self.class.reset_urns
end

def urns_exhausted?
application_index > available_urns.size
end

def application_index
return @application_index if @application_index

@application_index = FindApplicationIndexQuery
.new(application_id: @application.id)
.execute
.to_a
.dig(0, "application_index")

raise(ArgumentError, "application not found") unless @application_index

@application_index -= 1 # FindApplicationIndexQuery returns a index starting at 1
@application_index -= used_urns.size # removes the existing applications to have a correct index
@application_index
end

def available_urns
@available_urns ||= URNS.fetch(@application.application_route) - used_urns
end

def used_urns
@used_urns ||= Application.where(application_route: @application.application_route).pluck(:urn)
end

MUTEX = Mutex.new
end
35 changes: 35 additions & 0 deletions spec/models/application/urn_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require "rails_helper"

RSpec.describe Application::Urn do
describe "constants" do
it { expect(described_class::LENGTH).to eq(99_999) }
it { expect(described_class::PREFIX).to eq("IRP") }
it { expect(described_class::URNS.keys).to contain_exactly("teacher", "salaried_trainee") }
it { expect(described_class::URNS.dig("teacher", 1)).to include("IRPTE") }
it { expect(described_class::URNS.fetch("teacher").size).to eq(99_998) }
it { expect(described_class::URNS.dig("salaried_trainee", 1)).to include("IRPST") }
it { expect(described_class::URNS.fetch("salaried_trainee").size).to eq(99_998) }
end

describe "urn" do
subject(:service) { described_class.new(application) }

context "teacher" do
let(:application) { create(:teacher_application) }

it { expect(service.urn).to include("IRPTE") }
end

context "salaried_trainee" do
let(:application) { create(:salaried_trainee_application) }

it { expect(service.urn).to include("IRPST") }
end

context "missing application" do
let(:application) { build(:salaried_trainee_application) }

it { expect { service.urn }.to raise_error(ArgumentError, "application not found") }
end
end
end

0 comments on commit 1d06010

Please sign in to comment.