Třída CRUD JavaScript

Před pár týdny jsem začal vytvářet malou aplikaci pro seznam úkolů v JavaScriptu s historií, localStorage a několika dalšími věcmi, abych se v JavaScriptu zlepšil. Po několika hodinách jsem se rozhodl umístit úložiště do jiné třídy, aby bylo vše čisté.

Jakmile jsem s tímto malým projektem skončil, napadlo mě, že bych mohl třídu úložiště udělat trochu obecnější, aby se dala používat téměř všude, kde potřebujeme ukládat hodnoty jako páry klíč/hodnota. Takže článek, vysvětlující, jak jsem to udělal.

Pokud vás zajímá pouze kód, podívejte se na úložiště GitHub nebo toto pero.

Co to dělá?

Hlavní myšlenkou bylo poskytnout jednoduché a malé CRUD API (<2 kB, jakmile je gzipováno). V podstatě vytvoříte instanci databáze, vložíte objekty (dokumenty, pokud jste fanouškem MongoDB) a uložíte je, kam chcete. Poté můžete dokumenty získávat, aktualizovat a mazat. Docela snadné.

Nejprve jsem natvrdo zakódoval použití localStorage, pak se mi s pomocí Fabrice Weinberga a Valériana Galliata podařilo externalizovat ovladač (co dělá úložiště), abyste mohli třídu CRUD připojit k tomu, co vyhovuje vašim potřebám. Díky moc přátelé!

Co je ovladač?

Ovladač je to, co ve skutečnosti ukládá vaše data. Je to rozhraní, které se zabývá persistencí. Jednoduše řečeno, Database class manipulovat s vašimi daty, zatímco je ovladač ukládá.

Můžete nakódovat svůj vlastní ovladač nebo použít ten, který jsem vytvořil a který využívá úložiště DOM (buď localStorage nebo sessionStorage , v závislosti na tom, jak jej inicializujete). Ovladač se může spolehnout na jakýkoli úložný systém, který podporuje páry klíč/hodnota (DOM Storage, Redis...). Také musí implementovat 3 metody:getItem , setItem a removeItem .

Jak funguje „Rychlé vyhledávání“?

Jde o to, že jsem chtěl mít možnost získávat dokumenty nejen podle ID, ale také hledáním několika kritérií (v podstatě objekt s vlastnostmi/hodnotami). K tomu není tisíc řešení:musíte projít všechny dokumenty uložené v databázi, pak pro každý z nich iterovat všechny jeho vlastnosti a zkontrolovat, zda se shodují s těmi z objektu daného find funkce.

I když tento proces funguje, může být bolestně pomalý, když máte stovky dokumentů a hledáte shodu mezi několika vlastnostmi. Potřeboval jsem něco rychlejšího. Zde přichází to, čemu říkám „rychlé vyhledávání“.

Hlavní myšlenkou je indexovat vlastnosti, které se s největší pravděpodobností použijí při vyhledávání dokumentů. Řekněme, že ukládáte uživatele, jako je tento:

var dev = {
  name: 'Hugo',
  age: 22,
  job: 'dev'
}

Při vytváření instance databáze můžete předat konstruktor databáze indexedKeys: ['job', 'name'] informovat třídu, že při každé operaci musí tyto vlastnosti indexovat, aby v nich mohla provádět rychlé vyhledávání. Zde je to, co se stane, když vložíte vývojář do databáze:

  1. Přidá jedinečný klíč (výchozí je id ) k objektu, aby jej bylo možné později identifikovat
  2. Říká ovladači, aby uložil objekt
  3. Ovladač serializuje a ukládá objekt takto "{namespace}:{id}": "{serialized object}" (kde {namespace} je název databáze a {id} je jedinečné ID přiřazené v kroku 1)
  4. Prochází všechny vlastnosti objektu, aby zkontroloval, zda některé z nich musí být indexovány. Pro každý z nich ukládá záznam, jako je tento "{namespace}:{property}:{value}": "{array of IDs}" takže:
    • "MyDatabase:name:Hugo": "[1]"
    • "MyDatabase:job:dev": "[1]"

Nyní, kdykoli budete chtít vyhledat všechny dokumenty, které mají Hugo jako name , find Funkce může provádět rychlé vyhledávání přímým pohledem do "MyDatabase:name:Hugo" záznam pro získání jedinečného ID všech z nich. Rychlé a efektivní.

Jak jej používáte?

Vytvoření instance databáze

Jak bylo vidět dříve, indexedKeys cílem je urychlit vyhledávání. Nastavením některých klíčů k indexování bude hledání těchto klíčů mnohem rychlejší. V každém případě můžete vyhledat jakýkoli klíč, dokonce i ty, které nejsou indexovány.

var db = new Database({
  name: 'MyDatabase',
  indexedKeys: ['job', 'age']
})

Vložení nového dokumentu

var obj = {
  name: 'Hugo',
  age: 22,
  job: 'dev'
}

var id = db.insert(obj)

Aktualizace dokumentu

Pokud chcete aktualizovat konkrétní dokument, nejjednodušším způsobem je předat jeho ID jako první argument. ID je přidáno k záznamu, když je vloženo jako id vlastnictví. Název této vlastnosti můžete změnit nastavením uniqueKey možnost při vytváření instance databáze.

obj['mood'] = 'happy'
db.update(id, obj)

Chcete-li aktualizovat kolekci dokumentů na základě vyhledávání, postupujte takto:

var dev, devs = this.find({ job: 'dev' })

for(var i = 0, len = devs.length; i < len; i++) {
  dev = devs[i]
  dev['mood'] = 'happy'
  dev.job = 'clown'
  db.update(dev.id, dev)
}

Načítání dokumentů

find metoda vyžaduje objekt k analýze a vyhledávání.

db.find({ mood: 'happy' })
db.find({ job: 'dev', age: 22 })

Načítání všech dokumentů

Můžete buď zavolat findAll metoda, která vrátí všechny existující dokumenty v databázi:

db.findAll()

Nebo můžete zavolat find metoda bez argumentů, která v podstatě dělá to samé:

db.find()

Odstranění dokumentu

Pokud chcete smazat konkrétní dokument, nejjednodušší je předat funkci jeho ID. ID je přidáno k záznamu, když je vloženo jako id vlastnictví. Název této vlastnosti můžete změnit nastavením uniqueKey možnost při vytváření instance databáze.

db.delete(id)

Pokud chcete odstranit kolekci dokumentů na základě vyhledávání, můžete funkci předat objekt. Funkce nejprve provede vyhledání a poté smaže všechny vrácené dokumenty.

db.delete({ job: dev })

Jak si vytvoříte svůj vlastní ovladač?

Jde o to, že nemusíte používat StorageDriver, který jsem vytvořil, pokud nechcete používat DOM Storage. Nechal jsem to mimo jádro, takže můžete použít svůj vlastní ovladač, pokud se spoléhá na systém úložiště klíč/hodnota. Postavit si vlastní je docela snadné:

(function ( exports ) {
  'use strict';

var NameOfYourDriver = function ( conf ) {
    this.conf = exports.extend({
      name: 'NameOfYourDriver'
      // whatever you need
    }, conf || {});
  };

  NameOfYourDriver.prototype.setItem = function ( key, value ) {
    // Set an item
    // If key doesn't exist, create it
    // If key exists, replace with new value
  };

  NameOfYourDriver.prototype.getItem = function ( key ) {
    // Return the item matching key 
    // If key doesn't exist, return null
  };

  NameOfYourDriver.prototype.removeItem = function ( key ) {
    // Remove the item at key if it exists
  };

if (exports.Database) {
    exports.Database.drivers.NameOfYourDriver = NameOfYourDriver;
  }
}) ( window );

Abyste jej mohli použít, jednoduše vytvořte instanci databáze s instancí vašeho ovladače:

var db = new Database({
  name: 'MyDatabase',
  driver: new Database.driver.NameOfYourDriver({
    name: 'MyDatabase'
    // whatever is needed
  })
})

Hotovo! Nemusíte měnit Database kód vůbec. Pokud jste ovladač vytvořili správně, vše by mělo fungovat jako kouzlo. Docela pěkné, ne? :)

Co dál?

No lidi, vy mi to řekněte! Chtěl bych implementovat několik dalších nástrojů, jako je limit() , sort() pokud operátory jako OR a AND ale obávám se, že to příliš komplikuje tak jednoduché API.

V každém případě, pokud narazíte na chybu nebo si vzpomenete na funkci, která by toto API mohla vylepšit, nezapomeňte otevřít problém v úložišti GitHub.