Skip to content

Commit 6683c66

Browse files
authored
Merge pull request #108 from objectstack-ai/copilot/add-excel-driver-functionality
2 parents 840d7d4 + 892e2eb commit 6683c66

15 files changed

Lines changed: 3255 additions & 70 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Generated Excel files
2+
data/**/*.xlsx
3+
data/**/*.xls
4+
data/
5+
6+
# Build output
7+
dist/
8+
9+
# Dependencies
10+
node_modules/
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Excel Driver Demo
2+
3+
This example demonstrates the Excel Driver for ObjectQL.
4+
5+
## Installation
6+
7+
From the repository root:
8+
9+
```bash
10+
pnpm install
11+
```
12+
13+
## Running the Demo
14+
15+
```bash
16+
cd examples/drivers/excel-demo
17+
pnpm start
18+
```
19+
20+
## What This Demo Shows
21+
22+
1. **Creating Records** - Add users and products to Excel
23+
2. **Querying Data** - Filter, sort, search, and paginate
24+
3. **Updating Records** - Modify individual and bulk records
25+
4. **Deleting Records** - Remove records from Excel
26+
5. **Multiple Worksheets** - Separate sheets for different object types
27+
6. **Bulk Operations** - Create multiple records at once
28+
29+
## Output
30+
31+
The demo will:
32+
- Create an Excel file at `data/demo.xlsx`
33+
- Populate it with sample users and products
34+
- Demonstrate various query operations
35+
- Show the final state of the data
36+
37+
## Excel File Structure
38+
39+
After running, `data/demo.xlsx` will contain:
40+
41+
**Sheet: users**
42+
| id | name | email | role | age | department | created_at | updated_at |
43+
|----|------|-------|------|-----|------------|------------|------------|
44+
| ... | Alice Johnson | alice.johnson@... | admin | 31 | Tech | ... | ... |
45+
46+
**Sheet: products**
47+
| id | name | price | category | stock | created_at | updated_at |
48+
|----|------|-------|----------|-------|------------|------------|
49+
| ... | Laptop Pro | 1299.99 | Electronics | 50 | ... | ... |
50+
51+
## Next Steps
52+
53+
- Modify `src/index.ts` to experiment with different queries
54+
- Try adding your own object types
55+
- Explore filter operators and sorting options
56+
- Check the [Excel Driver README](../../../packages/drivers/excel/README.md)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "@objectql/example-excel-demo",
3+
"version": "0.1.0",
4+
"private": true,
5+
"description": "Example demonstrating the Excel Driver for ObjectQL",
6+
"scripts": {
7+
"start": "ts-node src/index.ts",
8+
"build": "tsc"
9+
},
10+
"dependencies": {
11+
"@objectql/driver-excel": "workspace:*",
12+
"@objectql/types": "workspace:*"
13+
},
14+
"devDependencies": {
15+
"@types/node": "^20.10.0",
16+
"ts-node": "^10.9.0",
17+
"typescript": "^5.0.0"
18+
}
19+
}
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
/**
2+
* Excel Driver Demo
3+
*
4+
* This example demonstrates both storage modes of the Excel Driver for ObjectQL:
5+
* 1. Single-file mode (default): All data in one Excel file
6+
* 2. File-per-object mode: Each object type in its own file
7+
*/
8+
9+
import { ExcelDriver } from '@objectql/driver-excel';
10+
import * as path from 'path';
11+
12+
async function demoFilePerObjectMode() {
13+
console.log('=' .repeat(60));
14+
console.log('📂 FILE-PER-OBJECT MODE DEMO');
15+
console.log('=' .repeat(60) + '\n');
16+
17+
const dataDir = path.join(__dirname, '../data/file-per-object');
18+
console.log(`📁 Using directory: ${dataDir}\n`);
19+
20+
const driver = await ExcelDriver.create({
21+
filePath: dataDir,
22+
fileStorageMode: 'file-per-object',
23+
createIfMissing: true,
24+
autoSave: true
25+
});
26+
27+
console.log('📝 Creating data in separate files...');
28+
29+
// Each object type will be stored in its own file
30+
await driver.create('customers', {
31+
name: 'ACME Corp',
32+
email: 'contact@acme.com',
33+
industry: 'Technology'
34+
});
35+
console.log('✓ Created customer (saved to customers.xlsx)');
36+
37+
await driver.create('invoices', {
38+
number: 'INV-001',
39+
amount: 5000.00,
40+
status: 'paid'
41+
});
42+
console.log('✓ Created invoice (saved to invoices.xlsx)');
43+
44+
await driver.create('tasks', {
45+
title: 'Review proposal',
46+
priority: 'high',
47+
status: 'in-progress'
48+
});
49+
console.log('✓ Created task (saved to tasks.xlsx)');
50+
51+
console.log('\n📊 Summary:');
52+
console.log(' - Each object type has its own Excel file');
53+
console.log(' - Better for large datasets or independent objects');
54+
console.log(' - Files: customers.xlsx, invoices.xlsx, tasks.xlsx\n');
55+
56+
await driver.disconnect();
57+
}
58+
59+
async function demoSingleFileMode() {
60+
console.log('=' .repeat(60));
61+
console.log('📄 SINGLE-FILE MODE DEMO');
62+
console.log('=' .repeat(60) + '\n');
63+
64+
// Initialize the Excel driver
65+
const dataPath = path.join(__dirname, '../data/demo.xlsx');
66+
console.log(`📁 Using Excel file: ${dataPath}\n`);
67+
68+
const driver = await ExcelDriver.create({
69+
filePath: dataPath,
70+
fileStorageMode: 'single-file', // Default mode (can be omitted)
71+
createIfMissing: true,
72+
autoSave: true
73+
});
74+
75+
// ========== CRUD Operations ==========
76+
console.log('📝 Creating users...');
77+
78+
const user1 = await driver.create('users', {
79+
name: 'Alice Johnson',
80+
email: 'alice@example.com',
81+
role: 'admin',
82+
age: 30,
83+
department: 'Engineering'
84+
});
85+
console.log('✓ Created:', user1.name, `(ID: ${user1.id})`);
86+
87+
const user2 = await driver.create('users', {
88+
name: 'Bob Smith',
89+
email: 'bob@example.com',
90+
role: 'user',
91+
age: 25,
92+
department: 'Marketing'
93+
});
94+
console.log('✓ Created:', user2.name, `(ID: ${user2.id})`);
95+
96+
const user3 = await driver.create('users', {
97+
name: 'Charlie Davis',
98+
email: 'charlie@example.com',
99+
role: 'user',
100+
age: 35,
101+
department: 'Engineering'
102+
});
103+
console.log('✓ Created:', user3.name, `(ID: ${user3.id})`);
104+
105+
// Create products
106+
console.log('\n📦 Creating products...');
107+
108+
await driver.create('products', {
109+
name: 'Laptop Pro',
110+
price: 1299.99,
111+
category: 'Electronics',
112+
stock: 50
113+
});
114+
console.log('✓ Created: Laptop Pro');
115+
116+
await driver.create('products', {
117+
name: 'Wireless Mouse',
118+
price: 29.99,
119+
category: 'Accessories',
120+
stock: 200
121+
});
122+
console.log('✓ Created: Wireless Mouse');
123+
124+
// ========== Query Operations ==========
125+
console.log('\n🔍 Querying data...');
126+
127+
// Find all users
128+
const allUsers = await driver.find('users');
129+
console.log(`\n✓ Found ${allUsers.length} users total`);
130+
131+
// Filter by role
132+
const admins = await driver.find('users', {
133+
filters: [['role', '=', 'admin']]
134+
});
135+
console.log(`✓ Found ${admins.length} admin(s):`, admins.map(u => u.name).join(', '));
136+
137+
// Filter by age
138+
const youngUsers = await driver.find('users', {
139+
filters: [['age', '<', 30]]
140+
});
141+
console.log(`✓ Found ${youngUsers.length} user(s) under 30:`, youngUsers.map(u => u.name).join(', '));
142+
143+
// Filter by department
144+
const engineers = await driver.find('users', {
145+
filters: [['department', '=', 'Engineering']]
146+
});
147+
console.log(`✓ Found ${engineers.length} engineer(s):`, engineers.map(u => u.name).join(', '));
148+
149+
// Search by name
150+
const searchResults = await driver.find('users', {
151+
filters: [['name', 'contains', 'li']]
152+
});
153+
console.log(`✓ Search "li" found ${searchResults.length} user(s):`, searchResults.map(u => u.name).join(', '));
154+
155+
// Sort users by age
156+
const sortedByAge = await driver.find('users', {
157+
sort: [['age', 'desc']]
158+
});
159+
console.log('✓ Users sorted by age (desc):', sortedByAge.map(u => `${u.name} (${u.age})`).join(', '));
160+
161+
// Pagination
162+
const pagedUsers = await driver.find('users', {
163+
limit: 2,
164+
skip: 1
165+
});
166+
console.log(`✓ Page 2 (limit 2, skip 1):`, pagedUsers.map(u => u.name).join(', '));
167+
168+
// Count
169+
const userCount = await driver.count('users', {});
170+
console.log(`✓ Total user count: ${userCount}`);
171+
172+
// Distinct values
173+
const departments = await driver.distinct('users', 'department');
174+
console.log('✓ Distinct departments:', departments.join(', '));
175+
176+
// ========== Update Operations ==========
177+
console.log('\n✏️ Updating records...');
178+
179+
await driver.update('users', user1.id, {
180+
email: 'alice.johnson@example.com',
181+
age: 31
182+
});
183+
console.log(`✓ Updated ${user1.name}'s email and age`);
184+
185+
// Update many
186+
const updateResult = await driver.updateMany(
187+
'users',
188+
[['department', '=', 'Engineering']],
189+
{ department: 'Tech' }
190+
);
191+
console.log(`✓ Updated ${updateResult.modifiedCount} user(s) department to Tech`);
192+
193+
// ========== Query Updated Data ==========
194+
console.log('\n🔄 After updates...');
195+
const updatedUser1 = await driver.findOne('users', user1.id);
196+
console.log(`✓ ${updatedUser1.name}: age=${updatedUser1.age}, email=${updatedUser1.email}`);
197+
198+
const techUsers = await driver.find('users', {
199+
filters: [['department', '=', 'Tech']]
200+
});
201+
console.log(`✓ Users in Tech: ${techUsers.map(u => u.name).join(', ')}`);
202+
203+
// ========== Multiple Worksheets ==========
204+
console.log('\n📊 Multiple worksheets (object types)...');
205+
const products = await driver.find('products');
206+
console.log(`✓ Found ${products.length} products in separate worksheet`);
207+
products.forEach(p => {
208+
console.log(` - ${p.name}: $${p.price} (${p.stock} in stock)`);
209+
});
210+
211+
// ========== Delete Operations ==========
212+
console.log('\n🗑️ Deleting records...');
213+
214+
await driver.delete('users', user2.id);
215+
console.log(`✓ Deleted ${user2.name}`);
216+
217+
const finalCount = await driver.count('users', {});
218+
console.log(`✓ Remaining users: ${finalCount}`);
219+
220+
// ========== Bulk Operations ==========
221+
console.log('\n📦 Bulk operations...');
222+
223+
const newUsers = await driver.createMany('users', [
224+
{ name: 'Diana Prince', email: 'diana@example.com', role: 'user', age: 28 },
225+
{ name: 'Ethan Hunt', email: 'ethan@example.com', role: 'admin', age: 40 }
226+
]);
227+
console.log(`✓ Created ${newUsers.length} users in bulk`);
228+
229+
// ========== Final Summary ==========
230+
console.log('\n📈 Final Summary:');
231+
const finalUsers = await driver.find('users');
232+
console.log(`✓ Total users in Excel: ${finalUsers.length}`);
233+
finalUsers.forEach((user, index) => {
234+
console.log(` ${index + 1}. ${user.name} (${user.role}, ${user.age} years old)`);
235+
});
236+
237+
const finalProducts = await driver.find('products');
238+
console.log(`✓ Total products in Excel: ${finalProducts.length}`);
239+
240+
console.log('\n📊 Summary:');
241+
console.log(' - All object types in one Excel file');
242+
console.log(' - Easy to manage (single file)');
243+
console.log(' - Best for related data sets');
244+
245+
// Clean up
246+
await driver.disconnect();
247+
248+
console.log('\n✅ Single-file mode demo completed!');
249+
console.log(`📁 Check the Excel file at: ${dataPath}\n`);
250+
}
251+
252+
async function main() {
253+
console.log('\n🚀 Excel Driver Demo - Storage Modes Comparison\n');
254+
255+
try {
256+
// Demo both storage modes
257+
await demoFilePerObjectMode();
258+
await demoSingleFileMode();
259+
260+
console.log('=' .repeat(60));
261+
console.log('✅ ALL DEMOS COMPLETED SUCCESSFULLY!');
262+
console.log('=' .repeat(60));
263+
console.log('\nYou can now:');
264+
console.log(' 1. Open data/demo.xlsx to see single-file mode results');
265+
console.log(' 2. Open data/file-per-object/*.xlsx to see file-per-object results');
266+
console.log('\n');
267+
} catch (error) {
268+
console.error('\n❌ Error:', error);
269+
process.exit(1);
270+
}
271+
}
272+
273+
// Run the demo
274+
main().catch(error => {
275+
console.error('❌ Fatal error:', error.message);
276+
process.exit(1);
277+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "./dist",
5+
"rootDir": "./src"
6+
},
7+
"include": ["src/**/*"]
8+
}

0 commit comments

Comments
 (0)