feat: link uuid + increase counter concurrently

This commit is contained in:
Juan Rodriguez
2024-05-13 08:08:20 +02:00
parent b34a52f3e0
commit e4ae0c2ac4
5 changed files with 38 additions and 6 deletions
@@ -1,10 +1,10 @@
-- +micrate Up
-- SQL in section 'Up' is executed when this migration is applied
CREATE TABLE links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
id TEXT PRIMARY KEY NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
url TEXT NOT NULL,
click_counter INTEGER DEFAULT 0,
click_counter INTEGER NOT NULL DEFAULT 0,
created_at INTEGER DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at INTEGER DEFAULT CURRENT_TIMESTAMP NOT NULL
);
+27 -2
View File
@@ -1,3 +1,5 @@
require "uuid"
require "../lib/controller.cr"
module App::Controllers::Link
@@ -11,6 +13,7 @@ module App::Controllers::Link
raise App::BadRequestException.new(env) if !url #TODO: return url "required field" error message
link = Link.new
link.id = UUID.v4().to_s
link.url = url.to_s
link.slug = Random::Secure.urlsafe_base64(4)
@@ -36,11 +39,33 @@ module App::Controllers::Link
link = Database.get_by(Link, slug: slug)
raise App::NotFoundException.new(env) if !link
#TODO: update click_counter
spawn do
link.click_counter = link.click_counter! + 1
changeset = Database.update(link)
if changeset.errors.any?
Log.error { "Increase click counter failed: #{changeset.errors}"}
end
end
env.redirect link.url!
end
end
#TODO: update, delete, list links
class Get < App::Lib::BaseController
include App::Models
include App::Lib
def call(env)
id = env.params.url["id"]
link = Database.get(Link, id)
raise App::NotFoundException.new(env) if !link
response = {"data" => App::Serializers::Link.new(link) }
response.to_json
end
end
#TODO: update, delete
end
+2 -1
View File
@@ -4,9 +4,10 @@ require "crecto"
module App::Models
class Link < Crecto::Model
schema :links do
field :id, String, primary_key: true
field :slug, String
field :url, String
field :click_counter, Int64
field :click_counter, Int64, default: 0
end
validate_required [:slug, :url]
+4
View File
@@ -13,6 +13,10 @@ module App
Controllers::Link::Index.new.call(env)
end
get "/api/links/:id" do |env|
Controllers::Link::Get.new.call(env)
end
post "/api/links" do |env|
Controllers::Link::Create.new.call(env)
end
+3 -1
View File
@@ -9,8 +9,10 @@ module App::Serializers
def to_json(builder : JSON::Builder)
builder.object do
builder.field("origin", @link.url)
builder.field("id", @link.id)
builder.field("link", "#{ENV["APP_URL"]}/#{@link.slug}")
builder.field("clicks", @link.click_counter)
builder.field("origin", @link.url)
end
end
end