drizzle-cube 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -85
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
Transform your Drizzle schema into a powerful, type-safe analytics platform with SQL injection protection and full TypeScript support.
|
|
6
6
|
|
|
7
|
+
> **⚠️ DEVELOPMENT WARNING**
|
|
8
|
+
> **This project is under active development and is not yet fully functional. I will update here when we reach an alpha/working version!**
|
|
9
|
+
> Feel free to star ⭐ the repo to stay updated on progress.
|
|
10
|
+
|
|
7
11
|
[](https://www.npmjs.com/package/drizzle-cube)
|
|
8
12
|
[](https://www.typescriptlang.org/)
|
|
9
13
|
[](https://orm.drizzle.team/)
|
|
@@ -54,29 +58,68 @@ export const schema = { employees, departments }
|
|
|
54
58
|
|
|
55
59
|
```typescript
|
|
56
60
|
// cubes.ts
|
|
57
|
-
import { defineCube
|
|
61
|
+
import { defineCube } from 'drizzle-cube/server'
|
|
62
|
+
import { eq } from 'drizzle-orm'
|
|
58
63
|
import { schema } from './schema'
|
|
59
64
|
|
|
60
|
-
export const employeesCube = defineCube(
|
|
61
|
-
|
|
65
|
+
export const employeesCube = defineCube('Employees', {
|
|
66
|
+
title: 'Employee Analytics',
|
|
62
67
|
|
|
63
|
-
// Use Drizzle query
|
|
64
|
-
sql: (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
// Use Drizzle query structure for type safety
|
|
69
|
+
sql: (ctx) => ({
|
|
70
|
+
from: schema.employees,
|
|
71
|
+
joins: [
|
|
72
|
+
{
|
|
73
|
+
table: schema.departments,
|
|
74
|
+
on: eq(schema.employees.departmentId, schema.departments.id),
|
|
75
|
+
type: 'left'
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
where: eq(schema.employees.organisationId, ctx.securityContext.organisationId)
|
|
79
|
+
}),
|
|
69
80
|
|
|
70
81
|
dimensions: {
|
|
71
|
-
name: {
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
name: {
|
|
83
|
+
name: 'name',
|
|
84
|
+
title: 'Employee Name',
|
|
85
|
+
sql: schema.employees.name,
|
|
86
|
+
type: 'string'
|
|
87
|
+
},
|
|
88
|
+
email: {
|
|
89
|
+
name: 'email',
|
|
90
|
+
title: 'Email Address',
|
|
91
|
+
sql: schema.employees.email,
|
|
92
|
+
type: 'string'
|
|
93
|
+
},
|
|
94
|
+
departmentName: {
|
|
95
|
+
name: 'departmentName',
|
|
96
|
+
title: 'Department',
|
|
97
|
+
sql: schema.departments.name,
|
|
98
|
+
type: 'string'
|
|
99
|
+
}
|
|
74
100
|
},
|
|
75
101
|
|
|
76
102
|
measures: {
|
|
77
|
-
count: {
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
count: {
|
|
104
|
+
name: 'count',
|
|
105
|
+
title: 'Total Employees',
|
|
106
|
+
sql: schema.employees.id,
|
|
107
|
+
type: 'count'
|
|
108
|
+
},
|
|
109
|
+
totalSalary: {
|
|
110
|
+
name: 'totalSalary',
|
|
111
|
+
title: 'Total Salary',
|
|
112
|
+
sql: schema.employees.salary,
|
|
113
|
+
type: 'sum',
|
|
114
|
+
format: 'currency'
|
|
115
|
+
},
|
|
116
|
+
avgSalary: {
|
|
117
|
+
name: 'avgSalary',
|
|
118
|
+
title: 'Average Salary',
|
|
119
|
+
sql: schema.employees.salary,
|
|
120
|
+
type: 'avg',
|
|
121
|
+
format: 'currency'
|
|
122
|
+
}
|
|
80
123
|
}
|
|
81
124
|
})
|
|
82
125
|
```
|
|
@@ -89,13 +132,19 @@ import { drizzle } from 'drizzle-orm/postgres-js'
|
|
|
89
132
|
import { createCubeApp } from 'drizzle-cube/adapters/hono'
|
|
90
133
|
import { SemanticLayerCompiler } from 'drizzle-cube/server'
|
|
91
134
|
import postgres from 'postgres'
|
|
135
|
+
import { schema } from './schema'
|
|
136
|
+
import { employeesCube } from './cubes'
|
|
92
137
|
|
|
93
138
|
// Setup Drizzle
|
|
94
139
|
const client = postgres(process.env.DATABASE_URL!)
|
|
95
140
|
const db = drizzle(client, { schema })
|
|
96
141
|
|
|
97
142
|
// Create semantic layer
|
|
98
|
-
const semanticLayer = new SemanticLayerCompiler({
|
|
143
|
+
const semanticLayer = new SemanticLayerCompiler({
|
|
144
|
+
drizzle: db,
|
|
145
|
+
schema,
|
|
146
|
+
engineType: 'postgres'
|
|
147
|
+
})
|
|
99
148
|
semanticLayer.registerCube(employeesCube)
|
|
100
149
|
|
|
101
150
|
// Create API server with Cube.js compatibility
|
|
@@ -161,10 +210,19 @@ const condition = eq(schema.employees.name, userInput)
|
|
|
161
210
|
Get full TypeScript support from your database schema to your analytics:
|
|
162
211
|
|
|
163
212
|
```typescript
|
|
164
|
-
const cube = defineCube(
|
|
213
|
+
const cube = defineCube('Employees', {
|
|
165
214
|
dimensions: {
|
|
166
|
-
name: {
|
|
167
|
-
|
|
215
|
+
name: {
|
|
216
|
+
name: 'name',
|
|
217
|
+
title: 'Employee Name',
|
|
218
|
+
sql: schema.employees.name, // ✅ Type-safe
|
|
219
|
+
type: 'string'
|
|
220
|
+
},
|
|
221
|
+
invalid: {
|
|
222
|
+
name: 'invalid',
|
|
223
|
+
sql: schema.employees.invalidCol, // ❌ TypeScript error
|
|
224
|
+
type: 'string'
|
|
225
|
+
}
|
|
168
226
|
}
|
|
169
227
|
})
|
|
170
228
|
```
|
|
@@ -186,82 +244,54 @@ Works with multiple frameworks via adapter pattern:
|
|
|
186
244
|
|
|
187
245
|
## Advanced Usage
|
|
188
246
|
|
|
189
|
-
|
|
247
|
+
|
|
248
|
+
### Advanced Security with Row-Level Security
|
|
190
249
|
|
|
191
250
|
```typescript
|
|
192
|
-
|
|
193
|
-
|
|
251
|
+
import { and, sql } from 'drizzle-orm'
|
|
252
|
+
|
|
253
|
+
const secureCube = defineCube('SecureEmployees', {
|
|
254
|
+
title: 'Secure Employee Data',
|
|
194
255
|
|
|
195
|
-
sql: (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
LEFT JOIN ${schema.employees} e ON d.id = e.department_id
|
|
204
|
-
WHERE d.organisation_id = ${securityContext.organisationId}
|
|
205
|
-
GROUP BY d.id, d.name
|
|
256
|
+
sql: (ctx) => ({
|
|
257
|
+
from: schema.employees,
|
|
258
|
+
where: and(
|
|
259
|
+
eq(schema.employees.organisationId, ctx.securityContext.organisationId),
|
|
260
|
+
// Only show employees user has permission to see
|
|
261
|
+
ctx.securityContext.role === 'admin'
|
|
262
|
+
? sql`true`
|
|
263
|
+
: eq(schema.employees.managerId, ctx.securityContext.userId)
|
|
206
264
|
)
|
|
207
|
-
|
|
208
|
-
`,
|
|
265
|
+
}),
|
|
209
266
|
|
|
210
267
|
dimensions: {
|
|
211
|
-
name: {
|
|
268
|
+
name: {
|
|
269
|
+
name: 'name',
|
|
270
|
+
title: 'Employee Name',
|
|
271
|
+
sql: schema.employees.name,
|
|
272
|
+
type: 'string'
|
|
273
|
+
}
|
|
212
274
|
},
|
|
213
275
|
|
|
214
276
|
measures: {
|
|
215
|
-
|
|
216
|
-
|
|
277
|
+
count: {
|
|
278
|
+
name: 'count',
|
|
279
|
+
title: 'Employee Count',
|
|
280
|
+
sql: schema.employees.id,
|
|
281
|
+
type: 'count'
|
|
282
|
+
}
|
|
217
283
|
}
|
|
218
284
|
})
|
|
219
285
|
```
|
|
220
286
|
|
|
221
|
-
### Advanced Security with Row-Level Security
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
const secureCube = defineCube(schema, {
|
|
225
|
-
name: 'SecureEmployees',
|
|
226
|
-
|
|
227
|
-
sql: ({ db, securityContext }) =>
|
|
228
|
-
db.select()
|
|
229
|
-
.from(schema.employees)
|
|
230
|
-
.where(
|
|
231
|
-
and(
|
|
232
|
-
eq(schema.employees.organisationId, securityContext.organisationId),
|
|
233
|
-
// Only show employees user has permission to see
|
|
234
|
-
securityContext.role === 'admin'
|
|
235
|
-
? sql`true`
|
|
236
|
-
: eq(schema.employees.managerId, securityContext.userId)
|
|
237
|
-
)
|
|
238
|
-
)
|
|
239
|
-
})
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Multiple Database Support
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
// PostgreSQL
|
|
246
|
-
import { drizzle } from 'drizzle-orm/postgres-js'
|
|
247
|
-
import postgres from 'postgres'
|
|
248
|
-
|
|
249
|
-
// MySQL
|
|
250
|
-
import { drizzle } from 'drizzle-orm/mysql2'
|
|
251
|
-
import mysql from 'mysql2/promise'
|
|
252
|
-
|
|
253
|
-
// SQLite
|
|
254
|
-
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
255
|
-
import Database from 'better-sqlite3'
|
|
256
|
-
```
|
|
257
287
|
|
|
258
288
|
## API Reference
|
|
259
289
|
|
|
260
290
|
### Core Functions
|
|
261
291
|
|
|
262
|
-
- `defineCube(
|
|
263
|
-
- `
|
|
264
|
-
- `createCubeApp(options)` - Create Cube.js API server
|
|
292
|
+
- `defineCube(name, definition)` - Create type-safe cube with name and configuration
|
|
293
|
+
- `SemanticLayerCompiler({ drizzle, schema, engineType })` - Setup semantic layer compiler
|
|
294
|
+
- `createCubeApp(options)` - Create Cube.js-compatible API server
|
|
265
295
|
|
|
266
296
|
### Supported Drizzle Features
|
|
267
297
|
|
|
@@ -288,17 +318,11 @@ Supports all Cube.js filter operators with Drizzle safety:
|
|
|
288
318
|
|
|
289
319
|
## Documentation
|
|
290
320
|
|
|
291
|
-
|
|
292
|
-
🏗️ **[API Reference](https://drizzle-cube.dev/api)**
|
|
293
|
-
🎯 **[Drizzle Integration Guide](./docs/drizzle-integration.md)**
|
|
294
|
-
🚀 **[Migration Guide](https://drizzle-cube.dev/migration)**
|
|
321
|
+
Coming soon! 📚
|
|
295
322
|
|
|
296
323
|
## Examples
|
|
297
324
|
|
|
298
|
-
|
|
299
|
-
- **[Advanced Security](./examples/hono-security/)**
|
|
300
|
-
- **[Multi-tenant SaaS](./examples/multi-tenant/)**
|
|
301
|
-
- **[Real-time Dashboard](./examples/dashboard/)**
|
|
325
|
+
Coming soon! Check the test files for usage patterns in the meantime.
|
|
302
326
|
|
|
303
327
|
## Contributing
|
|
304
328
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drizzle-cube",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.",
|
|
5
5
|
"main": "./dist/server/index.js",
|
|
6
6
|
"types": "./dist/server/index.d.ts",
|