Skip to content

Commit

Permalink
feat(type-evaluation): add support for Pos and Neg nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
sgulseth committed Mar 26, 2024
1 parent 7581bfc commit bef4ad5
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 2 deletions.
28 changes: 26 additions & 2 deletions src/typeEvaluator/typeEvaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import type {
FilterNode,
FlatMapNode,
MapNode,
NegNode,
NotNode,
ObjectNode,
OpCallNode,
ParentNode,
PosNode,
ProjectionNode,
SelectNode,
SliceNode,
Expand Down Expand Up @@ -583,6 +585,24 @@ function handleNotNode(node: NotNode, scope: Scope): TypeNode {
return {type: 'boolean'}
}

function handleNegNode(node: NegNode, scope: Scope): NumberTypeNode | NullTypeNode {
const base = walk({node: node.base, scope})
if (base.type !== 'number') {
return {type: 'null'}
}
if (base.value !== undefined) {
return {type: 'number', value: -base.value}
}
return base
}
function handlePosNode(node: PosNode, scope: Scope): NumberTypeNode | NullTypeNode {
const base = walk({node: node.base, scope})
if (base.type !== 'number') {
return {type: 'null'}
}
return base
}

function handleEverythingNode(_: EverythingNode, scope: Scope): TypeNode {
return {
type: 'array',
Expand Down Expand Up @@ -713,11 +733,15 @@ export function walk({node, scope}: {node: ExprNode; scope: Scope}): TypeNode {
case 'Slice': {
return handleSlice(node, scope)
}
case 'Neg': {
return handleNegNode(node, scope)
}
case 'Pos': {
return handlePosNode(node, scope)
}
// everything else
case 'Asc':
case 'Desc':
case 'Neg':
case 'Pos':
case 'Context':
case 'Tuple':
case 'Selector':
Expand Down
76 changes: 76 additions & 0 deletions test/typeEvaluate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,82 @@ t.test('this operator', (t) => {
t.end()
})

t.test('neg node', (t) => {
const query = `*[_type == "author"] {
"minusAge": -age,
"notNumber": -name,
"constant": -(3 + 4),
}`
const ast = parse(query)
const res = typeEvaluate(ast, schemas)
t.strictSame(res, {
type: 'array',
of: {
type: 'object',
attributes: {
minusAge: {
type: 'objectAttribute',
value: {
type: 'number',
},
},
notNumber: {
type: 'objectAttribute',
value: {
type: 'null',
},
},
constant: {
type: 'objectAttribute',
value: {
type: 'number',
value: -7,
},
},
},
},
})
t.end()
})

t.test('pos node', (t) => {
const query = `*[_type == "author"] {
"age": +age,
"notNumber": +name,
"constant": +(3 + 4),
}`
const ast = parse(query)
const res = typeEvaluate(ast, schemas)
t.strictSame(res, {
type: 'array',
of: {
type: 'object',
attributes: {
age: {
type: 'objectAttribute',
value: {
type: 'number',
},
},
notNumber: {
type: 'objectAttribute',
value: {
type: 'null',
},
},
constant: {
type: 'objectAttribute',
value: {
type: 'number',
value: 7,
},
},
},
},
})
t.end()
})

function findSchemaType(name: string): TypeNode {
const type = schemas.find((s) => s.name === name)
if (!type) {
Expand Down

0 comments on commit bef4ad5

Please sign in to comment.