mlpcardgame/src/mlpccg/database.ts

176 lines
4.5 KiB
TypeScript

import Dexie from "dexie";
import { Card, CardFilter, StoredImage } from "./types";
import { cardFullName } from "./card";
class CardDatabase extends Dexie {
public cards: Dexie.Table<Card, string>;
public images: Dexie.Table<StoredImage, string>;
public constructor() {
super("CardDatabase");
this.version(1).stores({
cards: "ID,Set,Type,Cost,Power",
images: "id"
});
this.cards = this.table("cards");
this.images = this.table("images");
}
}
export let Database: CardDatabase | null = null;
export async function initDB(): Promise<void> {
return new Promise(resolve => {
if (Database == null) {
Database = new CardDatabase();
Database.on("ready", async () => {
resolve();
});
Database.open();
} else {
resolve();
}
});
}
export async function getCards(filter: CardFilter) {
if (Database == null) {
throw new Error("Database was not initialized, init with 'initDB()'");
}
let table = Database.cards;
// Get best IDB index
let query: Dexie.Collection<Card, string>;
if (filter.Powers && filter.Powers.length > 0) {
query = table.where("Power").anyOf(filter.Powers);
} else if (filter.Costs && filter.Costs.length > 0) {
query = table.where("Cost").anyOf(filter.Costs);
} else if (filter.Sets && filter.Sets.length > 0) {
query = table.where("Set").anyOf(filter.Sets);
} else if (filter.Types && filter.Types.length > 0) {
query = table.where("Type").anyOf(filter.Types);
} else {
if (
filter.Name ||
filter.Rules ||
filter.Traits ||
filter.Rarities ||
filter.Elements
) {
query = table.toCollection();
} else {
// Nothing to query, return everything
return await table.toArray();
}
}
const results = query.filter(x => {
if (filter.Name) {
if (
!cardFullName(x)
.toLowerCase()
.includes(filter.Name.toLowerCase())
) {
return false;
}
}
if (filter.Rules) {
if (
!`${x.Keywords.join(" ~ ")} ~ ${x.Text}`
.toLowerCase()
.includes(filter.Rules.toLowerCase())
) {
return false;
}
}
if (filter.Traits && filter.Traits.length > 0) {
let found = false;
for (const trait of x.Traits) {
if (filter.Traits.includes(trait)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
if (filter.Sets && filter.Sets.length > 0) {
if (!filter.Sets.includes(x.Set)) {
return false;
}
}
if (filter.Types && filter.Types.length > 0) {
if (!filter.Types.includes(x.Type)) {
return false;
}
}
if (filter.Elements && filter.Elements.length > 0) {
let found = false;
for (const element of x.Element) {
if (filter.Elements.includes(element)) {
found = true;
break;
}
}
if (x.Requirement) {
for (const element in x.Requirement) {
if (filter.Elements.includes(element)) {
found = true;
break;
}
}
}
if (x.ProblemRequirement) {
for (const element in x.ProblemRequirement) {
if (filter.Elements.includes(element)) {
found = true;
break;
}
}
}
// For "None" element searches, "nothing" is actually ok
if (
filter.Elements.includes("None") &&
x.Element.length == 0 &&
(!x.Requirement || x.Requirement.length == 0) &&
(!x.ProblemRequirement || x.ProblemRequirement.length == 0)
) {
found = true;
}
if (!found) {
return false;
}
}
if (filter.Powers && filter.Powers.length > 0) {
if (typeof x.Power === "undefined" || !filter.Powers.includes(x.Power)) {
return false;
}
}
if (filter.Costs && filter.Costs.length > 0) {
if (typeof x.Cost === "undefined" || !filter.Costs.includes(x.Cost)) {
return false;
}
}
if (filter.Rarities && filter.Rarities.length > 0) {
if (!filter.Rarities.includes(x.Rarity)) {
return false;
}
}
return true;
});
return await results.toArray();
}
export async function cardFromIDs(cardIDs: string[]): Promise<Card[]> {
if (Database == null) {
throw new Error("Database was not initialized, init with 'initDB()'");
}
let table = Database.cards;
//TODO Replace with .bulkGet when upgrading to Dexie 3.x
return await table
.where("ID")
.anyOf(cardIDs)
.toArray();
}