#!/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) 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 = ?") part = statement.execute(id).to_a[0] return nil unless part # merge with family info while part and part["parent"] do family = statement.execute(part["parent"]).to_a[0] part["parent"] = nil # reset info break unless family part["family"] ||= family["name"] family.each do |k,v| part[k] ||= v end end # 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 # 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 # clean up 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