Skip to content

Commit 843fc62

Browse files
committed
feat: Add project and task management modules with comprehensive hooks, permissions, and validation
- Introduced project management features including data structure, hooks for lifecycle events, and validation rules. - Implemented task management with associated data structure and permissions. - Added YAML files for initial data, permissions, and validation rules for both projects and tasks. - Created TypeScript interfaces for projects and tasks to ensure type safety. - Configured TypeScript settings for the project tracker module.
1 parent 8dea4b9 commit 843fc62

35 files changed

+2985
-42
lines changed

docs/guide/cli.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ npx objectql init [options]
2626

2727
| Option | Alias | Default | Description |
2828
| :--- | :--- | :--- | :--- |
29-
| `--template <template>` | `-t` | `basic` | Template to use (`basic`, `express-api`, `enterprise`). |
29+
| `--template <template>` | `-t` | `starter` | Template to use (`starter`, `hello-world`). |
3030
| `--name <name>` | `-n` | - | Project name. |
3131
| `--dir <path>` | `-d` | - | Target directory. |
3232
| `--skip-install` | | `false` | Skip dependency installation. |
@@ -35,7 +35,7 @@ npx objectql init [options]
3535
**Example:**
3636

3737
```bash
38-
npx objectql init -t express-api -n my-app
38+
npx objectql init -t starter -n my-app
3939
```
4040

4141
### 2.2 `generate` (Type Generation)

docs/guide/getting-started.md

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,43 @@
88
2. **Universal Protocol**: The query language is a JSON AST, making it easy for frontends or AI agents to generate queries.
99
3. **Action & Hook System**: Built-in support for "Button Actions" (RPC) and "Triggers" (Hooks), allowing you to model **Behavior** alongside **Data**.
1010

11-
## Quick Start: The "Hello World"
11+
## Quick Start
1212

13-
You can experience ObjectQL with a single file. No YAML, no complex config.
13+
The fastest way to get started is using the CLI to scaffold a project.
1414

15-
### 1. Minimal Setup
15+
### 1. Minimal Setup (Hello World)
1616

17-
Install the core and SQLite driver (for zero-config database).
17+
Create a single-file project to learn the basics.
1818

1919
```bash
20-
npm install @objectql/core @objectql/driver-sql sqlite3
21-
# or
22-
pnpm add @objectql/core @objectql/driver-sql sqlite3
20+
# Initialize a new project
21+
npx @objectql/cli init --template hello-world --name my-first-app
22+
23+
# Enter directory
24+
cd my-first-app
25+
26+
# Start the app
27+
npm start
2328
```
2429

25-
### 2. The Universal Script
30+
This will create an `index.ts` file that defines a schema, initializes an in-memory SQLite database, and runs some queries.
31+
32+
### 2. Standard Setup (Project Tracker)
33+
34+
For building real applications, use the `starter` template. This sets up a proper folder structure with YAML metadata, TypeScript logic hooks, and relationship management.
35+
36+
```bash
37+
npx @objectql/cli init --template starter --name project-tracker
38+
```
39+
40+
This structure follows our **Best Practices**:
41+
* **`src/objects/*.object.yml`**: Data definitions.
42+
* **`src/hooks/*.hook.ts`**: Business logic.
43+
* **`src/index.ts`**: Application entry point.
44+
45+
## Manual Setup (The Hard Way)
2646

27-
Create `index.ts`. This script defines the schema, boots the engine, and runs queries in one go.
47+
If you prefer to set up manually or add ObjectQL to an existing project:
2848

2949
```typescript
3050
import { ObjectQL } from '@objectql/core';

packages/tools/cli/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@
1616
],
1717
"license": "MIT",
1818
"main": "dist/index.js",
19+
"files": [
20+
"dist",
21+
"bin",
22+
"templates"
23+
],
1924
"bin": {
2025
"objectql": "./bin/objectql"
2126
},
2227
"scripts": {
23-
"build": "tsc",
28+
"build": "tsc && pnpm run copy-templates",
29+
"copy-templates": "rm -rf templates && mkdir -p templates && cp -r ../../../examples/quickstart/hello-world templates/ && cp -r ../../../examples/showcase/project-tracker templates/ && rm -rf templates/*/node_modules templates/*/dist",
2430
"watch": "tsc -w",
2531
"test": "jest"
2632
},

packages/tools/cli/src/commands/init.ts

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ interface InitOptions {
1515
}
1616

1717
const TEMPLATES = {
18-
basic: '@objectql/starter-basic',
19-
'express-api': '@objectql/starter-express-api',
20-
enterprise: '@objectql/starter-enterprise'
18+
'hello-world': 'hello-world',
19+
'starter': 'project-tracker'
2120
};
2221

2322
export async function initProject(options: InitOptions) {
2423
const projectName = options.name || 'my-objectql-project';
2524
const targetDir = options.dir || path.join(process.cwd(), projectName);
26-
const template = (options.template || 'basic') as keyof typeof TEMPLATES;
25+
const template = (options.template || 'starter') as keyof typeof TEMPLATES;
2726

2827
if (!TEMPLATES[template]) {
2928
console.error(chalk.red(`❌ Unknown template: ${template}`));
@@ -45,42 +44,48 @@ export async function initProject(options: InitOptions) {
4544
fs.mkdirSync(targetDir, { recursive: true });
4645

4746
try {
48-
// Copy template files from starters
49-
const templatePath = path.join(__dirname, '../../../../starters', template);
50-
51-
// Check if we're in the monorepo (for development)
52-
if (fs.existsSync(templatePath)) {
53-
console.log(chalk.gray('Copying template files...'));
54-
await copyDirectory(templatePath, targetDir, ['node_modules', 'dist', '.git']);
55-
} else {
56-
// Try to use the published package
57-
console.log(chalk.gray(`Installing template from npm: ${TEMPLATES[template]}...`));
58-
await execAsync(`npm create ${TEMPLATES[template]} ${targetDir}`, {
59-
cwd: process.cwd()
60-
});
47+
// Copy embedded template
48+
const templateName = TEMPLATES[template];
49+
// Must resolve relative to the dist/commands folder structure
50+
const sourcePath = path.resolve(__dirname, '../../templates', templateName);
51+
52+
if (!fs.existsSync(sourcePath)) {
53+
// Fallback for development (running directly from src)
54+
// If running via ts-node in dev, structure might be different
55+
throw new Error(`Template not found at ${sourcePath}. Please check your CLI installation.`);
6156
}
6257

58+
console.log(chalk.cyan(`⬇️ Creating project from embedded template...`));
59+
await copyDirectory(sourcePath, targetDir, ['node_modules', 'dist', '.git']);
60+
console.log(chalk.green('✅ Template created successfully.'));
61+
6362
// Update package.json with project name
6463
const pkgPath = path.join(targetDir, 'package.json');
6564
if (fs.existsSync(pkgPath)) {
6665
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
6766
pkg.name = projectName;
6867
pkg.version = '0.1.0';
69-
// Convert workspace dependencies to actual versions for standalone project
70-
if (pkg.dependencies) {
71-
for (const dep of Object.keys(pkg.dependencies)) {
72-
if (pkg.dependencies[dep] === 'workspace:*') {
73-
pkg.dependencies[dep] = '^1.0.0'; // Use latest published version
74-
}
75-
}
76-
}
77-
if (pkg.devDependencies) {
78-
for (const dep of Object.keys(pkg.devDependencies)) {
79-
if (pkg.devDependencies[dep] === 'workspace:*') {
80-
pkg.devDependencies[dep] = '^1.0.0';
68+
69+
// Note: Since we are using examples from the monorepo,
70+
// they might have "workspace:*" protocols.
71+
// We should replace them with "latest" or a specific version for end users.
72+
const replaceWorkspaceVersion = (deps: Record<string, string>) => {
73+
for (const dep of Object.keys(deps)) {
74+
if (deps[dep] === 'workspace:*') {
75+
// For public release, this should match the current CLI version or latest
76+
deps[dep] = 'latest';
8177
}
8278
}
83-
}
79+
};
80+
81+
if (pkg.dependencies) replaceWorkspaceVersion(pkg.dependencies);
82+
if (pkg.devDependencies) replaceWorkspaceVersion(pkg.devDependencies); // Often peerDeps in examples
83+
84+
// Make public for the user's new project
85+
delete pkg.private;
86+
// Reset repository field as it will be a new repo
87+
delete pkg.repository;
88+
8489
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
8590
}
8691

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# @example/hello-world
2+
3+
## 1.0.4
4+
5+
### Patch Changes
6+
7+
- Updated dependencies
8+
- @objectql/core@1.8.4
9+
- @objectql/driver-sql@1.8.4
10+
11+
## 1.0.3
12+
13+
### Patch Changes
14+
15+
- Updated dependencies
16+
- @objectql/core@1.8.3
17+
- @objectql/driver-sql@1.8.3
18+
19+
## 1.0.2
20+
21+
### Patch Changes
22+
23+
- Updated dependencies
24+
- @objectql/core@1.8.2
25+
- @objectql/driver-sql@1.8.2
26+
27+
## 1.0.1
28+
29+
### Patch Changes
30+
31+
- Updated dependencies
32+
- @objectql/core@1.8.1
33+
- @objectql/driver-sql@1.8.1
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Hello ObjectQL
2+
3+
This is the simplest possible example of **ObjectQL**.
4+
5+
It demonstrates:
6+
1. **Zero Config:** No YAML files or server setup required.
7+
2. **In-Memory SQL:** Uses SQLite in memory, so no database installation is needed.
8+
3. **Inline Schema:** Defines the data model directly in code.
9+
10+
## How to Run
11+
12+
Since you are in the monorepo, simply run:
13+
14+
```bash
15+
# Install dependencies (if not already done at root)
16+
pnpm install
17+
18+
# Run the script
19+
cd examples/starters/hello-world
20+
pnpm start
21+
```
22+
23+
## What you see
24+
25+
The script will:
26+
1. Initialize the ObjectQL engine.
27+
2. Create a `deal` object definition on the fly.
28+
3. Insert a record into the in-memory SQLite database.
29+
4. Query it back and print the result.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@objectql/example-hello-world",
3+
"version": "1.0.4",
4+
"private": true,
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/objectql/objectql.git",
8+
"directory": "examples/quickstart/hello-world"
9+
},
10+
"description": "Zero-config ObjectQL starter",
11+
"scripts": {
12+
"start": "ts-node src/index.ts"
13+
},
14+
"dependencies": {
15+
"@objectql/core": "workspace:*",
16+
"@objectql/driver-sql": "workspace:*",
17+
"sqlite3": "^5.1.7"
18+
},
19+
"devDependencies": {
20+
"ts-node": "^10.9.2",
21+
"typescript": "^5.3.3",
22+
"@types/node": "^20.11.24"
23+
}
24+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { ObjectQL } from '@objectql/core';
2+
import { SqlDriver } from '@objectql/driver-sql';
3+
4+
async function main() {
5+
console.log("🚀 Starting ObjectQL Hello World...");
6+
7+
// 1. Initialize Driver
8+
const driver = new SqlDriver({
9+
client: 'sqlite3',
10+
connection: { filename: ':memory:' },
11+
useNullAsDefault: true
12+
});
13+
14+
// 2. Initialize Engine (Pass driver in config)
15+
const app = new ObjectQL({
16+
datasources: {
17+
default: driver
18+
}
19+
});
20+
21+
// 3. Define Metadata Inline
22+
app.registerObject({
23+
name: 'deal',
24+
fields: {
25+
title: { type: 'text', required: true },
26+
amount: { type: 'currency' },
27+
stage: {
28+
type: 'select',
29+
options: [
30+
{ label: 'New', value: 'new' },
31+
{ label: 'Negotiation', value: 'negotiation' },
32+
{ label: 'Closed', value: 'closed' }
33+
],
34+
defaultValue: 'new'
35+
}
36+
}
37+
});
38+
39+
await app.init(); // Boot the engine
40+
41+
// 4. Run Business Logic
42+
const ctx = app.createContext({ isSystem: true });
43+
const repo = ctx.object('deal');
44+
45+
console.log("Creating a new Deal...");
46+
await repo.create({
47+
title: 'Enterprise Contract',
48+
amount: 50000,
49+
stage: 'new'
50+
});
51+
52+
const results = await repo.find({});
53+
console.log('✅ Deals found in database:', results);
54+
}
55+
56+
if (require.main === module) {
57+
main().catch(console.error);
58+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "./dist",
5+
"rootDir": "./src",
6+
"module": "CommonJS",
7+
"moduleResolution": "node"
8+
},
9+
"include": ["src/**/*"]
10+
}

0 commit comments

Comments
 (0)