# frozen_string_literal: true require 'roda/endpoints/endpoint' require 'roda/endpoints/endpoint/data' require 'roda/endpoints/endpoint/caching' class Roda module Endpoints class Endpoint # HTTP endpoint representing a specific item of collection uniquely # identified by some parameter. class Item < Endpoint include Data include Caching self.attributes += %i(id by finder last_modified) self.defaults = defaults.merge( by: :fetch, finder: lambda do repository.public_send(by, id) end, last_modified: :updated_at ) # @return [Symbol] attr_reader :by # @return [Symbol] attr_reader :id # @return [Symbol] attr_reader :finder # @return [Endpoint::Collection] def collection parent end # @return [ROM::Struct] def entity @entity ||= fetch_entity end def fetch_entity instance_exec(&finder) end def last_modified @last_modified ? entity.public_send(@last_modified) : super end route do |r, endpoint| endpoint.verbs.each do |verb| # @route #{verb} /{collection.name}/{id} # STDOUT.puts [verb].pretty_inspect r.public_send(verb, transaction: verb) end end transaction :get do |endpoint| step :retrieve, with: endpoint.operation_for(:get) end transaction :patch do |endpoint| step :validate, with: endpoint.validation_for(:patch) step :persist, with: endpoint.operation_for(:patch) end transaction :put do |endpoint| step :validate, with: endpoint.validation_for(:put) # step :reset, with: 'endpoints.operations.reset' step :persist, with: endpoint.operation_for(:put) end transaction :delete do |endpoint| step :validate, with: endpoint.validation_for(:delete) step :persist, with: endpoint.operation_for(:delete) end # @route GET /{collection.name}/{id} # @param [Hash] params # @return [Dry::Monads::Either] verb :get do |_params| Right(entity) end # @route PATCH /{collection.name}/{id} # @return [Dry::Monads::Either] verb :patch do |params| changeset = params[name] Right(repository.update(id, changeset)) end # @route PUT /{collection.name}/{id} # @return [Dry::Monads::Either] verb :put do |params| changeset = entity.to_hash.keys.each_with_object( {} ) do |key, changeset| changeset[key] = nil end.merge(params[name] || {}) Right(repository.update(id, changeset)) end # @route DELETE /{collection.name}/{id} # @return [Dry::Monads::Either] verb :delete do |_params| if (result = repository.delete(id)) Right(nil) else Left(result) end end end end end end