一个CRUD JavaScript类

    技术2022-07-11  141

    A couple of weeks ago, I started making a little to-do list app' in JavaScript, with history, localStorage and quite a couple of things in order to get better at JavaScript. After a couple of hours, I decided to externalize the storage in an other class to keep things clean.

    几周前,我开始用JavaScript制作一个待办事项清单应用程序 ,其中包含历史记录,localStorage和很多东西,以便更好地利用JavaScript。 几个小时后,我决定在另一堂课中将存储外部化,以保持环境整洁。

    Once I was done with this little project, I thought I could make the storage class a bit more generic to be used pretty much everywhere we need to store values as key/value pairs. Thus the article, explaining how I did it.

    一旦完成了这个小项目,我想我可以使存储类更加通用,以便在需要将值存储为键/值对的任何地方使用。 因此,这篇文章解释了我是如何做到的。

    If you're only interested in the code, have a look at the GitHub repo or this pen.

    如果您只对代码感兴趣,请查看GitHub repo或这支笔 。

    它有什么作用? (What Does it Do?)

    The main idea was to provide a simple and tiny CRUD API (<2Kb once gzipped). Basically, you instantiate a database, inserts objects (documents if you're a fan of MongoDB) and store them wherever you want. Then you can retrieve, update and delete documents. Pretty easy.

    主要思想是提供一个简单而纤巧的CRUD API(压缩后<2Kb)。 基本上,您实例化一个数据库,插入对象(如果您是MongoDB的拥护者,则插入文档)并将它们存储在所需的任何位置。 然后,您可以检索,更新和删除文档。 挺容易。

    At first I hard-coded the usage of localStorage, then with the help of Fabrice Weinberg and Valérian Galliat, I managed to externalize the driver (what does the storage) so that you can plug the CRUD class to whatever suits your needs. Thanks a lot mates!

    首先,我对localStorage的用法进行了硬编码,然后在Fabrice Weinberg和ValérianGalliat的帮助下,我设法将驱动程序外部化(存储什么),以便您可以将CRUD类插入满足您需要的任何类。 非常感谢队友!

    什么是驱动程序? (What is the Driver?)

    The driver is what actually stores your data. It is the interface that deals with persistence. To put it simple, the Database class manipulate your data while the driver stores them.

    驱动程序是实际存储数据的地方。 它是处理持久性的接口。 简而言之, Database类在驱动程序存储数据时对其进行操作。

    You can code your own driver or use the one I made which relies on DOM Storage (either localStorage or sessionStorage, depending on how your initialize it). The driver can rely on any storage system that supports key/value pairs (DOM Storage, Redis...). Also, it has to implement the 3 methods: getItem, setItem and removeItem.

    您可以编写自己的驱动程序,也可以使用我自己编写的依赖DOM Storage的驱动程序( localStorage或sessionStorage ,具体取决于初始化方式)。 驱动程序可以依赖任何支持键/值对的存储系统(DOM存储,Redis ...)。 此外,它还必须实现3种方法: getItem , setItem和removeItem 。

    “快速搜索”如何工作? (How Does the "Quick Search" Work?)

    The thing is I wanted to be able to retrieve documents not only by ID, but also by searching for a couple of criterias (basically an object with properties/values). To do this, there are not thousand of solutions: you have to loop through all the documents stored in the database, then for each one iterate over all its properties and check whether they match the ones from the object given to the find function.

    问题是我希望不仅能够通过ID来检索文档,而且还能够通过搜索几个条件(基本上是具有属性/值的对象)来检索文档。 为此,没有成千上万的解决方案:您必须遍历数据库中存储的所有文档,然后针对每个文档遍历其所有属性,并检查它们是否与提供给find函数的对象中的属性匹配。

    While this process does work, it can become painfully slow when you have hundreds of documents and are looking for a match between several properties. I needed something faster. Here comes what I call "quicksearch".

    尽管此过程确实有效,但是当您有数百个文档并且正在寻找多个属性之间的匹配时,它可能会变得非常缓慢。 我需要更快的东西。 这就是我所谓的“快速搜索”。

    The main idea is to index the properties which are most likely to be used when searching for documents. Let's say you store users, like this one:

    主要思想是为搜索文档时最可能使用的属性建立索引。 假设您像这样存储用户:

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

    When instanciating the database, you could pass the Database constructor indexedKeys: ['job', 'name'] to inform the class that on every operation, it has to index those properties in order to perform quick searches on those. Here is what happen when you insert the dev into the database:

    实例化数据库时,可以传递数据库构造函数indexedKeys: ['job', 'name']通知类,在每个操作上,它必须索引那些属性以便对它们进行快速搜索。 将开发人员插入数据库时​​,会发生以下情况:

    It adds a unique key (default is id) to the object in order to be able to identify it later

    它将唯一键(默认为id )添加到对象,以便以后能够识别它

    It tells the driver to store the object

    它告诉驱动程序存储对象

    The driver serializes and stores the object like this "{namespace}:{id}": "{serialized object}" (where {namespace} is the name of the database and {id} is the unique id assigned in step 1)

    驱动程序将序列化并存储对象,例如"{namespace}:{id}": "{serialized object}" (其中{namespace}是数据库的名称, {id}是在步骤1中分配的唯一ID)

    It loops through all properties of the object to check if some of them have to be indexed. For each of them, it stores an entry like this "{namespace}:{property}:{value}": "{array of IDs}" so:

    它遍历对象的所有属性,以检查是否必须对其中一些进行索引。 对于它们中的每一个,它都存储如下条目"{namespace}:{property}:{value}": "{array of IDs}"因此:

    "MyDatabase:name:Hugo": "[1]""MyDatabase:name:Hugo": "[1]" "MyDatabase:job:dev": "[1]""MyDatabase:job:dev": "[1]"

    Now whenever you want to look for all documents which have Hugo as a name, the find function can perform a quick search by directly looking into the "MyDatabase:name:Hugo" entry to retrieve the unique ID of all of them. Fast and efficient.

    现在,无论何时要查找以Hugo为name所有文档, find功能都可以通过直接查看"MyDatabase:name:Hugo"条目以检索所有文档的唯一ID来执行快速搜索。 快速高效。

    你如何使用它? (How Do You Use It?)

    实例化数据库 (Instantiating a database)

    As seen before, the indexedKeys property aims at speeding up the search. By setting some keys to be indexed, searching for those keys will be way faster. In any case, you can search for any key, even those which are not indexed.

    如前所示, indexedKeys属性旨在加快搜索速度。 通过设置一些要索引的键,搜索那些键将更快。 无论如何,您都可以搜索任何键,即使没有索引的键也是如此。

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

    插入新文件 (Inserting a new document)

    var obj = { name: 'Hugo', age: 22, job: 'dev' } var id = db.insert(obj)

    更新文件 (Updating a document)

    If you want to update a specific document, the easiest way is to pass its ID as the first argument. The ID is being added to the entry when inserted as the id property. You can change the name of this property by setting the uniqueKey option when instantiating the database.

    如果要更新特定文档,最简单的方法是将其ID作为第一个参数传递。 作为id属性插入时,会将ID添加到条目中。 您可以通过在实例化数据库时设置uniqueKey选项来更改此属性的名称。

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

    To update a collection of document based on a search, here is how you would do it:

    要基于搜索更新文档集合,请按以下步骤操作:

    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) }

    检索文件 (Retrieving documents)

    The find method requires an object to parse and search with.

    find方法需要一个对象来解析和搜索。

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

    检索所有文件 (Retrieving all documents)

    You can either call the findAll method which returns all existing documents in the database:

    您可以调用findAll方法,该方法返回数据库中所有现有的文档:

    db.findAll()

    Or you can call the find method with no arguments, which basically does the same thing:

    或者,您可以不带任何参数调用find方法,基本上可以完成相同的操作:

    db.find()

    删除文件 (Deleting a document)

    If you want to delete a specific document, the easiest way is to pass its ID to the function. The ID is being added to the entry when inserted as the id property. You can change the name of this property by setting the uniqueKey option when instantiating the database.

    如果要删除特定文档,最简单的方法是将其ID传递给函数。 作为id属性插入时,会将ID添加到条目中。 您可以通过在实例化数据库时设置uniqueKey选项来更改此属性的名称。

    db.delete(id)

    If you want to delete a collection of documents based on a search, you can pass an object to the function. The function will first perform a find, then delete all the returned documents.

    如果要基于搜索删除文档集合,可以将对象传递给函数。 该函数将首先执行查找,然后删除所有返回的文档。

    db.delete({ job: dev })

    您如何构建自己的驱动程序? (How Do You Build Your Own Driver?)

    The thing is you don't have to use the StorageDriver I built if you don't want to use DOM Storage. I kept it out of the core so you build use your own driver as long as it relies on a key/value storage system. To build your own, it is quite easy:

    问题是,如果您不想使用DOM Storage,则不必使用我构建的StorageDriver 。 我将其保留在核心之外,因此您可以构建自己的驱动程序,只要它依赖于键/值存储系统即可。 要构建自己的应用程序,这很容易:

    (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 );

    Then to use it, simply instantiate the Database with an instance of your driver:

    然后使用它,只需使用驱动程序实例实例化数据库:

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

    Done! You don't have to change the Database code at all. If you've made your driver correctly, everything should work like a charm. Pretty neat, isn't it? :)

    做完了! 您根本不需要更改Database代码。 如果您正确设置了驱动程序,则所有操作都应像魅力一样。 很整洁,不是吗? :)

    接下来是什么? (What Next?)

    Well folks, you tell me! I'd like to implement a couple of other tools like limit(), sort() as long as operators like OR and AND but I'm afraid it adds too much complexity to such a simple API.

    伙计们,你告诉我! 我想实现一些其他工具,例如limit() , sort() ,只要运算符像OR和AND一样AND但是恐怕这样的简单API会增加太多的复杂性。

    In any case if you come across a bug or think of a feature that could make this API better, make sure to open an issue on the GitHub repository.

    无论如何,如果遇到错误或想使该API更好的功能,请确保在GitHub存储库上打开一个问题。

    翻译自: https://davidwalsh.name/crud-javascript-class

    相关资源:crud-nodejs-源码
    Processed: 0.029, SQL: 9