some other stuff
Former-commit-id: d28d5c154962973c238e362cb44f6cecff37e7ce
This commit is contained in:
@@ -7,6 +7,18 @@ class Basket extends Component {
|
||||
super(Basket);
|
||||
}
|
||||
|
||||
OnMount() {
|
||||
const basket = localStorage.getItem('basket');
|
||||
if (basket) {
|
||||
const basketItems = JSON.parse(basket);
|
||||
this.setState({
|
||||
...basketItems,
|
||||
}, false);
|
||||
console.log(basketItems, this.state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Render() {
|
||||
return {
|
||||
template: /* html */`
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
<script type="module" src="/components/basket.mjs"></script>
|
||||
<script type="module" src="/components/basket-popout.mjs"></script>
|
||||
<script type="module" src="/components/accessability-popout.mjs"></script>
|
||||
<script type="module" src="/components/accessability-popout.mjs"></script>
|
||||
<script type="module" src="/components/notificationbar.mjs"></script>
|
||||
<script type="module" src="/components/storefront.mjs"></script>
|
||||
<script type="module" src="/components/tag.mjs"></script>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Database
|
||||
|
||||
I decided to go with a RDBMS, PostgreSql as I am familiar with it.
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
const ControllerMaster = require('./controller-master.js');
|
||||
const Database = require('../database/database.js');
|
||||
const Logger = require('../logger.js');
|
||||
|
||||
const PgFormat = require('pg-format');
|
||||
|
||||
async function Search(fuzzyString) {
|
||||
async function Search(fuzzyStrings) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id ~* $1 OR lego_brick.name ~* $1 OR tag.name ~* $1
|
||||
`, [fuzzyString]);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(PgFormat(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id ~* ANY(ARRAY[%L]) OR lego_brick.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L])
|
||||
`, fuzzyStrings, fuzzyStrings, fuzzyStrings), []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -30,8 +40,8 @@ async function Search(fuzzyString) {
|
||||
const bName = b.name.toLowerCase();
|
||||
const aTag = a.tag.toLowerCase();
|
||||
const bTag = b.tag.toLowerCase();
|
||||
const aFuzzy = fuzzyString.toLowerCase();
|
||||
const bFuzzy = fuzzyString.toLowerCase();
|
||||
const aFuzzy = fuzzyStrings[0].toLowerCase();
|
||||
const bFuzzy = fuzzyStrings[0].toLowerCase();
|
||||
|
||||
const aDist = ControllerMaster.LevenshteinDistance(aName, aFuzzy);
|
||||
const bDist = ControllerMaster.LevenshteinDistance(bName, bFuzzy);
|
||||
@@ -64,13 +74,22 @@ async function Search(fuzzyString) {
|
||||
|
||||
async function SumPrices(bricksArr, quantityArray) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(PgFormat(`
|
||||
SELECT COALESCE(new_price, price) AS "price"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_inventory AS brick_inventory ON brick_inventory.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id IN (%L);
|
||||
`, bricksArr), []);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(PgFormat(`
|
||||
SELECT COALESCE(new_price, price) AS "price"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_inventory AS brick_inventory ON brick_inventory.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id IN (%L);
|
||||
`, bricksArr), []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -90,15 +109,24 @@ async function SumPrices(bricksArr, quantityArray) {
|
||||
|
||||
async function GetBulkBricks(bricksArr) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(PgFormat(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id IN (%L);
|
||||
`, bricksArr), []);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(PgFormat(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
WHERE lego_brick.id IN (%L);
|
||||
`, bricksArr), []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -120,25 +148,34 @@ async function GetBulkBricks(bricksArr) {
|
||||
|
||||
async function GetBrick(brickId) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
|
||||
const dbres = await Database.Query(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag",
|
||||
inv.price, inv.new_price AS "discount", inv.stock,
|
||||
inv.last_updated AS "last_stock_update",
|
||||
weight, dimensions_x, dimensions_y, dimensions_z
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
WHERE lego_brick.id = $1;
|
||||
`, [brickId]);
|
||||
const colDbres = await Database.Query(`
|
||||
SELECT lego_brick_colour.id, lego_brick_colour.name, lego_brick_colour.hexrgb,
|
||||
colour_type.name AS "colour_type"
|
||||
FROM lego_brick_colour
|
||||
LEFT JOIN colour_type AS colour_type ON lego_brick_colour.col_type = colour_type.id
|
||||
`, []);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
let colDbres;
|
||||
try {
|
||||
dbres = await Database.Query(`
|
||||
SELECT lego_brick.id, lego_brick.name, tag.name AS "tag",
|
||||
inv.price, inv.new_price AS "discount", inv.stock,
|
||||
inv.last_updated AS "last_stock_update",
|
||||
weight, dimensions_x, dimensions_y, dimensions_z
|
||||
FROM lego_brick
|
||||
LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id
|
||||
LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
WHERE lego_brick.id = $1;
|
||||
`, [brickId]);
|
||||
colDbres = await Database.Query(`
|
||||
SELECT lego_brick_colour.id, lego_brick_colour.name, lego_brick_colour.hexrgb,
|
||||
colour_type.name AS "colour_type"
|
||||
FROM lego_brick_colour
|
||||
LEFT JOIN colour_type AS colour_type ON lego_brick_colour.col_type = colour_type.id
|
||||
`, []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
const axios = require("axios");
|
||||
|
||||
let StaticDictionary = [];
|
||||
|
||||
async function Init() {
|
||||
await axios.get('http://www.mieliestronk.com/corncob_lowercase.txt').then(response => {
|
||||
StaticDictionary = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
// probability of trigram/bigram
|
||||
const BigramCommonality = {
|
||||
th: 1.52,
|
||||
he: 1.28,
|
||||
in: 0.94,
|
||||
er: 0.94,
|
||||
an: 0.82,
|
||||
re: 0.68,
|
||||
nd: 0.63,
|
||||
at: 0.59,
|
||||
on: 0.57,
|
||||
nt: 0.56,
|
||||
ha: 0.56,
|
||||
es: 0.56,
|
||||
st: 0.55,
|
||||
en: 0.55,
|
||||
ed: 0.53,
|
||||
to: 0.52,
|
||||
it: 0.50,
|
||||
ou: 0.50,
|
||||
ea: 0.47,
|
||||
hi: 0.46,
|
||||
is: 0.46,
|
||||
or: 0.43,
|
||||
ti: 0.34,
|
||||
as: 0.33,
|
||||
te: 0.27,
|
||||
et: 0.19,
|
||||
ng: 0.18,
|
||||
of: 0.16,
|
||||
al: 0.09,
|
||||
de: 0.09,
|
||||
se: 0.08,
|
||||
le: 0.08,
|
||||
sa: 0.06,
|
||||
si: 0.05,
|
||||
ar: 0.04,
|
||||
ve: 0.04,
|
||||
ra: 0.04,
|
||||
ld: 0.02,
|
||||
ur: 0.02,
|
||||
};
|
||||
|
||||
const TrigramCommonality = {
|
||||
the: 1.81,
|
||||
and: 0.73,
|
||||
tha: 0.33,
|
||||
ent: 0.42,
|
||||
ing: 0.72,
|
||||
ion: 0.42,
|
||||
tio: 0.31,
|
||||
for: 0.34,
|
||||
oft: 0.22,
|
||||
sth: 0.21,
|
||||
};
|
||||
|
||||
function MostProbableAlternateQueries(query) {
|
||||
const words = query.split(' ');
|
||||
|
||||
const reconstruction = [];
|
||||
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const mostLikely = MostProbableMissSpelling(words[i]);
|
||||
reconstruction.push([...mostLikely]);
|
||||
}
|
||||
|
||||
console.log(reconstruction)
|
||||
|
||||
// work out a bit of context to determine the most likely sentence
|
||||
}
|
||||
|
||||
function MostProbableMissSpelling(word) {
|
||||
// First work out if it's intended to be a word
|
||||
|
||||
console.log(word);
|
||||
return BiGrams(word);
|
||||
}
|
||||
|
||||
function ConditionalTrigramProbability(token) {
|
||||
|
||||
}
|
||||
|
||||
function ConditionalBigramProbability(token) {
|
||||
|
||||
}
|
||||
|
||||
// returns list of tokens
|
||||
function TriGrams(word) {
|
||||
return NGrams(word, 3);
|
||||
}
|
||||
|
||||
function BiGrams(word) {
|
||||
return NGrams(word, 2);
|
||||
}
|
||||
|
||||
function NGrams(word, n) {
|
||||
const tokens = [];
|
||||
for (let i = 0; i < word.length - n + 1; i++) {
|
||||
tokens.push(word.substring(i, i + n));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Init,
|
||||
MostProbableAlternateQueries,
|
||||
MostProbableMissSpelling,
|
||||
};
|
||||
@@ -1,19 +1,29 @@
|
||||
const ControllerMaster = require('./controller-master.js');
|
||||
const Database = require('../database/database.js');
|
||||
const Logger = require('../logger.js');
|
||||
|
||||
const PgFormat = require('pg-format');
|
||||
|
||||
async function Search(fuzzyString) {
|
||||
async function Search(fuzzyStrings) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(`
|
||||
SELECT lego_set.id, lego_set.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id
|
||||
WHERE lego_set.id ~* $1 OR lego_set.name ~* $1 OR tag.name ~* $1
|
||||
`, [fuzzyString]);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(PgFormat(`
|
||||
SELECT lego_set.id, lego_set.name, tag.name AS "tag", inv.price, inv.new_price AS "discount"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id
|
||||
WHERE lego_set.id ~* ANY(ARRAY[%L]) OR lego_set.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L])
|
||||
`, fuzzyStrings, fuzzyStrings, fuzzyStrings), []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -30,8 +40,8 @@ async function Search(fuzzyString) {
|
||||
const bName = b.name.toLowerCase();
|
||||
const aTag = a.tag.toLowerCase();
|
||||
const bTag = b.tag.toLowerCase();
|
||||
const aFuzzy = fuzzyString.toLowerCase();
|
||||
const bFuzzy = fuzzyString.toLowerCase();
|
||||
const aFuzzy = fuzzyStrings[0].toLowerCase();
|
||||
const bFuzzy = fuzzyStrings[0].toLowerCase();
|
||||
|
||||
const aDist = ControllerMaster.LevenshteinDistance(aName, aFuzzy);
|
||||
const bDist = ControllerMaster.LevenshteinDistance(bName, bFuzzy);
|
||||
@@ -74,13 +84,22 @@ async function Search(fuzzyString) {
|
||||
|
||||
async function SumPrices(setsArray, quantityArray) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(PgFormat(`
|
||||
SELECT COALESCE(new_price, price) AS "price"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory AS set_inventory ON set_inventory.set_id = lego_set.id
|
||||
WHERE lego_set.id IN (%L);
|
||||
`, setsArray), []);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(PgFormat(`
|
||||
SELECT COALESCE(new_price, price) AS "price"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory AS set_inventory ON set_inventory.set_id = lego_set.id
|
||||
WHERE lego_set.id IN (%L);
|
||||
`, setsArray), []);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -101,19 +120,28 @@ async function SumPrices(setsArray, quantityArray) {
|
||||
|
||||
async function GetSet(setId) {
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const dbres = await Database.Query(`
|
||||
SELECT lego_set.id, lego_set.name, description, tag.name AS "tag",
|
||||
set_contents.brick_id, set_contents.amount, inv.price,
|
||||
date_released, weight, dimensions_x, dimensions_y, dimensions_z,
|
||||
new_price AS "discount", inv.stock, inv.last_updated AS "last_stock_update"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN set_descriptor AS set_contents ON set_contents.set_id = lego_set.id
|
||||
WHERE lego_set.id = $1;
|
||||
`, [setId]);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
let dbres;
|
||||
try {
|
||||
dbres = await Database.Query(`
|
||||
SELECT lego_set.id, lego_set.name, description, tag.name AS "tag",
|
||||
set_contents.brick_id, set_contents.amount, inv.price,
|
||||
date_released, weight, dimensions_x, dimensions_y, dimensions_z,
|
||||
new_price AS "discount", inv.stock, inv.last_updated AS "last_stock_update"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
LEFT JOIN set_descriptor AS set_contents ON set_contents.set_id = lego_set.id
|
||||
WHERE lego_set.id = $1;
|
||||
`, [setId]);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -142,22 +170,31 @@ async function GetSet(setId) {
|
||||
}
|
||||
|
||||
async function GetSets(page, resPerPage) {
|
||||
// query for the set
|
||||
await Database.Query('BEGIN TRANSACTION;');
|
||||
const countRes = await Database.Query('SELECT COUNT (*) FROM lego_set;');
|
||||
const total = parseInt(countRes.rows[0].count);
|
||||
const dbres = await Database.Query(`
|
||||
let countRes;
|
||||
let dbres;
|
||||
try {
|
||||
countRes = await Database.Query('SELECT COUNT (*) FROM lego_set;');
|
||||
dbres = await Database.Query(`
|
||||
SELECT
|
||||
lego_set.id, lego_set.name, price, new_price AS "discount", tag.name AS "tag"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory as inv ON lego_set.id = inv.set_id
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
ORDER BY id ASC
|
||||
LIMIT $1
|
||||
OFFSET $2;`,
|
||||
[resPerPage, page * resPerPage]);
|
||||
await Database.Query('END TRANSACTION;');
|
||||
lego_set.id, lego_set.name, price, new_price AS "discount", tag.name AS "tag"
|
||||
FROM lego_set
|
||||
LEFT JOIN lego_set_inventory as inv ON lego_set.id = inv.set_id
|
||||
LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id
|
||||
LEFT JOIN tag AS tag ON tags.tag = tag.id
|
||||
ORDER BY id ASC
|
||||
LIMIT $1
|
||||
OFFSET $2;`,
|
||||
[resPerPage, page * resPerPage]);
|
||||
await Database.Query('COMMIT TRANSACTION;');
|
||||
} catch {
|
||||
await Database.Query('ROLLBACK TRANSACTION;');
|
||||
Logger.Error('Database Error');
|
||||
return {
|
||||
error: 'Database error',
|
||||
};
|
||||
}
|
||||
const total = parseInt(countRes.rows[0].count);
|
||||
|
||||
// validate database response
|
||||
if (dbres.rows.length === 0) {
|
||||
@@ -174,6 +211,7 @@ async function GetSets(page, resPerPage) {
|
||||
set.tags = [];
|
||||
}
|
||||
|
||||
|
||||
// combine (joined) rows into a single array
|
||||
sets = sets.reduce((arr, current) => {
|
||||
if (!arr.some(item => item.id === current.id)) {
|
||||
|
||||
168
src/controllers/spellchecker.js
Normal file
168
src/controllers/spellchecker.js
Normal file
@@ -0,0 +1,168 @@
|
||||
const axios = require('axios');
|
||||
|
||||
let StaticDictionary = [];
|
||||
let MispellingDictionaryRAW = '';
|
||||
|
||||
async function Init() {
|
||||
// yes i know it could be unreliable to get them from external, untrusted sources
|
||||
// this algorithm is purely for fun and is very much a "work in progress"
|
||||
await axios.get('http://www.mieliestronk.com/corncob_lowercase.txt').then(response => {
|
||||
StaticDictionary = response.data;
|
||||
});
|
||||
|
||||
await axios.get('https://www.dcs.bbk.ac.uk/~roger/missp.dat').then(response => {
|
||||
MispellingDictionaryRAW = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
// probability of trigram/bigram
|
||||
const BigramCommonality = {
|
||||
th: 1.52,
|
||||
he: 1.28,
|
||||
in: 0.94,
|
||||
er: 0.94,
|
||||
an: 0.82,
|
||||
re: 0.68,
|
||||
nd: 0.63,
|
||||
at: 0.59,
|
||||
on: 0.57,
|
||||
nt: 0.56,
|
||||
ha: 0.56,
|
||||
es: 0.56,
|
||||
st: 0.55,
|
||||
en: 0.55,
|
||||
ed: 0.53,
|
||||
to: 0.52,
|
||||
it: 0.50,
|
||||
ou: 0.50,
|
||||
ea: 0.47,
|
||||
hi: 0.46,
|
||||
is: 0.46,
|
||||
or: 0.43,
|
||||
ti: 0.34,
|
||||
as: 0.33,
|
||||
te: 0.27,
|
||||
et: 0.19,
|
||||
ng: 0.18,
|
||||
of: 0.16,
|
||||
al: 0.09,
|
||||
de: 0.09,
|
||||
se: 0.08,
|
||||
le: 0.08,
|
||||
sa: 0.06,
|
||||
si: 0.05,
|
||||
ar: 0.04,
|
||||
ve: 0.04,
|
||||
ra: 0.04,
|
||||
ld: 0.02,
|
||||
ur: 0.02,
|
||||
};
|
||||
|
||||
const TrigramCommonality = {
|
||||
the: 1.81,
|
||||
and: 0.73,
|
||||
tha: 0.33,
|
||||
ent: 0.42,
|
||||
ing: 0.72,
|
||||
ion: 0.42,
|
||||
tio: 0.31,
|
||||
for: 0.34,
|
||||
oft: 0.22,
|
||||
sth: 0.21,
|
||||
};
|
||||
|
||||
function MostProbableAlternateQueries(query) {
|
||||
const words = query.split(' ');
|
||||
|
||||
const reconstruction = [];
|
||||
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const mostLikely = MostProbableMissSpelling(words[i]);
|
||||
reconstruction.push([...mostLikely]);
|
||||
}
|
||||
|
||||
// go over suggested fixes and construct the permutations of the query
|
||||
// for example if the query is 'brik 2x10X4', the reconstructions are:
|
||||
// brick, [2x10x4, 2 x 10 x 4]
|
||||
// therefore the permutations are:
|
||||
// brick 2x10x4, brick 2 x 10 x 4
|
||||
|
||||
let totalLength = 1;
|
||||
for (let i = 0; i < reconstruction.length; i++) {
|
||||
const length = reconstruction[i].length;
|
||||
totalLength *= length;
|
||||
}
|
||||
|
||||
const permutations = [];
|
||||
for (let i = 0; i < totalLength; i++) {
|
||||
const permutation = [];
|
||||
for (let j = 0; j < reconstruction.length; j++) {
|
||||
const index = i % reconstruction[j].length;
|
||||
permutation.push(reconstruction[j][index]);
|
||||
}
|
||||
permutations.push(permutation.join(' '));
|
||||
}
|
||||
|
||||
// work out a bit of context to determine the most likely sentence
|
||||
return permutations;
|
||||
}
|
||||
|
||||
function MostProbableMissSpelling(word) {
|
||||
// First work out if it's intended to be a word
|
||||
if (word.match(/[0-9]/g)) {
|
||||
// it's got a number so probably not a word
|
||||
// if it's a number, it's either a year, id or dimension
|
||||
|
||||
// if it's a dimension, we should split by x X
|
||||
if (word.match(/[xX]/g)) {
|
||||
// it's a dimension split by x X
|
||||
const split = word.split(/[xX]/g);
|
||||
return [split.join(' x '), word];
|
||||
}
|
||||
|
||||
return [word];
|
||||
}
|
||||
|
||||
// if it's one letter, it's probably not a word
|
||||
if (word.length === 1) {
|
||||
return [word];
|
||||
}
|
||||
|
||||
const trigrams = TriGrams(word);
|
||||
const bigrams = BiGrams(word);
|
||||
|
||||
return [word];
|
||||
}
|
||||
|
||||
function ConditionalTrigramProbability(token) {
|
||||
// closeness of token to the trigram commonality
|
||||
|
||||
|
||||
}
|
||||
|
||||
function ConditionalBigramProbability(token) {
|
||||
|
||||
}
|
||||
|
||||
// returns list of tokens
|
||||
function TriGrams(word) {
|
||||
return NGrams(word, 3);
|
||||
}
|
||||
|
||||
function BiGrams(word) {
|
||||
return NGrams(word, 2);
|
||||
}
|
||||
|
||||
function NGrams(word, n) {
|
||||
const tokens = [];
|
||||
for (let i = 0; i < word.length - n + 1; i++) {
|
||||
tokens.push(word.substring(i, i + n));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Init,
|
||||
MostProbableAlternateQueries,
|
||||
MostProbableMissSpelling,
|
||||
};
|
||||
11
src/index.js
11
src/index.js
@@ -5,7 +5,7 @@ const API = require('./routes/api.js');
|
||||
|
||||
const Database = require('./database/database.js');
|
||||
|
||||
const ngrams = require('./controllers/n-grams.js');
|
||||
const ngrams = require('./controllers/spellchecker.js');
|
||||
|
||||
async function main() {
|
||||
Config.Load();
|
||||
@@ -20,15 +20,16 @@ async function main() {
|
||||
Logger.Info('Pre-Init Complete');
|
||||
|
||||
await Database.Connect();
|
||||
await ngrams.Init();
|
||||
|
||||
Server.Listen(process.env.PORT);
|
||||
API.Init();
|
||||
|
||||
await ngrams.Init();
|
||||
|
||||
ngrams.MostProbableAlternateQueries('brick 2x10x4');
|
||||
ngrams.MostProbableAlternateQueries('lego star wars battlefront');
|
||||
ngrams.MostProbableAlternateQueries('lego stor was s');
|
||||
ngrams.MostProbableAlternateQueries('brick 2x10X4 2 x 2');
|
||||
// ngrams.MostProbableAlternateQueries('brick 2 x 10 x 4 2x10X4');
|
||||
// ngrams.MostProbableAlternateQueries('lego star wars battlefront');
|
||||
// ngrams.MostProbableAlternateQueries('lego stor was s');
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
@@ -30,10 +30,11 @@ async function CalculateBasketPrice(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
const setSubtotal = await SetController.SumPrices(setList, setQuantities);
|
||||
const brickSubtotal = await BrickController.SumPrices(brickList, brickQuantities);
|
||||
let setSubtotal = await SetController.SumPrices(setList, setQuantities);
|
||||
let brickSubtotal = await BrickController.SumPrices(brickList, brickQuantities);
|
||||
|
||||
console.log(setSubtotal, brickSubtotal);
|
||||
if (setSubtotal.error) setSubtotal = 0;
|
||||
if (brickSubtotal.error) brickSubtotal = 0;
|
||||
|
||||
res.send({
|
||||
data: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const ControllerMaster = require('../controllers/controller-master.js');
|
||||
const BrickController = require('../controllers/brick-controller.js');
|
||||
const SetController = require('../controllers/set-controller.js');
|
||||
const SpellController = require('../controllers/spellchecker.js');
|
||||
|
||||
async function Search(req, res) {
|
||||
const q = req.query.q;
|
||||
@@ -15,14 +16,16 @@ async function Search(req, res) {
|
||||
return;
|
||||
}
|
||||
|
||||
const alternateQueries = SpellController.MostProbableAlternateQueries(sanatisedQuery);
|
||||
|
||||
const pageRequested = req.query.page || 1;
|
||||
const perPage = req.query.per_page || 16;
|
||||
|
||||
// TODO: it is tricky to do a database offset / limit here
|
||||
// due to the fact that we have to combine the results of
|
||||
// the two queries, look into me (maybe merging the queries)
|
||||
const brickResults = await BrickController.Search(sanatisedQuery);
|
||||
const setResults = await SetController.Search(sanatisedQuery);
|
||||
const brickResults = await BrickController.Search(alternateQueries);
|
||||
const setResults = await SetController.Search(alternateQueries);
|
||||
|
||||
if (brickResults.error && setResults.error) {
|
||||
return res.send(JSON.stringify({
|
||||
@@ -32,8 +35,8 @@ async function Search(req, res) {
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
if (brickResults) count += brickResults.length;
|
||||
if (setResults) count += setResults.length;
|
||||
if (!brickResults.error) count += brickResults.length;
|
||||
if (!setResults.error) count += setResults.length;
|
||||
|
||||
if (brickResults.error) {
|
||||
// remove after the requested page
|
||||
@@ -72,8 +75,8 @@ async function Search(req, res) {
|
||||
const bName = b.name.toLowerCase();
|
||||
const aTag = a.tag.toLowerCase();
|
||||
const bTag = b.tag.toLowerCase();
|
||||
const aFuzzy = q.toLowerCase();
|
||||
const bFuzzy = q.toLowerCase();
|
||||
const aFuzzy = alternateQueries[0].toLowerCase();
|
||||
const bFuzzy = alternateQueries[0].toLowerCase();
|
||||
|
||||
const aDist = ControllerMaster.LevenshteinDistance(aName, aFuzzy);
|
||||
const bDist = ControllerMaster.LevenshteinDistance(bName, bFuzzy);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const Controller = require('../controllers/set-controller.js');
|
||||
const Database = require('../database/database.js');
|
||||
|
||||
async function Get(req, res) {
|
||||
// get id from url
|
||||
@@ -18,7 +17,7 @@ async function Get(req, res) {
|
||||
|
||||
async function Featured(req, res) {
|
||||
// query all sets and return all of them
|
||||
const { sets } = await Controller.GetSets(0, 8);
|
||||
const { sets } = await Controller.GetSets(0, 10);
|
||||
|
||||
if (sets.error) {
|
||||
res.send(JSON.stringify(sets));
|
||||
|
||||
Reference in New Issue
Block a user