738 lines
28 KiB
JavaScript
738 lines
28 KiB
JavaScript
//#region import
|
||
|
||
var http = require('http');
|
||
var fs = require('fs');
|
||
const express = require('express');
|
||
const WebSocket = require('ws');
|
||
const app = express();
|
||
const server = http.createServer(app);
|
||
const wss = new WebSocket.Server({ server });
|
||
server.listen(80, () => {
|
||
console.log(`Server started on port ${server.address().port} :)`);
|
||
});
|
||
|
||
const pg = require('pg');
|
||
const { Pool, Client } = pg
|
||
const pool = new Pool({
|
||
user: 'd',
|
||
password: '123',
|
||
host: '192.168.56.104',
|
||
port: 5432,
|
||
database: 'mydb',
|
||
})
|
||
async function query(q) {
|
||
return (await pool.query(q)).rows;
|
||
}
|
||
|
||
|
||
//#endregion
|
||
|
||
|
||
//#region Server CRUD Interface
|
||
|
||
function getTables() {
|
||
return query(`SELECT table_name
|
||
FROM information_schema.tables
|
||
WHERE table_schema='public'
|
||
AND table_type='BASE TABLE';`);
|
||
}
|
||
|
||
async function getTable(data) {
|
||
let table = data[0], filters = data[1];
|
||
if (table == "moovie") {
|
||
//q =
|
||
}
|
||
let q = `select * from ` + table;
|
||
|
||
let isFilters = false;
|
||
if (Array.isArray(filters) && filters.length != 0) {
|
||
q += " WHERE ";
|
||
filters.forEach(f => {
|
||
isFilters = true;
|
||
|
||
let n = typeof f[1] == "string" && f[1].length > 1 && (f[1][0] == ">" || f[1][0] == "<");
|
||
if (f[0] != null && f[1] != "") {
|
||
if (typeof f[1] == "number")
|
||
q += f[0] + "=" + f[1] + " AND ";
|
||
else
|
||
q += f[0] + (n ? "" : " LIKE '%") + f[1] + (n ? "" : "%'") + " AND ";
|
||
}
|
||
})
|
||
}
|
||
if (isFilters) q = q.slice(0, -4);
|
||
let querry = q;
|
||
try {
|
||
|
||
q = await query(q);
|
||
} catch {
|
||
return null;
|
||
}
|
||
q[q.length] = table;
|
||
q["querry"] = querry;
|
||
return q;
|
||
}
|
||
|
||
async function getDifficultMoovies() {
|
||
let q = `SELECT moovie_id, moovie_name, rating_rate, moovie_productionYear, moovie_about, moovie_timeAdded, subscription_name, subscription_price
|
||
FROM moovie
|
||
INNER JOIN rating ON moovie.moovie_id = rating.rating__fk_moovie
|
||
INNER JOIN subscription ON subscription_id = (
|
||
select customer__fk_subsription from customer
|
||
where customer_id = 9
|
||
)
|
||
where moovie_id IN (
|
||
select mooviesubscription_fk_moovie_id from moovieSubscription
|
||
Where moovieSubscription_fk_subscription_id = (
|
||
select customer__fk_subsription from customer
|
||
where customer_id = 9
|
||
)
|
||
);
|
||
`;
|
||
let querry = q;
|
||
q = await query(q);
|
||
q["querry"] = querry;
|
||
return q;
|
||
}
|
||
|
||
|
||
//#region Generate Interface
|
||
|
||
function createTabless() {
|
||
let q = `DROP TABLE if exists moovie cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_moovie;
|
||
|
||
CREATE SEQUENCE SEQ_moovie INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE moovie (
|
||
moovie_id integer PRIMARY KEY DEFAULT nextval('SEQ_moovie'),
|
||
moovie_name varchar(50) NOT NULL,
|
||
moovie_productionYear integer NOT NULL,
|
||
moovie_about varchar(50) NOT NULL,
|
||
moovie_timeAdded date NOT NULL
|
||
);
|
||
|
||
DROP TABLE if exists genre cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_genre;
|
||
|
||
CREATE SEQUENCE SEQ_genre INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE genre (
|
||
genre_id integer PRIMARY KEY DEFAULT nextval('SEQ_genre'),
|
||
genre_name varchar(50) NOT NULL
|
||
);
|
||
|
||
DROP TABLE if exists moovieGenre cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_moovieGenre;
|
||
|
||
CREATE SEQUENCE SEQ_moovieGenre INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE moovieGenre (
|
||
moovieGenre_id integer PRIMARY KEY DEFAULT nextval('SEQ_moovieGenre'),
|
||
moovieGenre_fk_moovie_id int REFERENCES moovie (moovie_id),
|
||
moovieGenre_fk_genre_id int REFERENCES genre (genre_id)
|
||
);
|
||
|
||
DROP TABLE if exists subscription cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_subscription;
|
||
|
||
CREATE SEQUENCE SEQ_subscription INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE subscription (
|
||
subscription_id integer PRIMARY KEY DEFAULT nextval('SEQ_subscription'),
|
||
subscription_name varchar(50) NOT NULL,
|
||
subscription_price integer NOT NULL,
|
||
subscription_fk_parentSubscription_id int NULL REFERENCES subscription (subscription_id)
|
||
);
|
||
|
||
DROP TABLE if exists moovieSubscription cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_moovieSubscription;
|
||
|
||
CREATE SEQUENCE SEQ_moovieSubscription INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE moovieSubscription (
|
||
moovieSubscription_id integer PRIMARY KEY DEFAULT nextval('SEQ_moovieSubscription'),
|
||
moovieSubscription_fk_moovie_id int REFERENCES moovie (moovie_id),
|
||
moovieSubscription_fk_subscription_id int REFERENCES subscription (subscription_id)
|
||
);
|
||
|
||
DROP TABLE if exists customer cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_customer;
|
||
|
||
CREATE SEQUENCE SEQ_customer INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE customer (
|
||
customer_id integer PRIMARY KEY DEFAULT nextval('SEQ_customer'),
|
||
customer_name varchar(50) NOT NULL,
|
||
customer_email varchar(50) NOT NULL,
|
||
customer_password varchar(50) NOT NULL,
|
||
customer_age int NOT NULL,
|
||
customer_phone varchar(50) NOT NULL,
|
||
customer__fk_subsription int NOT NULL REFERENCES subscription (subscription_id)
|
||
);
|
||
|
||
DROP TABLE if exists rating cascade;
|
||
|
||
DROP SEQUENCE if exists SEQ_rating;
|
||
|
||
CREATE SEQUENCE SEQ_rating INCREMENT BY 1 START WITH 1;
|
||
|
||
CREATE TABLE rating (
|
||
rating_id integer PRIMARY KEY DEFAULT nextval('SEQ_rating'),
|
||
rating_rate int NOT NULL,
|
||
rating_fk_user int NOT NULL REFERENCES customer (customer_id),
|
||
rating__fk_moovie int NOT NULL REFERENCES moovie (moovie_id)
|
||
);
|
||
|
||
|
||
COMMENT ON TABLE public.moovie IS 'Это таблица о Фильмах';
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_name SET NOT NULL;
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_name SET DEFAULT 'Название фильма';
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_productionYear SET NOT NULL;
|
||
--ALTER TABLE public.moovie ALTER COLUMN moovie_productionYear SET DEFAULT 2000;
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_about SET NOT NULL;
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_about SET DEFAULT 'Описание фильма';
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_timeAdded SET NOT NULL;
|
||
ALTER TABLE public.moovie ALTER COLUMN moovie_timeAdded SET DEFAULT '2024-06-16 12:00:00';
|
||
|
||
COMMENT ON TABLE public.genre IS 'Это таблица о Жанрах фильмов';
|
||
ALTER TABLE public.genre ALTER COLUMN genre_name SET NOT NULL;
|
||
ALTER TABLE public.genre ALTER COLUMN genre_name SET DEFAULT 'Название жанра';
|
||
|
||
COMMENT ON TABLE public.moovieGenre IS 'Это таблица много ко многим для таблиц Фильм и Жанр';
|
||
ALTER TABLE public.moovieGenre ALTER COLUMN moovieGenre_fk_moovie_id SET NOT NULL;
|
||
ALTER TABLE public.moovieGenre ALTER COLUMN moovieGenre_fk_genre_id SET NOT NULL;
|
||
|
||
COMMENT ON TABLE public.subscription IS 'Это таблица о подписках на фильмы';
|
||
ALTER TABLE public.subscription ALTER COLUMN subscription_name SET NOT NULL;
|
||
ALTER TABLE public.subscription ALTER COLUMN subscription_name SET DEFAULT 'Подписка';
|
||
ALTER TABLE public.subscription ALTER COLUMN subscription_price SET NOT NULL;
|
||
ALTER TABLE public.subscription ALTER COLUMN subscription_price SET DEFAULT 999;
|
||
|
||
|
||
COMMENT ON TABLE public.customer IS 'Это таблица о пользователях';
|
||
ALTER TABLE public.customer ALTER COLUMN customer_name SET NOT NULL;
|
||
ALTER TABLE public.customer ALTER COLUMN customer_name SET DEFAULT 'Пользователь 1';
|
||
ALTER TABLE public.customer ALTER COLUMN customer_password SET NOT NULL;
|
||
ALTER TABLE public.customer ALTER COLUMN customer_password SET DEFAULT '123';
|
||
ALTER TABLE public.customer ALTER COLUMN customer_age SET NOT NULL;
|
||
ALTER TABLE public.customer ALTER COLUMN customer_age SET DEFAULT '18';
|
||
ALTER TABLE public.customer ALTER COLUMN customer_phone SET NOT NULL;
|
||
ALTER TABLE public.customer ALTER COLUMN customer__fk_subsription SET NOT NULL;
|
||
|
||
|
||
COMMENT ON TABLE public.rating IS 'Это таблица об отзывах про фильмы';
|
||
ALTER TABLE public.rating ALTER COLUMN rating_rate SET NOT NULL;
|
||
ALTER TABLE public.rating ALTER COLUMN rating_rate SET DEFAULT 10;
|
||
ALTER TABLE public.rating ALTER COLUMN rating_fk_user SET NOT NULL;
|
||
ALTER TABLE public.rating ALTER COLUMN rating_fk_user SET DEFAULT 0;
|
||
ALTER TABLE public.rating ALTER COLUMN rating__fk_moovie SET NOT NULL;
|
||
ALTER TABLE public.rating ALTER COLUMN rating__fk_moovie SET DEFAULT 0;
|
||
|
||
|
||
|
||
ALTER TABLE public.mooviegenre DROP CONSTRAINT mooviegenre_mooviegenre_fk_genre_id_fkey;
|
||
ALTER TABLE public.mooviegenre ADD CONSTRAINT mooviegenre_mooviegenre_fk_genre_id_fkey FOREIGN KEY (mooviegenre_fk_genre_id) REFERENCES public.genre(genre_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
ALTER TABLE public.mooviegenre DROP CONSTRAINT mooviegenre_mooviegenre_fk_moovie_id_fkey;
|
||
ALTER TABLE public.mooviegenre ADD CONSTRAINT mooviegenre_mooviegenre_fk_moovie_id_fkey FOREIGN KEY (mooviegenre_fk_moovie_id) REFERENCES public.moovie(moovie_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
|
||
ALTER TABLE public.mooviesubscription DROP CONSTRAINT mooviesubscription_mooviesubscription_fk_moovie_id_fkey;
|
||
ALTER TABLE public.mooviesubscription ADD CONSTRAINT mooviesubscription_mooviesubscription_fk_moovie_id_fkey FOREIGN KEY (mooviesubscription_fk_moovie_id) REFERENCES public.moovie(moovie_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
ALTER TABLE public.mooviesubscription DROP CONSTRAINT mooviesubscription_mooviesubscription_fk_subscription_id_fkey;
|
||
ALTER TABLE public.mooviesubscription ADD CONSTRAINT mooviesubscription_mooviesubscription_fk_subscription_id_fkey FOREIGN KEY (mooviesubscription_fk_subscription_id) REFERENCES public."subscription"(subscription_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
|
||
ALTER TABLE public."subscription" DROP CONSTRAINT subscription_subscription_fk_parentsubscription_id_fkey;
|
||
ALTER TABLE public."subscription" ADD CONSTRAINT subscription_subscription_fk_parentsubscription_id_fkey FOREIGN KEY (subscription_fk_parentsubscription_id) REFERENCES public."subscription"(subscription_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
|
||
ALTER TABLE public.customer DROP CONSTRAINT customer_customer__fk_subsription_fkey;
|
||
ALTER TABLE public.customer ADD CONSTRAINT customer_customer__fk_subsription_fkey FOREIGN KEY (customer__fk_subsription) REFERENCES public."subscription"(subscription_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
|
||
ALTER TABLE public.rating DROP CONSTRAINT rating_rating__fk_moovie_fkey;
|
||
ALTER TABLE public.rating ADD CONSTRAINT rating_rating__fk_moovie_fkey FOREIGN KEY (rating__fk_moovie) REFERENCES public.moovie(moovie_id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||
|
||
`;
|
||
|
||
return pool.query(q);
|
||
}
|
||
async function del() {
|
||
let q = `
|
||
DELETE FROM moovieSubscription;
|
||
DELETE FROM customer;
|
||
DELETE FROM genre;
|
||
DELETE FROM subscription;
|
||
DELETE FROM moovie;
|
||
|
||
|
||
ALTER SEQUENCE SEQ_moovie RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_genre RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_moovieGenre RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_subscription RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_moovieSubscription RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_customer RESTART WITH 1;
|
||
ALTER SEQUENCE SEQ_rating RESTART WITH 1;
|
||
`;
|
||
await pool.query(q);
|
||
}
|
||
|
||
let genress = ` Action Thriller Western Fantasy Science fiction Comedy Satire Drama Adventure Mystery Romantic comedy Melodrama Romance Hybrid genre Fairy tale Coming-of-age story Fantasy Suspense Detective fiction Biography Dark comedy Mystery Apocalyptic and post-apocalyptic fiction Slapstick Screenplay Historical drama Comedy horror Historical fantasy Body horror Tech noir Legal drama Film criticism`.split(" ");
|
||
async function createRandomGenres() {
|
||
let q = `
|
||
|
||
INSERT INTO genre VALUES
|
||
`;
|
||
for (let i = 0; i < count; i++) {
|
||
q += "(DEFAULT, '" + genress[Math.round((genress.length - 1) * Math.random())] + "'),";
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = "INSERT INTO genre VALUES";
|
||
return w;
|
||
}
|
||
async function createRandomUsers(subscriptionsLength = count) {
|
||
let q = `
|
||
INSERT INTO customer VALUES
|
||
`;
|
||
for (let i = 0; i < count; i++) {
|
||
let w = Math.round(Math.random() * (subscriptionsLength - 2) + 1);
|
||
//console.log(w);
|
||
q += "(DEFAULT, " +
|
||
"'user" + i + "', 'email" + i + "@gmail.com'," + " 'password" + i + "', "
|
||
+ Math.round(Math.random() * (50 - 18) + 18) + ", " + "'phoneNumber" + i + "', "
|
||
+ w
|
||
+ "),";
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = "INSERT INTO customer VALUES";
|
||
return w;
|
||
}
|
||
async function createRandomSubscriptions() {
|
||
let q = `
|
||
INSERT INTO subscription VALUES
|
||
`;
|
||
for (let i = 0; i < count; i++) {
|
||
q += "(DEFAULT, 'Подписка " + i.toString() + "', "
|
||
+ Math.round(Math.random() * 5000) + " " + ""/* Math.max(1, Math.round(Math.random() * (i-1))) */ + "),";
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = " INSERT INTO subscription VALUES";
|
||
return w;
|
||
//query(q);
|
||
}
|
||
async function createRandomMoovies() {
|
||
let q = `
|
||
INSERT INTO moovie VALUES
|
||
`;
|
||
for (let i = 0; i < count; i++) {
|
||
q += "(DEFAULT, 'Фильм" + i + "', "
|
||
+ Math.round(Math.random() * (2024 - 1980) + 1980) + ", 'Описание" + i + "', '" + "2004-01-22" + "'),";
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = "INSERT INTO moovie VALUES";
|
||
return w;
|
||
//query(q);
|
||
}
|
||
async function createRandomMoovieSubscriptions() {
|
||
let q = `
|
||
INSERT INTO moovieSubscription VALUES
|
||
`;
|
||
for (let i = 1; i < count / 10; i++) {
|
||
for (let t = 1; t < count / 5; t++) {
|
||
q += "(DEFAULT, " + t.toString() + ", " + i.toString() + "),";
|
||
}
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = "INSERT INTO moovieSubscription VALUES";
|
||
return w;
|
||
//query(q);
|
||
}
|
||
async function createRandomRatings() {
|
||
let q = `
|
||
INSERT INTO rating VALUES
|
||
`;
|
||
for (let t = 1; t < count; t++) {
|
||
q += "(DEFAULT, " + Math.round(Math.random() * 10) + ", " +
|
||
Math.round(Math.random() * (count - 2) + 1) + ", " +
|
||
Math.round(Math.random() * (count - 2) + 1) + "),";
|
||
}
|
||
let w = await pool.query(q.slice(0, -1));
|
||
w["querry"] = "INSERT INTO rating VALUES";
|
||
return w;
|
||
//query(q);
|
||
}
|
||
|
||
//#endregion
|
||
|
||
|
||
//#endregion
|
||
|
||
|
||
//#region Measure
|
||
|
||
var result = [];
|
||
async function measure(f, args = [], multipleTimes = true) {
|
||
return new Promise(async resolve => {
|
||
let commonTime = null, res = "";
|
||
for (let i = 0; i < 10; i++) {
|
||
let t1 = process.hrtime.bigint();
|
||
res = await f(...args);
|
||
let t2 = process.hrtime.bigint();
|
||
if (commonTime == null) commonTime = (Number(t2 - t1) / 10 ** 6);
|
||
else commonTime = (commonTime + (Number(t2 - t1) / 10 ** 6)) / 2;
|
||
if (multipleTimes == false) break;
|
||
}
|
||
|
||
//console.log(Number(t2 - t1).toString() + " nanoseconds");
|
||
result.push(res["querry"] + " : " + commonTime.toFixed(1).toString() + "мс"/* " милиСекунд (10*-3)" */);
|
||
resolve();
|
||
})
|
||
}
|
||
|
||
var count = 15;
|
||
async function createTables() {
|
||
let ts = await getTables();
|
||
if (true || ts.length == 0) {
|
||
await createTabless();
|
||
}
|
||
//await del();
|
||
|
||
await measure(createRandomSubscriptions, [], false);
|
||
await measure(createRandomGenres, [], false);
|
||
await measure(createRandomUsers, [], false);
|
||
await measure(createRandomMoovies, [], false);
|
||
await measure(createRandomMoovieSubscriptions, [], false);
|
||
await measure(createRandomRatings, [], false);
|
||
|
||
await measure(getTable, [["subscription", []]])
|
||
await measure(getTable, [["moovie", []]])
|
||
await measure(getTable, [["moovie", [["moovie_productionYear", ">2021"], ["moovie_name", "2"]]]]);
|
||
await measure(getTable, [["genre", []]]);
|
||
await measure(getTable, [["moovieGenre", []]]);
|
||
await measure(getTable, [["subscription", []]]);
|
||
await measure(getTable, [["moovieSubscription", []]]);
|
||
await measure(getTable, [["customer", []]]);
|
||
await measure(getTable, [["rating", []]]);
|
||
await measure(getDifficultMoovies);
|
||
|
||
result.unshift("№ Запрос:Среднее время")
|
||
console.log(result.slice(0, -1).map((a, index) => ((index).toString() + ": " + a + ": ")).join(" "));
|
||
console.log(result[result.length - 1]);
|
||
}
|
||
|
||
//#endregion
|
||
|
||
|
||
function wsInterface() {
|
||
try {
|
||
ws = new WebSocket('ws://localhost:80')
|
||
} catch { }
|
||
ws.onopen = () => {
|
||
//document.getElementById('selects').children[0].select = true;
|
||
getTableInterface(document.getElementById('selects'));
|
||
console.log('ws opened on browser')
|
||
//ws.send('hello world')
|
||
}
|
||
ws.onclose = () => {
|
||
location.reload()
|
||
};
|
||
ws.onmessage = (message) => {
|
||
let data = JSON.parse(message.data).data;
|
||
|
||
callbacks[data[0].toString()](data[1]);
|
||
//console.log(`message received ${message}`)
|
||
}
|
||
}
|
||
wss.on('connection', (ws) => {
|
||
wsocket = ws;
|
||
ws.on('message', async (message) => {
|
||
let data = JSON.parse(message);
|
||
if (data?.type == "getTable") {
|
||
send([data.querry[0], await getTable(data.querry[1])]);
|
||
|
||
}
|
||
else if (data?.type == "create") {
|
||
pool.query(data.querry)
|
||
}
|
||
else if (data?.type == "update") {
|
||
pool.query(data.querry)
|
||
}
|
||
else if (data?.type == "delete") {
|
||
let qe = `
|
||
SET FOREIGN_KEY_CHECKS=0;
|
||
` + data.querry + `
|
||
SET FOREIGN_KEY_CHECKS=1;
|
||
`;
|
||
pool.query(data.querry)
|
||
}
|
||
});
|
||
});
|
||
|
||
|
||
//#region HTML CRUD Interface
|
||
|
||
function create(th) {
|
||
let newValues = Array.from(th.parentElement.children).slice(0, -1).map(a => "'" + a.children[0].value + "'");
|
||
ws.send(JSON.stringify({
|
||
"type": "create",
|
||
"querry": "INSERT INTO " + th.parentElement.parentElement.parentElement.getAttribute("name") + " VALUES (DEFAULT, " + newValues.slice(1, newValues.length).join(", ") + ")"
|
||
}));
|
||
setTimeout(() => {
|
||
getTableInterface(document.getElementById("selects"))
|
||
}, 100);
|
||
}
|
||
|
||
function change(th) {
|
||
let textarea = true;
|
||
|
||
let a = Array.from(th.parentElement.children);
|
||
a.slice(0, -2).forEach(element => {
|
||
if (textarea)
|
||
element.innerHTML = `<textarea type="text" style="width: 100%;">` + element.outerText + `</textarea>`;
|
||
else
|
||
element.innerHTML = `<input type="text" value="` + element.outerText + `" style="width: 100%;"></input>`;
|
||
})
|
||
a[a.length - 2].onclick = function () { update(this) };
|
||
a[a.length - 2].innerHTML = `
|
||
<td onclick=update(this)>
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-return-left" viewBox="0 0 16 16">
|
||
<path fill-rule="evenodd" d="M14.5 1.5a.5.5 0 0 1 .5.5v4.8a2.5 2.5 0 0 1-2.5 2.5H2.707l3.347 3.346a.5.5 0 0 1-.708.708l-4.2-4.2a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 8.3H12.5A1.5 1.5 0 0 0 14 6.8V2a.5.5 0 0 1 .5-.5"/>
|
||
</svg>
|
||
</td>
|
||
`;
|
||
}
|
||
function update(th) {
|
||
let a = Array.from(th.parentElement.children);
|
||
let querry = `UPDATE ` + th.parentElement.parentElement.parentElement.getAttribute("name") + " SET ";
|
||
let types = Array.from(th.parentElement.parentElement.children[0].children).map(a => a.getAttribute("type"));
|
||
let at = Array.from(th.parentElement.parentElement.children[0].children).map(a => a.outerText);
|
||
a.slice(1, -2).forEach((element, index) => {
|
||
querry += at[index + 1] + " = ";
|
||
if (types[index + 1] == "number")
|
||
querry += element.children[0].value + ",";
|
||
else
|
||
querry += "'" + element.children[0].value + "',";
|
||
})
|
||
querry = querry.slice(0, -1);
|
||
querry += " WHERE " + at[0] + "=" + a[0].children[0].value;
|
||
|
||
ws.send(JSON.stringify({
|
||
"type": "update",
|
||
"querry": querry
|
||
}));
|
||
|
||
a.slice(0, -2).forEach(element => {
|
||
element.innerHTML = element.children[0].value
|
||
})
|
||
a[a.length - 2].onclick = function () { change(this) };
|
||
a[a.length - 2].innerHTML = `
|
||
<td onclick=change(this)>
|
||
<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
|
||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2z"/>
|
||
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466"/>
|
||
</svg>
|
||
</td> `;
|
||
|
||
}
|
||
|
||
function remove(th) {
|
||
let a = Array.from(th.parentElement.children);
|
||
let at = Array.from(th.parentElement.parentElement.children[0].children).map(a => a.outerText);
|
||
ws.send(JSON.stringify({
|
||
"type": "delete",
|
||
"querry": "DELETE FROM " + th.parentElement.parentElement.parentElement.getAttribute("name") + " Cascade WHERE " + at[0] + "=" + + a[0].outerText
|
||
}));
|
||
th.parentElement.remove();
|
||
}
|
||
|
||
async function getTableInterface(th) {
|
||
let newFilter = th.id == "selects";
|
||
var g = document.getElementById("filter");
|
||
if (newFilter == false && g != null) {
|
||
let types = Array.from(document.getElementById("table").children[0].children[0].children).map(a => a.getAttribute("type"));
|
||
let at = Array.from(document.getElementById("table").children[0].children[0].children).map(a => a.outerText);;
|
||
g = Array.from(g.children[0].children[0].children)
|
||
.map((a, index) => [at[index], (types[index] == "number" && a.children[0].value != "" && a.children[0].value[0] != "<" && a.children[0].value[0] != ">" ? Number(a.children[0].value) : a.children[0].value)]);
|
||
}
|
||
else {
|
||
g = null
|
||
}
|
||
let table = [await sendInterface("getTable", [document.querySelector("#selects")[document.querySelector("#selects").selectedIndex].value, g])];
|
||
//let tables = await createTables();
|
||
if (table[0] == null) {
|
||
return;
|
||
}
|
||
table = table.map(t => createTableFromJSON(t, newFilter));
|
||
|
||
let d = document.getElementById("table")
|
||
if (newFilter) d = document.body.children[1];
|
||
if (table[0].length < 50) {
|
||
while (d.children[0].childNodes.length > 1) {
|
||
d.children[0].removeChild(d.children[0].lastChild);
|
||
}
|
||
} else {
|
||
d.innerHTML = table;
|
||
}
|
||
document.body.children[1].id = "";
|
||
}
|
||
|
||
//#endregion
|
||
|
||
|
||
//#region html Table Interfaces
|
||
|
||
function createTableFromJSON(jsonData, newFilter = false) {
|
||
let name = jsonData[jsonData.length - 1];
|
||
delete jsonData[jsonData.length - 1];
|
||
|
||
let text = "";
|
||
|
||
if (newFilter || document.getElementById("filter") == null) {
|
||
text = "<table id='filter'>";
|
||
Object.values(jsonData).forEach((row, index) => {
|
||
if (index == 0) {
|
||
text += "<tr>";
|
||
Object.keys(row).forEach((t, index) => {
|
||
text += "<td>" + `<textarea onkeyup =getTableInterface(this) type="text" style="width: 100%;">` + "" + `</textarea>` + "</td>";
|
||
});
|
||
text += "<td>" + `<textarea onkeyup =getTableInterface(this) type="text" style="width: 100%;">` + "" + `</textarea>` + "</td>";
|
||
text += "<td>" + `<textarea onkeyup =getTableInterface(this) type="text" style="width: 100%;">` + "" + `</textarea>` + "</td>";
|
||
text += "</tr>";
|
||
}
|
||
});
|
||
text += "</table> ";
|
||
}
|
||
|
||
text += "<table id='table' border='1' name='" + name + "'>";
|
||
Object.values(jsonData).forEach((row, index) => {
|
||
if (index == 0) {
|
||
text += "<tr>";
|
||
let v = Object.values(row);
|
||
Object.keys(row).forEach((t, index) => {
|
||
text += "<td type=" + (typeof v[index]).toString() + ">" + t + "</td>";
|
||
});
|
||
text += "</tr>";
|
||
}
|
||
text += "<tr>";
|
||
Object.values(row).forEach(t => {
|
||
if (t instanceof Date) t = t.toLocaleString('ru-RU')
|
||
text += "<td>" + (t == null ? "" : t.toString()) + "</td>";
|
||
});
|
||
|
||
text += `
|
||
<td onclick=change(this)>
|
||
<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
|
||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2z"/>
|
||
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466"/>
|
||
</svg>
|
||
</td>
|
||
|
||
<td onclick=remove(this)>
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-x" viewBox="0 0 16 16">
|
||
<path d="M6.146 6.146a.5.5 0 0 1 .708 0L8 7.293l1.146-1.147a.5.5 0 1 1 .708.708L8.707 8l1.147 1.146a.5.5 0 0 1-.708.708L8 8.707 6.854 9.854a.5.5 0 0 1-.708-.708L7.293 8 6.146 6.854a.5.5 0 0 1 0-.708"/>
|
||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm0 1h8a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1"/>
|
||
</svg>
|
||
</td>
|
||
</tr>`;
|
||
if (index == Object.values(jsonData).length - 1) {
|
||
Object.values(row).forEach(t => {
|
||
if (t instanceof Date) t = t.toLocaleString('ru-RU')
|
||
text += "<td>" + `<textarea type="text" style="width: 100%;">` + (t == null ? "" : t.toString()) + `</textarea>` + "</td>";
|
||
});
|
||
text += "<td onclick=create(this)>" + `Create` + "</td>";
|
||
}
|
||
//text += " </tr>";
|
||
});
|
||
|
||
return text;
|
||
};
|
||
|
||
let functionsToImport = [
|
||
createTableFromJSON,
|
||
create, change, update, remove, getTableInterface,
|
||
wsInterface, sendInterface,
|
||
"var ws; var id = 0, callbacks = []; wsInterface(); let w; ",
|
||
];
|
||
var once = true;
|
||
app.get('/', async function (request, response) {
|
||
if (once) {
|
||
once = false;
|
||
let tables = await createTables();
|
||
}
|
||
let ts = await getTables();
|
||
ts = ts.map(t => {
|
||
return "<option value=" + t.table_name + ">" + t.table_name + "</option>"
|
||
var option = document.createElement("option");
|
||
option.value = t.table_name;
|
||
option.text = t.table_name;
|
||
return option.toString();
|
||
})
|
||
let qw = `
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Document</title>
|
||
<style>
|
||
*{
|
||
font-size: 14px;
|
||
}
|
||
table {
|
||
width: 100%;
|
||
table-layout: fixed;
|
||
border-collapse: collapse;
|
||
margin: 20px;
|
||
}
|
||
th, td {
|
||
padding-right: 7px;
|
||
padding-left: 7px;
|
||
}
|
||
td {
|
||
overflow: hidden;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<select id="selects" onchange=getTableInterface(this) name="Таблица">
|
||
`+ ts.join(" ") + `
|
||
</select>
|
||
<div id="table"></div>`
|
||
+ " <script> " + (functionsToImport.map(a => a.toString())).join(" ") +
|
||
" </script> " + `
|
||
</body>
|
||
</html>
|
||
`;
|
||
|
||
response.writeHeader(200, { 'Content-Type': 'html' });
|
||
response.write(qw);
|
||
response.end();
|
||
})
|
||
|
||
let wsocket;
|
||
function send(data) {
|
||
wsocket.send(JSON.stringify({
|
||
data: data
|
||
}));
|
||
}
|
||
function sendInterface(s, data) {
|
||
return new Promise(resolve => {
|
||
ws.send(JSON.stringify({
|
||
"type": s,
|
||
"querry": [id, data]
|
||
}));
|
||
callbacks[id] = resolve;
|
||
id++
|
||
})
|
||
}
|
||
|
||
//#endregion
|
||
|