Skip to content

Commit 94cb232

Browse files
Copilothuangyiirene
andcommitted
Add FileSystem driver package with tests, docs, and example
Co-authored-by: huangyiirene <[email protected]>
1 parent a3ccc12 commit 94cb232

File tree

12 files changed

+1650
-0
lines changed

12 files changed

+1650
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Data directory (generated at runtime)
2+
data/
3+
4+
# Node modules
5+
node_modules/
6+
7+
# Build output
8+
dist/
9+
10+
# OS files
11+
.DS_Store

examples/drivers/fs-demo/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# FileSystem Driver Demo
2+
3+
This example demonstrates how to use the `@objectql/driver-fs` package for file-based storage with ObjectQL.
4+
5+
## Features Demonstrated
6+
7+
- ✅ File system-based persistent storage
8+
- ✅ One JSON file per object type
9+
- ✅ CRUD operations (Create, Read, Update, Delete)
10+
- ✅ Query operations (filters, sorting, pagination)
11+
- ✅ Aggregate operations (count, distinct)
12+
- ✅ Human-readable JSON format
13+
- ✅ Automatic backup files
14+
15+
## Running the Demo
16+
17+
```bash
18+
# From the project root
19+
npm run dev
20+
21+
# Or directly
22+
ts-node src/index.ts
23+
```
24+
25+
## What It Does
26+
27+
1. **Initializes** the FileSystem driver with a data directory
28+
2. **Creates** a schema for "projects" with various fields
29+
3. **Inserts** 4 sample projects
30+
4. **Queries** the data with different filters
31+
5. **Updates** a project status
32+
6. **Shows** aggregate operations
33+
34+
## Output
35+
36+
After running, you'll see:
37+
- Console output showing all operations
38+
- A `data/` directory with `projects.json` file
39+
- A `projects.json.bak` backup file
40+
41+
## Inspecting the Data
42+
43+
The data is stored in human-readable JSON:
44+
45+
```bash
46+
cat data/projects.json
47+
```
48+
49+
You can manually edit this file and the changes will be reflected in the application!
50+
51+
## Data Directory Structure
52+
53+
```
54+
fs-demo/
55+
├── src/
56+
│ └── index.ts
57+
├── data/ ← Created on first run
58+
│ ├── projects.json ← Current data
59+
│ └── projects.json.bak ← Backup
60+
├── package.json
61+
└── tsconfig.json
62+
```
63+
64+
## Use Cases
65+
66+
This driver is ideal for:
67+
- Development and prototyping
68+
- Small applications (< 10k records)
69+
- Configuration storage
70+
- Embedded applications
71+
- Scenarios without database setup
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "fs-demo",
3+
"version": "0.1.0",
4+
"private": true,
5+
"description": "Example demonstrating @objectql/driver-fs",
6+
"scripts": {
7+
"start": "ts-node src/index.ts",
8+
"dev": "ts-node src/index.ts"
9+
},
10+
"dependencies": {
11+
"@objectql/core": "workspace:*",
12+
"@objectql/driver-fs": "workspace:*"
13+
},
14+
"devDependencies": {
15+
"@types/node": "^20.0.0",
16+
"ts-node": "^10.9.0",
17+
"typescript": "^5.0.0"
18+
}
19+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { ObjectQL } from '@objectql/core';
2+
import { FileSystemDriver } from '@objectql/driver-fs';
3+
import * as path from 'path';
4+
5+
async function main() {
6+
console.log("🚀 ObjectQL FileSystem Driver Demo\n");
7+
8+
// 1. Initialize Driver with data directory
9+
const dataDir = path.join(__dirname, '../data');
10+
const driver = new FileSystemDriver({
11+
dataDir: dataDir,
12+
prettyPrint: true,
13+
enableBackup: true
14+
});
15+
16+
console.log(`📁 Data directory: ${dataDir}\n`);
17+
18+
// 2. Initialize ObjectQL
19+
const app = new ObjectQL({
20+
datasources: {
21+
default: driver
22+
}
23+
});
24+
25+
// 3. Define Object Schema
26+
app.registerObject({
27+
name: 'projects',
28+
label: 'Projects',
29+
fields: {
30+
name: {
31+
type: 'text',
32+
required: true,
33+
label: 'Project Name'
34+
},
35+
status: {
36+
type: 'select',
37+
options: [
38+
{ label: 'Planning', value: 'planning' },
39+
{ label: 'In Progress', value: 'in_progress' },
40+
{ label: 'Completed', value: 'completed' }
41+
],
42+
defaultValue: 'planning',
43+
label: 'Status'
44+
},
45+
priority: {
46+
type: 'select',
47+
options: [
48+
{ label: 'Low', value: 'low' },
49+
{ label: 'Medium', value: 'medium' },
50+
{ label: 'High', value: 'high' }
51+
],
52+
defaultValue: 'medium',
53+
label: 'Priority'
54+
},
55+
budget: {
56+
type: 'currency',
57+
label: 'Budget'
58+
},
59+
startDate: {
60+
type: 'date',
61+
label: 'Start Date'
62+
}
63+
}
64+
});
65+
66+
await app.init();
67+
68+
// 4. Get Repository
69+
const ctx = app.createContext({ isSystem: true });
70+
const projects = ctx.object('projects');
71+
72+
// 5. Create Sample Projects
73+
console.log("📝 Creating sample projects...\n");
74+
75+
await projects.create({
76+
id: 'PROJ-001',
77+
name: 'Website Redesign',
78+
status: 'in_progress',
79+
priority: 'high',
80+
budget: 50000,
81+
startDate: '2024-01-15'
82+
});
83+
84+
await projects.create({
85+
id: 'PROJ-002',
86+
name: 'Mobile App Development',
87+
status: 'planning',
88+
priority: 'high',
89+
budget: 80000,
90+
startDate: '2024-02-01'
91+
});
92+
93+
await projects.create({
94+
id: 'PROJ-003',
95+
name: 'Infrastructure Upgrade',
96+
status: 'in_progress',
97+
priority: 'medium',
98+
budget: 30000,
99+
startDate: '2024-01-10'
100+
});
101+
102+
await projects.create({
103+
id: 'PROJ-004',
104+
name: 'Marketing Campaign',
105+
status: 'completed',
106+
priority: 'low',
107+
budget: 15000,
108+
startDate: '2023-12-01'
109+
});
110+
111+
console.log("✅ Created 4 projects\n");
112+
113+
// 6. Query Examples
114+
console.log("🔍 Query Examples:\n");
115+
116+
// Find all projects
117+
const allProjects = await projects.find({});
118+
console.log(`📊 Total projects: ${allProjects.length}`);
119+
120+
// Find high priority projects
121+
const highPriority = await projects.find({
122+
filters: [['priority', '=', 'high']]
123+
});
124+
console.log(`🔥 High priority projects: ${highPriority.length}`);
125+
highPriority.forEach(p => console.log(` - ${p.name}`));
126+
127+
// Find in-progress projects
128+
const inProgress = await projects.find({
129+
filters: [['status', '=', 'in_progress']]
130+
});
131+
console.log(`\n⚡ In-progress projects: ${inProgress.length}`);
132+
inProgress.forEach(p => console.log(` - ${p.name}`));
133+
134+
// Find projects with budget > 40000
135+
const largeBudget = await projects.find({
136+
filters: [['budget', '>', 40000]]
137+
});
138+
console.log(`\n💰 Projects with budget > $40,000: ${largeBudget.length}`);
139+
largeBudget.forEach(p => console.log(` - ${p.name}: $${p.budget.toLocaleString()}`));
140+
141+
// Sort by budget
142+
const sortedByBudget = await projects.find({
143+
sort: [['budget', 'desc']]
144+
});
145+
console.log(`\n📈 Projects sorted by budget (desc):`);
146+
sortedByBudget.forEach(p => console.log(` - ${p.name}: $${p.budget.toLocaleString()}`));
147+
148+
// 7. Update Example
149+
console.log(`\n🔄 Updating project status...\n`);
150+
await projects.update('PROJ-002', { status: 'in_progress' });
151+
const updated = await projects.findOne('PROJ-002');
152+
console.log(`✅ Updated ${updated.name} to ${updated.status}`);
153+
154+
// 8. Aggregate Operations
155+
console.log(`\n📊 Aggregate Operations:\n`);
156+
157+
const statusCount = await projects.count({
158+
filters: [['status', '=', 'in_progress']]
159+
});
160+
console.log(`In-progress projects: ${statusCount}`);
161+
162+
const priorities = await projects.distinct('priority');
163+
console.log(`Distinct priorities: ${priorities.join(', ')}`);
164+
165+
// 9. Show file location
166+
console.log(`\n📁 Data Files:\n`);
167+
console.log(` JSON file: ${dataDir}/projects.json`);
168+
console.log(` Backup: ${dataDir}/projects.json.bak`);
169+
console.log(`\n💡 Tip: Open the JSON files to see human-readable data!`);
170+
171+
// Cleanup
172+
await app.close();
173+
}
174+
175+
// Run the demo
176+
if (require.main === module) {
177+
main().catch(console.error);
178+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "./dist"
5+
},
6+
"include": ["src/**/*"]
7+
}

packages/drivers/fs/CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Changelog
2+
3+
All notable changes to the @objectql/driver-fs package will be documented in this file.
4+
5+
## [0.1.0] - 2024-01-16
6+
7+
### Added
8+
- Initial release of FileSystem Driver for ObjectQL
9+
- One JSON file per table/object type
10+
- Atomic write operations with temp file + rename strategy
11+
- Automatic backup files (`.bak`) on write
12+
- Full query support (filters, sorting, pagination, field projection)
13+
- Support for all standard Driver interface methods:
14+
- find, findOne, create, update, delete
15+
- count, distinct
16+
- createMany, updateMany, deleteMany
17+
- Pretty-printed JSON for human readability
18+
- Zero external dependencies (only @objectql/types)
19+
- Comprehensive test suite with 30+ test cases
20+
- Complete documentation and examples

0 commit comments

Comments
 (0)