partdb/server.rb

159 lines
4.6 KiB
Ruby
Raw Normal View History

#!/usr/bin/env ruby
# encoding: utf-8
# ruby: 3.0.2
=begin
server to query part database
to install sinatra
sudo pacman -S ruby-sinatra ruby-webrick
pikaur -S ruby-mysql2
=end
require 'set'
require 'mysql2'
require 'json'
require 'sinatra'
DEBUG = true
PARTS_LIMIT = 100
CREDENTIALS = "credentials.json"
raise "database information #{CREDENTIALS} do not exist" unless File.file? CREDENTIALS
# open server
configure do
if DEBUG then
set :show_exceptions, true
set :logging, true
else
set :show_exceptions, false
set :environment, :production
set :logging, false
end
set :protection, :except => :json_csrf
set :bind, 'localhost'
set :port, 4244
set :public_folder, "public"
set :static, true
end
before do
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
if request.request_method == 'OPTIONS'
response.headers["Access-Control-Allow-Methods"] = "GET,POST"
halt 200
end
# all replies are only JSON
content_type 'application/json'
# open database
credentials = {}
JSON.parse(IO.read(CREDENTIALS)).each {|key,value| credentials[key.to_sym] = value}
Mysql2::Client.default_query_options.merge!(:as => :hash)
@db = Mysql2::Client.new(credentials)
end
after do
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
end
get '/' do
redirect to('/index.html')
end
def get_part_by_id(id)
2023-01-25 05:15:15 +01:00
statement = @db.prepare("SELECT part.id, part.name, part.description, part.datasheet, manufacturer.name AS manufacturer, package.name AS package, part.pincount AS pincount, part.page AS page, part.family AS parent FROM part LEFT JOIN package ON package.id = part.package LEFT JOIN manufacturer ON manufacturer.id = part.manufacturer WHERE part.id = ?")
2023-01-25 07:48:36 +01:00
part = statement.execute(id).to_a[0]
return nil unless part
# merge with family info
2023-01-25 05:15:15 +01:00
while part and part["parent"] do
family = statement.execute(part["parent"]).to_a[0]
part["parent"] = nil # reset info
break unless family
2023-01-25 05:15:15 +01:00
part["family"] ||= family["name"]
family.each do |k,v|
part[k] ||= v
end
end
2023-01-25 07:47:48 +01:00
# add all distributors
distributors = @db.query("SELECT * FROM distributor").to_a
statement = @db.prepare("SELECT * FROM distribution WHERE part = ?")
distributions = statement.execute(id).to_a
distributors.each do |distributor|
distributions.each do |distribution|
if distribution["distributor"] == distributor["id"] then
distributor["sku"] = distribution["sku"]
distributor["url"] = distributor["product_page"].gsub("%s", distribution["sku"])
end
end
distributor.delete("id")
distributor.delete("homepage")
distributor.delete("product_page")
end
part["distributors"] = distributors
2023-01-25 08:46:21 +01:00
# add inventory
statement = @db.prepare("SELECT location.name AS location, inventory.quantity AS stock FROM inventory LEFT JOIN location ON location.id = inventory.location WHERE inventory.part = ? ORDER BY inventory.quantity DESC LIMIT 1")
inventory = statement.execute(id).to_a[0]
if inventory then
part["location"] = inventory["location"]
part["stock"] = inventory["stock"]
end
2023-01-25 11:22:26 +01:00
# add properties
part["properties"] = {}
family = id
statement = @db.prepare("SELECT property.name AS name, property_value.value AS value FROM property_value JOIN property ON property.id = property_value.property WHERE property_value.part = ?")
family_stmt = @db.prepare("SELECT family FROM part WHERE id = ?")
while family do
statement.execute(family).each do |row|
part["properties"][row["name"]] ||= []
part["properties"][row["name"]] << row["value"]
end
results = family_stmt.execute(family)
family = nil
results.each do |row|
family = row["id"]
end
end
# clean up
2023-01-25 05:15:15 +01:00
delete = ["parent"]
delete.each do |k|
part.delete k
end
return part
end
def get_part_by_name(name)
statement = @db.prepare("SELECT id FROM part WHERE part.name = ?")
id = statement.execute(name).to_a[0]
if id then
return get_part_by_id(id["id"])
else
return nil
end
end
get '/part/:name' do
part = get_part_by_name(params['name'])
halt 404 unless part
part.to_json
end
get '/search/:terms' do
terms = params['terms'].split(" ")
terms.keep_if {|term| term.length >= 3}
ids = Set.new
part_statement = @db.prepare("SELECT id FROM part WHERE name LIKE ?")
terms.each do |term|
part_statement.execute("%#{term}%").each do |row|
ids << row["id"]
end
end
puts ids
parts = ids.collect {|id| get_part_by_id(id)}
parts.compact!
parts = parts[0, PARTS_LIMIT]
parts.sort! {|x,y| x["name"] <=> y["name"]}
parts.to_json
end