# jdb-lite

A lightweight, zero-dependency JSON database for Node.js with a familiar API. Perfect for small projects, prototyping, or when you need a simple file-based database without the complexity of traditional databases.

## ✨ Features

- 🔄 **Familiar API** - Mongoose-like interface that feels natural
- 📁 **JSON File Storage** - Data stored in simple JSON files
- 🔧 **Schema Validation** - Define and validate your data structure
- 📦 **Multi-format Support** - Works with CommonJS, ES Modules, TypeScript, and JavaScript
- 🔍 **Full CRUD Operations** - Create, Read, Update, Delete with filtering and sorting
- 🎯 **TypeScript Support** - Full type safety and IntelliSense
- ⚡ **Zero Dependencies** - Lightweight with no external dependencies
- 🚀 **Easy Setup** - Get started in minutes

## 📦 Installation

```bash
npm install jdb-lite
```

## 🚀 Quick Start

### JavaScript (CommonJS)
```javascript
const JsonDB = require('jdb-lite');
const { Schema } = require('jdb-lite');

// Define a schema
const userSchema = new Schema({
  name: { type: 'String', required: true },
  email: { type: 'String', required: true },
  age: { type: 'Number', required: true },
  isActive: { type: 'Boolean', default: true }
});

// Connect and create model
async function main() {
  await JsonDB.connect('./my-database');
  const User = JsonDB.model('User', userSchema);

  // Create a user
  const user = new User({
    name: 'John Doe',
    email: 'john@example.com',
    age: 30
  });

  await user.save();
  console.log('User saved!', user);
}

main();
```

### JavaScript (ES Modules)
```javascript
import JsonDB, { Schema } from 'jdb-lite';

const userSchema = new Schema({
  name: { type: 'String', required: true },
  email: { type: 'String', required: true },
  age: { type: 'Number', required: true }
});

await JsonDB.connect('./my-database');
const User = JsonDB.model('User', userSchema);

const user = await User.create({
  name: 'Jane Doe',
  email: 'jane@example.com',
  age: 25
});

console.log('User created!', user);
```

### TypeScript
```typescript
import JsonDB, { Schema, Document } from 'jdb-lite';

// Define interface
interface IUser extends Document {
  name: string;
  email: string;
  age: number;
  isActive?: boolean;
}

// Create schema with type safety
const userSchema = new Schema<IUser>({
  name: { type: 'String', required: true },
  email: { type: 'String', required: true },
  age: { type: 'Number', required: true },
  isActive: { type: 'Boolean', default: true }
});

await JsonDB.connect('./my-database');
const User = JsonDB.model<IUser>('User', userSchema);

// Type-safe operations
const user: IUser = await User.create({
  name: 'Alice Smith',
  email: 'alice@example.com',
  age: 28
});
```

## 📖 Complete Usage Guide

### 1. Connection

```javascript
// Connect to database (creates folder if doesn't exist)
await JsonDB.connect('./my-database');

// Or specify a different path
await JsonDB.connect('/path/to/database');

// Disconnect when done
await JsonDB.disconnect();
```

### 2. Schema Definition

```javascript
const userSchema = new Schema({
  // String field
  name: { 
    type: 'String', 
    required: true,
    default: 'Anonymous'
  },
  
  // Number field
  age: { 
    type: 'Number', 
    required: true,
    validate: (value) => value >= 0 // Custom validation
  },
  
  // Boolean field
  isActive: { 
    type: 'Boolean', 
    default: true 
  },
  
  // Date field
  createdAt: { 
    type: 'Date', 
    default: Date.now 
  },
  
  // Array field
  tags: { 
    type: 'Array', 
    default: [] 
  },
  
  // Object field
  settings: { 
    type: 'Object', 
    default: {} 
  }
}, {
  timestamps: true, // Adds createdAt and updatedAt automatically
  collection: 'users' // Custom collection name (optional)
});
```

### 3. Creating Documents

```javascript
// Method 1: Constructor + save
const user = new User({
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
});
await user.save();

// Method 2: Direct creation
const user = await User.create({
  name: 'Jane Doe',
  email: 'jane@example.com',
  age: 25
});

// Method 3: Create multiple
const users = await User.insertMany([
  { name: 'User 1', email: 'user1@example.com', age: 20 },
  { name: 'User 2', email: 'user2@example.com', age: 30 }
]);
```

### 4. Reading Documents

```javascript
// Find all documents
const allUsers = await User.find();

// Find with conditions
const adults = await User.find({ age: { $gte: 18 } });
const activeUsers = await User.find({ isActive: true });

// Find one document
const user = await User.findOne({ email: 'john@example.com' });

// Find by ID
const user = await User.findById('507f1f77bcf86cd799439011');

// Advanced querying
const users = await User.find({ age: { $gte: 25 } })
  .sort({ age: -1 })        // Sort by age descending
  .limit(10)                // Limit to 10 results
  .skip(5);                 // Skip first 5 results

// Count documents
const count = await User.countDocuments({ isActive: true });
```

### 5. Updating Documents

```javascript
// Update one document
await User.updateOne(
  { email: 'john@example.com' }, // Filter
  { age: 31 }                    // Update
);

// Update multiple documents
await User.updateMany(
  { isActive: false },  // Filter
  { isActive: true }    // Update
);

// Find and update (returns updated document)
const updatedUser = await User.findOneAndUpdate(
  { email: 'john@example.com' },
  { age: 32 },
  { new: true } // Return updated document
);

// Find by ID and update
const user = await User.findByIdAndUpdate(
  '507f1f77bcf86cd799439011',
  { name: 'John Smith' },
  { new: true }
);
```

### 6. Deleting Documents

```javascript
// Delete one document
await User.deleteOne({ email: 'john@example.com' });

// Delete multiple documents
await User.deleteMany({ isActive: false });

// Find and delete (returns deleted document)
const deletedUser = await User.findOneAndDelete({ email: 'john@example.com' });

// Find by ID and delete
const user = await User.findByIdAndDelete('507f1f77bcf86cd799439011');
```

### 7. Instance Methods

```javascript
const user = await User.findOne({ email: 'john@example.com' });

// Check if document is new (not saved yet)
console.log(user.isNew); // false

// Check if field was modified
user.age = 32;
console.log(user.isModified('age')); // true

// Convert to plain object
const plainObject = user.toObject();

// Convert to JSON
const jsonString = JSON.stringify(user.toJSON());

// Validate document
await user.validate();

// Save changes
await user.save();

// Remove document
await user.remove();
```

## 🏗️ Data Storage

Your data is stored in JSON files within the specified database folder:

```
my-database/
├── users.json      # User collection
├── posts.json      # Post collection
└── comments.json   # Comment collection
```

Each collection is a JSON array of documents:

```json
[
  {
    "_id": "507f1f77bcf86cd799439011",
    "name": "John Doe",
    "email": "john@example.com",
    "age": 30,
    "isActive": true,
    "createdAt": "2023-01-01T00:00:00.000Z",
    "updatedAt": "2023-01-01T00:00:00.000Z"
  }
]
```

## 🔧 Advanced Features

### Custom Methods and Statics

```javascript
// Add instance methods
userSchema.methods.getDisplayName = function() {
  return this.name.toUpperCase();
};

// Add static methods
userSchema.statics.findByEmail = function(email) {
  return this.findOne({ email });
};

// Usage
const user = await User.findOne({ name: 'John' });
console.log(user.getDisplayName()); // "JOHN"

const user = await User.findByEmail('john@example.com');
```

### Schema Validation

```javascript
const userSchema = new Schema({
  email: {
    type: 'String',
    required: true,
    validate: (email) => {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailRegex.test(email)) {
        throw new Error('Invalid email format');
      }
      return true;
    }
  },
  age: {
    type: 'Number',
    required: true,
    validate: (age) => {
      if (age < 0 || age > 150) {
        throw new Error('Age must be between 0 and 150');
      }
      return true;
    }
  }
});
```

## 📱 Module System Examples

### Node.js (CommonJS)
```javascript
// index.js
const JsonDB = require('jdb-lite');

async function main() {
  await JsonDB.connect('./database');
  // Your code here
}
```

### Node.js (ES Modules)
```javascript
// index.mjs or with "type": "module" in package.json
import JsonDB from 'jdb-lite';

await JsonDB.connect('./database');
// Your code here
```

### TypeScript
```typescript
// index.ts
import JsonDB, { Schema, Document } from 'jdb-lite';

interface User extends Document {
  name: string;
  email: string;
}

const userSchema = new Schema<User>({
  name: { type: 'String', required: true },
  email: { type: 'String', required: true }
});

await JsonDB.connect('./database');
const UserModel = JsonDB.model<User>('User', userSchema);
```

## 🔍 Query Examples

```javascript
// Basic queries
const users = await User.find({ age: 25 });
const user = await User.findOne({ email: 'john@example.com' });

// Comparison operators
const adults = await User.find({ age: { $gte: 18 } });
const seniors = await User.find({ age: { $gt: 65 } });
const young = await User.find({ age: { $lt: 30 } });

// Sorting and limiting
const newest = await User.find().sort({ createdAt: -1 }).limit(5);
const oldest = await User.find().sort({ createdAt: 1 }).limit(5);

// Pagination
const page2 = await User.find().skip(10).limit(10);

// Counting
const totalUsers = await User.countDocuments();
const activeUsers = await User.countDocuments({ isActive: true });
```

## 🛠️ Error Handling

```javascript
try {
  const user = new User({
    name: 'John',
    // Missing required email field
    age: 30
  });
  
  await user.save();
} catch (error) {
  console.error('Validation error:', error.message);
  // "Field 'email' is required"
}
```

## 🚀 Performance Tips

1. **Use indexes for frequently queried fields** (planned feature)
2. **Limit results with `.limit()`** to avoid loading large datasets
3. **Use `.countDocuments()`** instead of `.find().length` for counting
4. **Close connections** with `JsonDB.disconnect()` when done

## 📚 Migration from Other Libraries

### From Mongoose
```javascript
// Mongoose
const mongoose = require('mongoose');
const User = mongoose.model('User', userSchema);

// jdb-lite
const JsonDB = require('jdb-lite');
const User = JsonDB.model('User', userSchema);
```

### From Lowdb
```javascript
// Lowdb
const low = require('lowdb');
const db = low('db.json');

// jdb-lite
const JsonDB = require('jdb-lite');
await JsonDB.connect('./database');
```

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 📄 License

MIT License - see [LICENSE](LICENSE) file for details.

---

**Made with ❤️ for developers who need a simple, reliable JSON database solution.**
