lukujarjestaja/tietokanta.js

144 lines
2.8 KiB
JavaScript

'use strict';
const taulut = {
luokat: 'luokat',
};
class Transaktio {
peruttu = false;
muutokset = [];
constructor(tietokanta) {
this.tietokanta = tietokanta;
this.seuraavaId = tietokanta.seuraavaId;
this.taulut = new Map;
for (const taulu of tietokanta.taulut.keys()) {
this.taulut.set(taulu, new Map);
}
}
peru() {
this.peruttu = true;
}
hae(taulu, id) {
if (!this.taulut.has(taulu)) {
throw new Error(`ei taulua ${taulu}`);
}
if (this.taulut.get(taulu).has(id)) {
return this.taulut.get(taulu).get(id);
} else {
return this.tietokanta.taulut.get(taulu).get(id);
}
}
lisää(taulu, sisältö) {
if (this.peruttu) {
throw new Error(`yritys lisätä rivi perutussa transaktiossa`);
}
if (!this.taulut.has(taulu)) {
throw new Error(`ei taulua ${taulu}`);
}
const id = this.seuraavaId++;
this.muutokset.push({
taulu,
id,
uusi: sisältö,
});
this.taulut.get(taulu).set(id, sisältö);
return id;
}
poista(taulu, id) {
if (this.peruttu) {
throw new Error(`yritys poistaa rivi perutussa transaktiossa`);
}
const vanha = this.hae(taulu, id);
if (vanha === undefined) {
throw new Error(`ei riviä ${id} taulussa ${taulu}`);
}
this.muutokset.push({
taulu,
id,
vanha,
});
this.taulut.get(taulu).set(id, undefined);
}
}
class Tietokanta {
seuraavaId = 0;
taulut = new Map;
historia = [];
constructor() {
this.taulut.set(taulut.luokat, new Map);
}
transaktio(funktio) {
const transaktio = new Transaktio(this);
funktio(transaktio);
return this.suorita(transaktio);
}
suorita(transaktio) {
if (transaktio.peruttu) {
return [];
}
// Varmista, että invariantit ovat yhä totta
for (const {taulu, id, vanha, uusi} of transaktio.muutokset) {
}
// Suorita muutokset
for (const {taulu, id, uusi} of transaktio.muutokset) {
if (uusi !== undefined) {
this.taulut.get(taulu).set(id, uusi);
} else {
this.taulut.get(taulu).delete(id);
}
}
this.historia.push({
muutokset: transaktio.muutokset,
idMuutos: transaktio.seuraavaId - this.seuraavaId,
});
this.seuraavaId = transaktio.seuraavaId;
return transaktio.muutokset;
}
kumoa() {
if (this.historia.length === 0) {
return [];
}
const {muutokset, idMuutos} = this.historia.pop();
this.seuraavaId -= idMuutos;
const kumotut = [];
for (const {taulu, id, vanha, uusi} of muutokset) {
if (vanha !== undefined) {
this.taulut.get(taulu).set(id, vanha);
} else {
this.taulut.get(taulu).delete(id);
}
kumotut.push({
taulu,
id,
vanha: uusi,
uusi: vanha,
});
}
return kumotut;
}
hae(taulu, id) {
if (!this.taulut.has(taulu)) {
throw new Error(`ei taulua ${taulu}`);
}
return this.taulut.get(taulu).get(id);
}
}
const tietokanta = new Tietokanta;