1
0
Fork 0
backend/main.rb

139 lines
3.2 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
require 'connection_pool'
require 'pg'
require 'sinatra'
require 'sinatra/json'
$DB_POOL = ConnectionPool.new size: 5, timeout: 5 do
PG.connect(
host: 'pg.causa-arcana.com',
dbname: 'leqsikoni',
user: 'leqsikoni',
password: 'ggeucene3ou7mqh2upehhm52tfp5bkcj',
).tap do |conn|
conn.type_map_for_results = PG::BasicTypeMapForResults.new conn
end
end
before do
headers 'Access-Control-Allow-Origin' => '*'
end
get '/words/:id' do
Context.call db_pool: $DB_POOL, user_lang_id: nil do |context|
word_id = Integer params[:id]
json({
part_of_speech: context.part_of_speech_name(word_id),
examples: context.examples(word_id),
})
end
end
class Context
private_class_method :new
def self.call(db_pool:, **kwargs, &block)
new(**kwargs).send :call, db_pool: db_pool, &block
end
def initialize(user_lang_id:)
self.user_lang_id = user_lang_id
end
private
attr_reader :user_lang_id
def call(db_pool:)
db_pool.with do |db_conn|
@db_conn = db_conn
result = yield self
@db_conn = nil
result
end
end
def user_lang_id=(user_lang_id)
return @user_lang_id = nil if user_lang_id.nil?
user_lang_id = Integer user_lang_id
raise unless user_lang_id.positive?
@user_lang_id = user_lang_id
end
public
##
# @return [String, nil]
#
def part_of_speech_name(word_id)
word_id = Integer word_id
column = @db_conn.exec_params(
(
<<~SQL
SELECT parts.english_name
FROM words
INNER JOIN parts
ON words.part_id = parts.id
WHERE words.id = $1
LIMIT 1
SQL
),
[word_id],
).values.first&.first
str = String(column).strip.freeze
str unless str.empty?
end
##
# @return [Array<Array(String, String)>]
#
def examples(word_id)
word_id = Integer word_id
result = @db_conn.exec_params(
(
<<~SQL
SELECT
array_agg(foo.value ORDER BY foo.language_id DESC)::text[] AS values
FROM example_texts foo
INNER JOIN (
SELECT example_id, language_id, MIN(index) as min_index
FROM example_texts
WHERE
example_id = ANY(
SELECT example_texts.example_id
FROM words
INNER JOIN word_forms
ON word_forms.word_id = words.id
INNER JOIN word_form_example_texts
ON word_form_example_texts.word_form_id = word_forms.id
INNER JOIN example_texts
ON example_texts.id = word_form_example_texts.example_text_id
WHERE words.id = $1
GROUP BY example_texts.example_id
)
AND
(language_id = 5 OR language_id = 2)
GROUP BY example_id, language_id
) bar
ON
foo.example_id = bar.example_id AND
foo.language_id = bar.language_id AND
foo.index = bar.min_index
GROUP BY foo.example_id
SQL
),
[word_id],
).map { |row| row['values'] }
result.map { |pair| pair.map(&:freeze).freeze }.freeze
end
end