add server (only with basic search for now)

This commit is contained in:
King Kévin 2023-01-23 14:13:43 +01:00
parent 99ad35f618
commit 8649abb725
2 changed files with 196 additions and 0 deletions

78
public/index.html Normal file
View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<title>electronic parts database explorer</title>
<script type='application/javascript'>
"use strict";
// the last search query
var last_search = null;
function search()
{
const terms = document.getElementById('terms');
if (terms && terms.value && terms.value.length >= 3) {
console.log(terms.value);
} else {
return;
}
last_search = '/search/' + terms.value;
let xhr = new XMLHttpRequest();
xhr.open('GET', last_search, true);
xhr.onload = function() {
if (this.responseURL.endsWith(last_search)) {
populate(JSON.parse(this.response));
}
};
xhr.onerror = function() {
console.log("search call failed");
};
xhr.send();
}
function populate(parts)
{
const results = document.getElementById('results');
results.innerHTML = null;
for (const part of parts) {
console.log(part);
const tr = document.createElement('tr');
for (const key of ["name", "description"]) {
const td = document.createElement('td');
td.innerHTML = part[key];
tr.appendChild(td);
}
results.appendChild(tr);
}
}
</script>
<style>
table {
border: 1px #E1E3F2 solid;
width: 500px;
resize: both;
overflow: auto;
}
</style>
</head>
<body>
<div>
<form>
<input type="text" id="terms" name="terms" placeholder="search terms" oninput="search()"><br>
</form>
</div>
<div>
<table>
<thead>
<tr>
<th>name</th>
<th>description</th>
<th>stock</th>
</tr>
</thead>
<tbody id="results"></tbody>
</table>
</div>
</body>
</html>

118
server.rb Executable file
View File

@ -0,0 +1,118 @@
#!/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.name, part.description, part.datasheet, manufacturer.name AS manufacturer, package.name AS package, part.pincount AS pincount, part.page AS page, part.family AS family 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, :as => :hash).to_a[0]
return nil unless part
# merge with family info
while part and part["family"] do
family = statement.execute(part["family"]).to_a[0]
part["family"] = nil # reset info
break unless family
family.each do |k,v|
part[k] ||= v
end
end
# clean up
delete = ["family"]
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