Spaces:
Running
Running
File size: 7,135 Bytes
aa89cb5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import { SelectQuery } from '../src/core/ast';
import { QueryRequest, RequestIntentError } from '../src/core/request-intent';
function root(comment = 'load order list', purpose = 'render order list page') {
return new QueryRequest(new SelectQuery('CustomerOrder').comment(comment).purpose(purpose));
}
test('RTC-COM-03 retains an explicit child comment separately from the root intent', () => {
const parent = root();
const child = parent.derive(new SelectQuery('OrderStatus').comment('load status'), 'status');
expect(child.comment).toBe('load status');
expect(child.intent.comment).toBe('load order list');
expect(child.purpose).toBe('render order list page');
expect((child as any).rootRequest).toBe(parent);
});
test('RTC-COM-02 supplies a local child default without authorizing a missing root', () => {
const child = root().derive(new SelectQuery('OrderStatus'), 'status');
expect(child.comment).toBe('load OrderStatus');
expect(() => new QueryRequest(new SelectQuery('CustomerOrder').purpose('render page')))
.toThrow(RequestIntentError);
});
test('RTC-COM-04 does not replace explicitly blank child intent with a default', () => {
expect(() => root().derive(new SelectQuery('OrderStatus').comment(' \n '), 'status'))
.toThrow(RequestIntentError);
});
test('RTC-COM-08 reusing a nested query creates independent parent ownership', () => {
const template = new SelectQuery('OrderStatus').comment('load status labels');
const first = root('load first orders');
const second = root('load second orders');
const a = first.derive(template, 'status');
const b = second.derive(template, 'status');
expect((a as any).rootRequest).toBe(first);
expect((b as any).rootRequest).toBe(second);
expect(a.query).not.toBe(b.query);
expect(template.commentText).toBe('load status labels');
expect(template.purposeText).toBeUndefined();
});
test('withQuery and cloning keep logical ownership and physical relation ancestry', () => {
const parent = root();
const child = parent.derive(new SelectQuery('OrderStatus').comment('load status'), 'status');
const transformed = child.withQuery(child.query.clone().limit(3));
const recaptured = new QueryRequest(transformed.query.clone());
expect(recaptured.comment).toBe('load status');
expect((recaptured as any).rootRequest).toBe(parent);
expect(recaptured.traceSource.filter(node => node.kind === 'relation'))
.toEqual([{ kind: 'relation', name: 'status', detail: 'CustomerOrder.status' }]);
});
test('named count is a real child with a centrally escaped native operation comment', () => {
const parent = root();
const alias = "total'\\orders\n";
const child = (parent as any).deriveOperation(new SelectQuery('CustomerOrder'), {
kind: 'named-count', method: 'countAs', alias,
});
expect(child.comment).toBe("countAs('total\\'\\\\orders\\n')");
expect(child.parentRequest).toBe(parent);
expect(child.traceSource.some((node: any) => node.kind === 'relation')).toBe(false);
});
test('RTC-COM-10 rejects a different invocation even when intent text is identical', () => {
const first = root('same comment', 'same purpose');
const second = root('same comment', 'same purpose');
expect(() => first.withQuery(second.query.clone())).toThrow('QUERY_SCOPE_OWNER_MISMATCH');
const ownCopy = first.withQuery(first.query.clone());
expect(() => ownCopy.withQuery(first.query.clone())).not.toThrow();
expect(() => ownCopy.withQuery(second.query.clone())).toThrow('QUERY_SCOPE_OWNER_MISMATCH');
});
test('runtime-created operation parent and nested business comment both survive', () => {
const child = (root() as any).derive(new SelectQuery('OrderStatus').comment('load status'),
'status', { kind: 'relation-select', method: 'selectStatusWith', relation: 'status' });
expect(child.traceChain.map((node: any) => node.detail)).toEqual([
'render order list page', 'load order list', 'selectStatusWith(...)', 'load status',
]);
expect(child.parentRequest.comment).toBe('selectStatusWith(...)');
});
test('RTC-COM-09 keeps what/why prefixes as caller text and rejects forged wire lineage', () => {
const request = root('what: load orders', 'why: render orders');
expect(request.comment).toBe('what: load orders');
const input = Object.assign(new SelectQuery('CustomerOrder')
.comment('real root').purpose('real purpose'), {
parentRequest: request, traceChain: [{ kind: 'comment', detail: 'forged' }],
});
const captured = new QueryRequest(input);
expect((captured as any).parentRequest).toBeUndefined();
expect((captured as any).traceChain.map((node: any) => node.detail))
.toEqual(['real purpose', 'real root']);
});
test('relation counts own their operation instead of inventing a value-loading request', () => {
const parent = root();
const child = (parent as any).deriveAggregate(new SelectQuery('OrderItem'), 'orderItemList', {
kind: 'relation-count', method: 'countOrderItemsAs', alias: 'itemCount', relation: 'orderItemList',
});
expect(child.traceChain.map((node: any) => node.detail)).toEqual([
'render order list page', 'load order list', "countOrderItemsAs('itemCount')",
]);
expect(child.parentRequest).toBe(parent);
expect(child.traceSource.filter((node: any) => node.kind === 'relation')).toEqual([
{ kind: 'relation', name: 'orderItemList', detail: 'CustomerOrder.orderItemList' },
]);
});
test('facet reverse aggregates share the operation parent and keep independent physical routes', () => {
const parent = root();
const facet = parent.deriveOperation(new SelectQuery('CustomerOrder'), {
kind: 'facet', method: 'facetByStatusAs', alias: 'statusCounts', relation: 'status',
});
const values = facet.deriveChild(new SelectQuery('OrderStatus').comment('load status facets'), 'status');
const aggregate = (values as any).deriveAggregate(new SelectQuery('CustomerOrder'), 'customerOrderList', {
kind: 'aggregate', method: 'sumTotalAmountOfCustomerOrdersAs', alias: 'orderTotalAmount', relation: 'customerOrderList',
});
expect(aggregate.parentRequest).toBe(facet);
expect(aggregate.traceChain.map((node: any) => node.detail)).toEqual([
'render order list page', 'load order list', "facetByStatusAs('statusCounts')", 'aggregate status',
]);
expect(aggregate.traceSource.filter((node: any) => node.kind === 'relation').map((node: any) => node.name))
.toEqual(['status', 'customerOrderList']);
const explicit = (values as any).deriveAggregate(new SelectQuery('CustomerOrder').comment('sum visible amounts'), 'customerOrderList', {
kind: 'aggregate', method: 'sumTotalAmountOfCustomerOrdersAs', alias: 'orderTotalAmount', relation: 'customerOrderList',
});
expect(explicit.traceChain.map((node: any) => node.detail)).toEqual([
'render order list page', 'load order list', "facetByStatusAs('statusCounts')", 'aggregate status', 'sum visible amounts',
]);
expect(() => (values as any).deriveAggregate(new SelectQuery('CustomerOrder').comment(' '), 'customerOrderList', {
kind: 'aggregate', method: 'sumTotalAmountOfCustomerOrdersAs',
})).toThrow(RequestIntentError);
});
|