Lovefield - Relational Database for Web Apps
Lovefield is a relational database written entirely in JavaScript, designed for web applications. It provides a SQL-like query API, leveraging IndexedDB for persistent storage in the browser environment. Developed by Google, the package reached its last published version, 2.1.12, in February 2017. While the GitHub repository saw minor updates until January 2023, active feature development and official maintenance appear to have ceased significantly earlier, around 2015-2017, as indicated by project videos and publishing dates. Lovefield offers cross-browser compatibility (supporting older versions of Chrome, Firefox, IE, and Safari) but explicitly does not support Node.js due to its reliance on IndexedDB. Its key differentiators were bringing a relational model and SQL-like syntax to client-side data management before more modern alternatives emerged, offering atomic transactions and a query optimizer.
Common errors
-
ReferenceError: lf is not defined
cause The Lovefield JavaScript file was not loaded, or the code attempting to use 'lf' is executing before the script has parsed.fixEnsure `<script src="path/to/lovefield.min.js"></script>` is correctly placed in your HTML, preferably before any inline scripts that use `lf`. Verify the path to `lovefield.min.js` is correct and accessible. -
Error: This database is already connected, cannot connect again.
cause The `schemaBuilder.connect()` method was called more than once for the same database instance. Lovefield assumes a single connection at a time.fixEnsure `schemaBuilder.connect()` is called only once. Store the returned database instance (`db`) and reuse it for all subsequent operations. You might need a global or module-scoped variable to hold the database connection promise or instance. -
TypeError: Cannot read properties of undefined (reading 'connect')
cause The `lf.schema` object was not correctly accessed, or the global `lf` object was not available when trying to call `create()` or `connect()`.fixDouble-check that `lf` is defined and accessible. This often happens if the `lovefield.min.js` script failed to load or a module system (e.g., CommonJS `require`) was incorrectly used in a browser context. Ensure `lf.schema.create()` is called to get a schema builder before attempting `schemaBuilder.connect()`.
Warnings
- breaking Lovefield is an abandoned project. The last npm package was published in 2017 (v2.1.12), and active development by Google ceased significantly earlier. Use in new projects is strongly discouraged due to lack of security updates, bug fixes, or compatibility with modern browser APIs and JavaScript features.
- breaking Lovefield explicitly does NOT support Node.js environments. It relies on the browser's IndexedDB API, which is not available in Node.js. Attempts to use it in Node.js will result in runtime errors.
- gotcha Once the `connect()` method is called on a `schemaBuilder`, the database schema cannot be altered. Any attempts to modify the schema after connection will fail or require a database upgrade path, which needs to be explicitly handled.
- gotcha The results returned from `select` queries should be treated as read-only. Modifying these objects directly is not recommended and may lead to unexpected behavior or inconsistencies, as Lovefield does not actively clone/freeze objects from its internal cache for performance reasons.
- gotcha Lovefield's SQL-like API does not support the `HAVING` clause, which is common in standard SQL for filtering grouped results. Additionally, multi-column `ROLLUP` and `CUBE` are not supported for `GROUP BY` operations.
- gotcha Lovefield does not provide an API for programmatically deleting a database instance. This can complicate cleanup during development or for end-users who need to reset application data.
Install
-
npm install lovefield -
yarn add lovefield -
pnpm add lovefield
Imports
- lf
<!-- In HTML --> <script src="path/to/lovefield.min.js"></script> <script> const schemaBuilder = lf.schema.create('my_db', 1); // ... rest of your code using lf </script> - lf.schema.create
import { schema } from 'lovefield'; // Incorrect for browser global const schemaBuilder = schema.create('my_db', 1);const schemaBuilder = lf.schema.create('my_db', 1); - lf.Type
import { Type } from 'lovefield'; addColumn('id', Type.INTEGER);addColumn('id', lf.Type.INTEGER);
Quickstart
<!-- In an HTML file -->
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Lovefield Quick Start</title>
<script src="https://unpkg.com/lovefield@2.1.12/dist/lovefield.min.js"></script>
</head>
<body>
<script>
// Define the database schema
const schemaBuilder = lf.schema.create('todoDb', 1);
schemaBuilder.createTable('Item')
.addColumn('id', lf.Type.INTEGER)
.addColumn('description', lf.Type.STRING)
.addColumn('deadline', lf.Type.DATE_TIME)
.addColumn('done', lf.Type.BOOLEAN)
.addPrimaryKey(['id'])
.addIndex('idxDeadline', ['deadline'], false, lf.Order.DESC);
let todoDb;
let itemTable;
// Connect to the database and perform operations
schemaBuilder.connect().then(function(db) {
todoDb = db;
itemTable = db.getSchema().table('Item');
// Create a new row
const row = itemTable.createRow({
'id': 1,
'description': 'Buy groceries',
'deadline': new Date(2026, 4, 25),
'done': false
});
// Insert the row into the database
return db.insertOrReplace().into(itemTable).values([row]).exec();
}).then(function() {
// Query data
return todoDb.select().from(itemTable).where(itemTable.done.eq(false)).exec();
}).then(function(results) {
// Process results
results.forEach(function(row) {
console.log(`Task: ${row['description']}, Due: ${row['deadline'].toLocaleDateString()}`);
});
// Example: Update an item
return todoDb.update(itemTable)
.set(itemTable.done, true)
.where(itemTable.id.eq(1))
.exec();
}).then(() => {
console.log('Task ID 1 marked as done.');
}).catch(err => {
console.error('Lovefield operation failed:', err);
});
</script>
</body>
</html>