Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/uiedbook/sqlitebruv
💃 A type-safe, secure SQLite query builder with D1/Turso support with built-in migrations and security features.
https://github.com/uiedbook/sqlitebruv
cloudflare-d1 d1 database sql sqlite sqlite3 sqlitebruv turso turso-db
Last synced: 6 days ago
JSON representation
💃 A type-safe, secure SQLite query builder with D1/Turso support with built-in migrations and security features.
- Host: GitHub
- URL: https://github.com/uiedbook/sqlitebruv
- Owner: Uiedbook
- Created: 2024-10-19T14:50:00.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2024-12-29T01:28:56.000Z (12 days ago)
- Last Synced: 2024-12-29T02:23:54.698Z (12 days ago)
- Topics: cloudflare-d1, d1, database, sql, sqlite, sqlite3, sqlitebruv, turso, turso-db
- Language: TypeScript
- Homepage:
- Size: 2.38 MB
- Stars: 5
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# SQLiteBruv Query Builder
A Tiny Type-Safe, Secure SQLite Query Builder with D1/Turso support with built-in migrations and security features.
[![npm version](https://badge.fury.io/js/sqlitebruv.svg)](https://www.npmjs.com/package/sqlitebruv)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm](https://img.shields.io/npm/dm/sqlitebruv.svg)](https://www.npmjs.com/package/sqlitebruv) [![TypeScript](https://img.shields.io/badge/Typescript-%3E%3D4.0-blue.svg)](https://www.typescriptlang.org/)## Features
- 🛡️ Security-first design with SQL injection prevention
- 📡 JSON interface for http no sql queries
- 🔄 Automatic schema migrations
- 🏃♂️ In-memory caching
- 🌐 Cloudflare D1 & Turso support
- 📝 Type-safe queries
- 🔍 Query validation & sanitization
- 📊 Schema management
- 🌠 Bunjs Support 100%## Installation
```bash
npm install sqlite-bruv
```## 🚀 Updates
- **Light weight**: Zero dependency and small size.
- **Bun-Ready**: built for Bunjs
- **Platform Support**:
- Cloudflare D1
- Turso
- Local SQLite
- raw query output
- **Security**: SQL injection prevention, query validation, parameter sanitization
- **Type Safety**: Full TypeScript support with inferred types
- **Migrations**: Automatic schema diff detection and migration generation
- **Caching**: Built-in memory caching with invalidation
- **Relations**: Support for one-to-one and one-to-many relationships## 📦 Installation
```bash
# bun
bun add sqlite-bruv# npm
npm install sqlite-bruv
```## Usage/Examples
```typescript
import { SqliteBruv, Schema } from "sqlite-bruv";// Define your schema
const UserSchema = new Schema<{
name: string;
email: string;
role: "admin" | "user";
createdAt: Date;
}>({
name: "users",
columns: {
name: { type: "TEXT", required: true },
email: { type: "TEXT", unique: true },
role: { type: "TEXT", default: () => "user" },
createdAt: { type: "DATETIME", default: () => new Date() },
},
});const PostSchema = new Schema({
name: "posts",
columns: {
title: { type: "TEXT", required: true },
content: { type: "TEXT" },
userId: {
type: "TEXT",
target: "users",
relationType: "ONE",
},
},
});const CommentSchema = new Schema({
name: "comments",
columns: {
content: { type: "TEXT", required: true },
postId: {
type: "TEXT",
target: "posts",
relationType: "MANY",
},
},
});// Initialize database
const db = new SqliteBruv({
schema: [UserSchema],
});
```Platform-Specific Setup
Cloudflare D1```typescript
const db = new SqliteBruv({
D1: {
accountId: process.env.CF_ACCOUNT_ID,
databaseId: process.env.D1_DATABASE_ID,
apiKey: process.env.CF_API_KEY,
},
schema: [UserSchema, PostSchema, CommentSchema],
});
```Turso;
```typescript
const db = new SqliteBruv({
turso: {
url: process.env.TURSO_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
},
schema: [UserSchema, PostSchema, CommentSchema],
});
```## Example usage:
```typescript
const queryBuilder = new SqliteBruv({
schema: [UserSchema, PostSchema, CommentSchema],
});// Insert
await queryBuilder
.from("users")
.insert({ name: "John Doe", email: "[email protected]" })
.then((changes) => {
// console.log({ changes });
});// Update
await queryBuilder
.from("users")
.where("id = ?", 1)
.update({ name: "Jane Doe" })
.then((changes) => {
// console.log({ changes });
});// Search
await queryBuilder
.from("users")
.where("id = ?", 1)
.andWhere("name LIKE ?", `%oh%`)
.get()
.then((changes) => {
// console.log({ changes });
});// Delete
await queryBuilder
.from("users")
.where("id = ?", 1)
.delete()
.then((changes) => {
console.log({ changes });
});// Get all users
queryBuilder
.from("users")
.get()
.then((changes) => {
// console.log({ changes });
});// Get one user
await queryBuilder
.from("users")
.where("id = ?", 1)
.getOne()
.then((changes) => {
// console.log({ changes });
});// Select specific columns
await queryBuilder
.from("users")
.select("id", "name")
.get()
.then((changes) => {
// console.log({ changes });
});// Where conditions
await queryBuilder
.from("users")
.where("age > ?", 18)
.get()
.then((changes) => {
// console.log({ changes });
});// AndWhere conditions
await queryBuilder
.from("users")
.where("age > ?", 18)
.andWhere("country = ?", "USA")
.get()
.then((changes) => {
// console.log({ changes });
});// OrWhere conditions
await queryBuilder
.from("users")
.where("age > ?", 18)
.orWhere("country = ?", "Canada")
.get()
.then((changes) => {
// console.log({ changes });
});// Limit and Offset
await queryBuilder
.from("users")
.limit(10)
.offset(5)
.get()
.then((changes) => {
// console.log({ changes });
});// OrderBy
await queryBuilder
.from("users")
.orderBy("name", "ASC")
.get()
.then((changes) => {
// console.log({ changes });
});await queryBuilder
.from("users")
.orderBy("name", "ASC")
.get()
.then((changes) => {
// console.log({ changes });
});
```## 💡 Advanced Usage
Complex Queries
```ts
// Relations and joins
const posts = await db
.from("posts")
.select("posts.*", "users.name as author")
.where("posts.published = ?", true)
.andWhere("posts.views > ?", 1000)
.orderBy("posts.createdAt", "DESC")
.limit(10)
.get();// Raw queries with safety
await db.raw("SELECT * FROM users WHERE id = ?", [userId]);// Cache usage
const users = await db
.from("users")
.select("*")
.where("active = ?", true)
.cacheAs("active-users")
.get();// Cache invalidation
db.invalidateCache("active-users");
```## Using from over the network via JSON interface
```typescript
// JSON interface structure
interface Query {
from: string;
select?: string[];
where?: {
condition: string;
params: any[];
}[];
andWhere?: {
condition: string;
params: any[];
}[];
orWhere?: {
condition: string;
params: any[];
}[];
orderBy?: {
column: string;
direction: "ASC" | "DESC";
};
limit?: number;
offset?: number;
cacheAs?: string;
invalidateCache?: string;
action?: "get" | "getOne" | "insert" | "update" | "delete" | "count";
/**
### For insert and update only
*/
data?: any;
}
// Example usage in an Express.js route
import express from "express";
const app = express();
app.use(express.json());app.post("/execute-query", async (req, res) => {
try {
const queryInput = req.body;
// do your role authentication here,
// use query.from to know the table being accessed
const result = await qb.executeJsonQuery(queryInput);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
```## 🔄 Migrations
Migrations are automatically generated when schema changes are detected:
```sql
-- Generated in ./Bruv-migrations/timestamp_add_user_role.sql:
-- Up
ALTER TABLE users ADD COLUMN role TEXT DEFAULT 'user';-- Down
ALTER TABLE users DROP COLUMN role;
```### Setting up your schema
This if your DB is new and your are not using any orm, just call toString
and query your db with the queryBuilder.raw() method.Note: raw is not secured, it can be used to apply migrations too.
be careful what you do with queryBuilder.raw().```ts
console.log(user.toString());
const raw = await qb.raw(user.toString());
console.log({ raw });
```## 🛡️ Security Features
The query builder implements several security measures to prevent SQL injection and malicious queries:
- Parameter validation (max 100 params)
- SQL injection prevention
- Query timeout limits
- Rate limiting
- String length validation
- Dangerous pattern detection
- Allowed parameter types: string, number, boolean, null#### Condition Validation
- Whitelisted operators: `=, >, <, >=, <=, LIKE, IN, BETWEEN, IS NULL, IS NOT NULL`
- Blocked dangerous patterns: `; DROP, DELETE, UPDATE, INSERT, ALTER, EXEC, UNION`
- Parameterized queries enforced### Security Examples
```typescript
// ✅ Safe queries
db.from("users")
.where("email LIKE ?", "%@example.com") // ✅ Safe
.andWhere("role = ?", "admin") // ✅ Safe
.get();
db.from("users")
.where("age > ?", 18)
.andWhere("status = ?", "active")
.orWhere("role IN (?)", ["admin", "mod"]);// ❌ These will throw security errors:
db.where("1=1; DROP TABLE users;"); // Dangerous pattern
db.where("col = (SELECT ...)"); // Complex subqueries blocked
db.where("name = ?", "a".repeat(1001)); // String too long
```## 🎮 Features
**Cloudflare D1**
- D1 API integration
**Turso**
- HTTP API support
**📊 Performance**
- Prepared statements
- Connection pooling
- Built-in Query caching**🚔 Security**
- Block dangerous patterns
- Block Complex subqueries
- Block very long string parameters**🤝 Contributing**
1. Fork the repository
2. Create feature branch (git checkout -b feature/amazing)
3. Commit changes (git commit -am 'Add amazing feature')
4. Push branch (git push origin feature/amazing)
5. Open a Pull Request## 📝 License
[MIT License](https://choosealicense.com/licenses/mit/) - see LICENSE file
### 🆘 Support
Contributions are always welcome! creates issues and pull requests.
Documentation
GitHub Issues
Discord Community