LacertaDB - Secure, compressed, client-side storage made simple. (Works better above 0.5.0)
LacertaDB is a browser-based, high-performance database built on IndexedDB
with a focus on flexibility, encryption, compression, and automatic metadata synchronization using the faster LocalStorage
. It is designed to simplify client-side storage for web applications, offering robust features like built-in data security and performance optimizations.
- Observer: Observe or listen to collection's operation with handlers.
- Quick Store Functionality: When you open a progressive web application, you don't want to rely on indexedDB to load settings such as theme and locales, because it is slow. Instead you access those kind of data from localstorage which has no initialization needed.
- Automatic Metadata Tracking: Metadata, including database size, number of documents, and modification times, are updated automatically, keeping your data organized.
- Compression & Encryption: Compress data using the browser and encrypt it with it too for secure and efficient storage.
- Flexible Document Handling: Supports adding, updating, retrieving, and deleting documents seamlessly.
- Built-in Collection Management: Automatically manage and query collections, with automatic synchronization of metadata.
- Dynamic Metadata Access: Get metadata like total database size, collection length, or last modification time using simple getters like
db.totalSizeKB
andcollection.length
. - Advanced Data Support: Store complex data types like
TypedArray
,BigInt
,Map
,Set
,Date
,Error
and more. Thanks to the JOYSON serialization module, LacertaDB supports data that JSON doesn't natively handle.
Install LacertaDB using npm:
npm install lacertadb
Welcome to the comprehensive documentation for our Database System! This guide will help you understand how to create a database, use the quick store, initialize the system, access observers, manage documents, and more.
- Introduction
- Getting Started
- Quick Store
- Observer Pattern
- Document Structure
- Document Management
- Collection Management
- Document Class Static Methods
- Conclusion
✨ Welcome to the LacertaDB System! LacertaDB provides a robust and efficient way to manage your data with features like encryption, compression, and attachment handling. It supports asynchronous initialization, observers for event handling, and offers both quick storage and full database capabilities.
To create a new database, instantiate the Database
class:
const dbName = 'myDatabase';
const db = new Database(dbName);
Before using the database, initialize it asynchronously:
await db.init();
When you're done with the database, ensure you close it to release resources:
await db.close();
⚡ Quick Store is a special store that can be accessed before asynchronous initialization. It allows you to store and retrieve documents quickly without waiting for the full database to initialize.
Access the quick store through the quickStore
property of the Database
instance:
const quickStore = db.quickStore;
const documentData = { data: { /* your data */ } };
await quickStore.setDocument(documentData);
const docId = 'yourDocumentId';
const document = await quickStore.getDocument(docId);
👀 Each Collection
instance has an observer
that you can use to listen for events:
const collection = await db.getCollection('myCollection');
const observer = collection.observer;
Subscribe to various events such as beforeAdd
, afterAdd
, beforeDelete
, afterDelete
, beforeGet
, and afterGet
:
observer.on('beforeAdd', (documentData) => {
console.log('About to add:', documentData);
});
observer.on('afterAdd', (documentData) => {
console.log('Added:', documentData);
});
A Document
in the database system has several fields:
_id
: (String) Unique identifier for the document. If not provided, it is auto-generated._created
: (Number) Timestamp of when the document was created._modified
: (Number) Timestamp of when the document was last modified._permanent
: (Boolean) Indicates if the document is permanent and should not be deleted during free space operations._encrypted
: (Boolean) Set totrue
to encrypt the document data._compressed
: (Boolean) Set totrue
to compress the document data.data
: (Object) The actual data content of the document.attachments
: (Array) An array of attachment file paths associated with the document.
const documentData = {
_id: 'uniqueDocId',
_permanent: false,
_encrypted: true,
_compressed: true,
data: {
name: 'Sample Document',
content: 'This is a sample.'
},
attachments: [/* array of file paths or Blob objects */]
};
📎 Attachments can be added to documents. They are stored separately in the file system and linked via file paths in the attachments
field.
When adding attachments, include them in the attachments
array:
const documentData = {
data: { /* your data */ },
attachments: [fileBlob1, fileBlob2]
};
await collection.addDocument(documentData);
To retrieve attachments along with the document:
const document = await collection.getDocument(docId, encryptionKey, true);
const attachments = document.attachments; // Contains Blob objects
To add a document to a collection:
const documentData = {
_encrypted: true, // Set to true to encrypt
_compressed: true, // Set to true to compress
data: { /* your data */ },
attachments: [/* optional attachments */]
};
await collection.addDocument(documentData, 'yourEncryptionKey');
To modify a document, add a document with the same _id
. It will update the existing document:
const updatedDocumentData = {
_id: 'existingDocId',
data: { /* updated data */ },
_modified: Date.now()
};
await collection.addDocument(updatedDocumentData);
To delete a document:
const docId = 'documentId';
const forceDelete = false; // Set to true to delete permanent documents
await collection.deleteDocument(docId, forceDelete);
const docIds = ['docId1', 'docId2'];
await collection.deleteDocuments(docIds);
To create a new collection:
const collectionName = 'myNewCollection';
const collection = await db.createCollection(collectionName);
To delete an existing collection:
const collectionName = 'collectionToDelete';
await db.deleteCollection(collectionName);
You can access metadata about a collection, such as its size, document count, and modification time:
const collection = await db.getCollection('myCollection');
const metadata = collection.metadataData;
console.log('Collection Size (KB):', metadata.sizeKB);
console.log('Number of Documents:', metadata.length);
console.log('Last Modified At:', new Date(metadata.modifiedAt));
To get metadata about individual documents:
const documentsMetadata = collection.documentsMetadata;
documentsMetadata.forEach((docMeta) => {
console.log('Document ID:', docMeta.id);
console.log('Size (KB):', docMeta.size);
console.log('Modified At:', new Date(docMeta.modified));
console.log('Is Permanent:', docMeta.permanent);
console.log('Attachment Count:', docMeta.attachment);
});
🔐 To verify if a document is still encrypted, use the isEncrypted
static method of the Document
class:
const isEncrypted = Document.isEncrypted(documentData);
📎 To check if a document has attachments that haven't been retrieved yet, use the hasAttachments
method:
const hasAttachments = Document.hasAttachments(documentData);
🎉 You are now ready to use the Database System! Remember to handle encryption keys securely and manage your documents efficiently. Utilize the observer pattern to react to database events, and leverage the quick store for immediate storage needs.
Note: All special characters in this documentation are properly escaped using \\
to ensure correct markdown parsing.
-
Encryption and Compression: Setting
_encrypted
totrue
encrypts the document data using the provided encryption key. Similarly, setting_compressed
totrue
compresses the document data. -
Attachments: Attachments are handled using the File System Access API. Ensure you have appropriate permissions to read and write files.
-
Deleting the Database: To delete the entire database:
await db.deleteDatabase();
-
Observer Events: Supported events include:
beforeAdd
afterAdd
beforeDelete
afterDelete
beforeGet
afterGet
-
Querying Documents:
const filter = { 'data.name': 'Sample Document' }; const results = await collection.query(filter, 'yourEncryptionKey');
-
Handling Permanent Documents: Documents marked as
_permanent: true
will not be deleted during free space operations unlessforce
is set totrue
when deleting.
Happy Coding!
Below is a quick example demonstrating LacertaDB’s features:
import { Database, Document } from "lacertadb";
(async function runExample() {
// Initialize the database
const db = new Database("interview");
// Database instance has a quick store
// You can use it before initiating the db
const quickDoc = {
_id: "settings",
data: { theme: "light", locales: "fr-CH" },
_compressed: false,
_permanent: true,
};
await db.quickStore.setDocument(quickDoc);
const docBack = await db.quickStore.getDocument("settings");
// You can list the documents inside your quickstore
// 5MB is the limit for localStorage IN TOTAL
const docIds = db.quickStore.getAllKeys();
console.log("QuickStore Document:", docBack);
console.log("QuickStore Document IDs:", docIds);
await db.init();
// Create or get a collection
const collection = await db.createCollection("humanoids");
// Create two blobs to add as attachments
const blob1 = new Blob(["Hello, this is the first blob"], { type: "text/plain" });
const blob2 = new Blob(["Hello, this is the second blob"], { type: "text/plain" });
// Add a new document with attachments (returns true if new, false if updated)
const documentWithAttachments = {
_id: "doc_with_attachments",
data: { message: "Document with attachments" },
_attachments: [
{ id: "attachment1", data: blob1 },
{ id: "attachment2", data: blob2 },
],
_compressed: false,
_permanent: false,
};
const isNewDocument = await collection.addDocument(documentWithAttachments);
console.log("Document with attachments added (new):", isNewDocument);
// Retrieve the document by its ID, with attachments
const retrieved = await collection.getDocument("doc_with_attachments", null, true);
console.log("Retrieved Document with Attachments:", retrieved);
// Add another simple document
await collection.addDocument({ data: "hello" });
// Retrieve the document by its ID
const retrievedSimple = await collection.getDocument(quickDoc._id, "password");
console.log("Retrieved Simple Document:", retrievedSimple);
// Add multiple documents
const docs = [];
for (let i = 0; i < 500; i++) {
const newDoc = {
_id: i.toString(16),
data: { index: i },
_compressed: true,
_permanent: false,
};
await collection.addDocument(newDoc);
docs.push(newDoc);
}
// Retrieve multiple documents by their IDs
const retrievedBatch = await collection.getDocuments(["a", "b", "9", "11", "c"]);
console.log("Retrieved Documents:", retrievedBatch);
// Query documents based on a field
const results = await collection.query({ index: 10 });
console.log("Query Results:", results);
// Access metadata through getters
console.log("Total DB Size (KB):", db.totalSizeKB);
console.log("All IDs in collection:", collection.keys);
console.log("Collection Document Count:", collection.totalLength);
// Delete a document (returns true if deleted, false otherwise)
const isDeleted = await collection.deleteDocument(quickDoc._id);
console.log("Document deleted:", isDeleted);
// Close the database when done
await db.close();
})();
We welcome contributions to LacertaDB! Whether it’s a bug report, feature suggestion, or pull request, your input helps improve the library. Open an issue or submit a pull request on the GitHub repository.
For any issues, questions, or suggestions, please visit our GitHub Issues page and let us know how we can improve LacertaDB.
LacertaDB is designed to make client-side storage secure, efficient, and easy to use. With dynamic metadata management, flexible document handling, and built-in support for encryption and compression, it’s the ideal solution for modern web applications.
This project is licensed under the MIT License.