Skip to content

Commit ecaa5d6

Browse files
authored
Merge pull request #279 from objectstack-ai/copilot/implement-object-and-field-schemas
2 parents 53dcd32 + f61c8ca commit ecaa5d6

File tree

12 files changed

+3420
-19
lines changed

12 files changed

+3420
-19
lines changed

PHASE3_IMPLEMENTATION.md

Lines changed: 508 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ npm install @object-ui/react @object-ui/components @object-ui/data-objectstack
7878
- Comprehensive documentation
7979
- Active development and support
8080

81+
### 🔥 **Phase 3: Enterprise Data Protocol** (NEW!)
82+
- **Advanced Field Types**: Vector (AI embeddings), Grid (sub-tables), Formula, Summary
83+
- **Query AST Builder**: SQL-like queries with joins, aggregations, subqueries
84+
- **Smart Validation**: 30+ rules, async validation, cross-field dependencies
85+
- **Multi-Datasource**: Health monitoring, connection pooling, query caching
86+
- **40+ Filter Operators**: Date ranges, lookup filters, full-text search
87+
- **Object Inheritance**: Triggers, advanced permissions, metadata caching
88+
8189
## Why Object UI?
8290

8391
### For You as a Developer
@@ -292,17 +300,31 @@ Object UI is perfect for:
292300
293301
## 🛣️ Roadmap
294302
295-
**Q1 2026** (Available March 2026):
296-
- ✅ Core schema rendering
297-
- ✅ 20+ production-ready components
298-
- ✅ Expression system
303+
**Phase 1-2 (Q4 2025 - Q1 2026)****COMPLETED**:
304+
- ✅ Core schema rendering engine
305+
- ✅ 40+ production-ready components (Shadcn + Tailwind)
306+
- ✅ Expression system with field references
307+
- ✅ Action system (AJAX, chaining, conditions)
308+
- ✅ Theme system (light/dark mode)
309+
- ✅ Report builder with exports
299310
- ✅ Visual designer (beta)
300311
301-
**Q2-Q4 2026**:
302-
- 🔄 Advanced data binding
303-
- 🔄 Real-time collaboration
304-
- 🔄 Mobile components
312+
**Phase 3 (Q1-Q2 2026)****COMPLETED**:
313+
- ✅ **Advanced Field Types**: Vector (AI embeddings), Grid (sub-tables), Formula, Summary
314+
- ✅ **ObjectSchema Enhancements**: Inheritance, triggers, advanced permissions, metadata caching
315+
- ✅ **QuerySchema AST**: SQL-like query building with joins, aggregations, subqueries
316+
- ✅ **Advanced Filtering**: 40+ operators, date ranges, lookup filters, full-text search
317+
- ✅ **Validation Engine**: 30+ rules, async validation, cross-field validation
318+
- ✅ **DriverInterface**: Transactions, batch operations, connection pooling, query caching
319+
- ✅ **DatasourceSchema**: Multi-datasource management, health monitoring
320+
321+
**Phase 4+ (Q2-Q4 2026)**:
322+
- 🔄 Real-time collaboration features
323+
- 🔄 Mobile-optimized components
305324
- 🔄 AI-powered schema generation
325+
- 🔄 Advanced workflow automation
326+
327+
See [PHASE3_IMPLEMENTATION.md](./PHASE3_IMPLEMENTATION.md) for detailed Phase 3 documentation.
306328
307329
## 🤝 Contributing
308330

packages/core/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
export * from './types';
1010
export * from './registry/Registry';
11-
export * from './validation/schema-validator';
11+
export * from './validation';
1212
export * from './builder/schema-builder';
1313
export * from './utils/filter-converter';
1414
export * from './evaluator';
1515
export * from './actions';
16+
export * from './query';
1617
// export * from './data-scope'; // TODO
1718
// export * from './validators'; // TODO
1819

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/**
2+
* @object-ui/core - Query AST Builder Tests
3+
*/
4+
5+
import { describe, it, expect } from 'vitest';
6+
import { QueryASTBuilder } from '../query-ast';
7+
import type { QuerySchema } from '@object-ui/types';
8+
9+
describe('QueryASTBuilder', () => {
10+
const builder = new QueryASTBuilder();
11+
12+
describe('Basic Query Building', () => {
13+
it('should build simple SELECT query', () => {
14+
const query: QuerySchema = {
15+
object: 'users',
16+
fields: ['id', 'name', 'email'],
17+
};
18+
19+
const ast = builder.build(query);
20+
21+
expect(ast.select.type).toBe('select');
22+
expect(ast.select.fields).toHaveLength(3);
23+
expect(ast.from.table).toBe('users');
24+
});
25+
26+
it('should build SELECT * when no fields specified', () => {
27+
const query: QuerySchema = {
28+
object: 'users',
29+
};
30+
31+
const ast = builder.build(query);
32+
33+
expect(ast.select.fields).toHaveLength(1);
34+
expect(ast.select.fields[0]).toMatchObject({
35+
type: 'field',
36+
name: '*',
37+
});
38+
});
39+
40+
it('should build query with WHERE clause', () => {
41+
const query: QuerySchema = {
42+
object: 'users',
43+
fields: ['id', 'name'],
44+
filter: {
45+
conditions: [
46+
{
47+
field: 'status',
48+
operator: 'equals',
49+
value: 'active',
50+
},
51+
],
52+
},
53+
};
54+
55+
const ast = builder.build(query);
56+
57+
expect(ast.where).toBeDefined();
58+
expect(ast.where?.type).toBe('where');
59+
expect(ast.where?.condition.type).toBe('operator');
60+
});
61+
62+
it('should build query with ORDER BY', () => {
63+
const query: QuerySchema = {
64+
object: 'users',
65+
fields: ['id', 'name'],
66+
sort: [
67+
{ field: 'created_at', order: 'desc' },
68+
{ field: 'name', order: 'asc' },
69+
],
70+
};
71+
72+
const ast = builder.build(query);
73+
74+
expect(ast.order_by).toBeDefined();
75+
expect(ast.order_by?.fields).toHaveLength(2);
76+
expect(ast.order_by?.fields[0].direction).toBe('desc');
77+
});
78+
79+
it('should build query with LIMIT and OFFSET', () => {
80+
const query: QuerySchema = {
81+
object: 'users',
82+
fields: ['id', 'name'],
83+
limit: 10,
84+
offset: 20,
85+
};
86+
87+
const ast = builder.build(query);
88+
89+
expect(ast.limit).toBeDefined();
90+
expect(ast.limit?.value).toBe(10);
91+
expect(ast.offset).toBeDefined();
92+
expect(ast.offset?.value).toBe(20);
93+
});
94+
});
95+
96+
describe('Advanced Query Building', () => {
97+
it('should build query with JOIN', () => {
98+
const query: QuerySchema = {
99+
object: 'users',
100+
fields: ['id', 'name', 'orders.total'],
101+
joins: [
102+
{
103+
type: 'left',
104+
object: 'orders',
105+
on: {
106+
local_field: 'id',
107+
foreign_field: 'user_id',
108+
},
109+
},
110+
],
111+
};
112+
113+
const ast = builder.build(query);
114+
115+
expect(ast.joins).toBeDefined();
116+
expect(ast.joins).toHaveLength(1);
117+
expect(ast.joins?.[0].join_type).toBe('left');
118+
expect(ast.joins?.[0].table).toBe('orders');
119+
});
120+
121+
it('should build query with aggregations', () => {
122+
const query: QuerySchema = {
123+
object: 'orders',
124+
aggregations: [
125+
{
126+
function: 'count',
127+
alias: 'total_count',
128+
},
129+
{
130+
function: 'sum',
131+
field: 'amount',
132+
alias: 'total_amount',
133+
},
134+
],
135+
};
136+
137+
const ast = builder.build(query);
138+
139+
expect(ast.select.fields).toHaveLength(2);
140+
expect(ast.select.fields[0]).toMatchObject({
141+
type: 'aggregate',
142+
function: 'count',
143+
alias: 'total_count',
144+
});
145+
});
146+
147+
it('should build query with GROUP BY', () => {
148+
const query: QuerySchema = {
149+
object: 'orders',
150+
fields: ['user_id'],
151+
group_by: ['user_id'],
152+
aggregations: [
153+
{
154+
function: 'count',
155+
alias: 'order_count',
156+
},
157+
],
158+
};
159+
160+
const ast = builder.build(query);
161+
162+
expect(ast.group_by).toBeDefined();
163+
expect(ast.group_by?.fields).toHaveLength(1);
164+
expect(ast.group_by?.fields[0]).toMatchObject({
165+
type: 'field',
166+
name: 'user_id',
167+
});
168+
});
169+
});
170+
171+
describe('Complex Filters', () => {
172+
it('should build query with nested AND/OR filters', () => {
173+
const query: QuerySchema = {
174+
object: 'users',
175+
filter: {
176+
operator: 'and',
177+
conditions: [
178+
{
179+
field: 'status',
180+
operator: 'equals',
181+
value: 'active',
182+
},
183+
],
184+
groups: [
185+
{
186+
operator: 'or',
187+
conditions: [
188+
{
189+
field: 'role',
190+
operator: 'equals',
191+
value: 'admin',
192+
},
193+
{
194+
field: 'role',
195+
operator: 'equals',
196+
value: 'moderator',
197+
},
198+
],
199+
},
200+
],
201+
},
202+
};
203+
204+
const ast = builder.build(query);
205+
206+
expect(ast.where).toBeDefined();
207+
expect(ast.where?.condition.operator).toBe('and');
208+
expect(ast.where?.condition.operands.length).toBeGreaterThan(0);
209+
});
210+
});
211+
});

packages/core/src/query/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* @object-ui/core - Query Module
3+
*
4+
* Phase 3.3: Query AST builder and utilities
5+
*/
6+
7+
export * from './query-ast';

0 commit comments

Comments
 (0)