Skip to content

Commit 5268475

Browse files
committed
feat: value type for table rows
1 parent 0e616bb commit 5268475

9 files changed

Lines changed: 122 additions & 1 deletion

File tree

libs/execution/src/lib/types/value-types/internal-representation-parsing.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ class InternalRepresentationParserVisitor extends ValueTypeVisitor<
124124
return new InvalidValue(`Cannot parse collections into internal values`);
125125
}
126126

127+
override visitTableRow(): InvalidValue {
128+
return new InvalidValue(`Cannot parse table rows into internal values`);
129+
}
130+
127131
override visitConstraint(): InvalidValue {
128132
return new InvalidValue(`Cannot parse constraints into internal values`);
129133
}

libs/execution/src/lib/types/value-types/value-representation-validity.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { strict as assert } from 'assert';
77

88
import {
9+
type TableRowValueType,
910
type AtomicValueType,
1011
type BooleanValuetype,
1112
type CellRangeValuetype,
@@ -130,6 +131,10 @@ class ValueRepresentationValidityVisitor extends ValueTypeVisitor<boolean> {
130131
return this.isValidForPrimitiveValuetype(valueType);
131132
}
132133

134+
override visitTableRow(valueType: TableRowValueType): boolean {
135+
return this.isValidForPrimitiveValuetype(valueType);
136+
}
137+
133138
override visitTransform(valueType: TransformValuetype): boolean {
134139
return this.isValidForPrimitiveValuetype(valueType);
135140
}

libs/execution/src/lib/types/value-types/visitors/sql-column-type-visitor.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ export class SQLColumnTypeVisitor extends ValueTypeVisitor<string> {
7676
);
7777
}
7878

79+
override visitTableRow(): string {
80+
throw new Error(
81+
'No visit implementation given for table rows. Cannot be the type of a column.',
82+
);
83+
}
84+
7985
override visitTransform(): string {
8086
throw new Error(
8187
'No visit implementation given for transforms. Cannot be the type of a column.',

libs/execution/src/lib/types/value-types/visitors/sql-value-representation-visitor.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ export class SQLValueRepresentationVisitor extends ValueTypeVisitor<
130130
);
131131
}
132132

133+
override visitTableRow(): (
134+
value: InternalValidValueRepresentation | InternalErrorValueRepresentation,
135+
) => string {
136+
throw new Error(
137+
'No visit implementation given for table rows. Cannot be the type of a column.',
138+
);
139+
}
140+
133141
override visitTransform(): (
134142
value: InternalValidValueRepresentation | InternalErrorValueRepresentation,
135143
) => string {

libs/language-server/src/lib/ast/expressions/type-inference.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
isNumericLiteral,
3030
isReferenceLiteral,
3131
isRegexLiteral,
32+
isTableRowLiteral,
3233
isTernaryExpression,
3334
isTextLiteral,
3435
isTransformDefinition,
@@ -39,10 +40,12 @@ import {
3940
isValueTypeProperty,
4041
isValuetypeAssignmentLiteral,
4142
isValuetypeDefinition,
43+
type TableRowLiteral,
4244
} from '../generated/ast';
4345
import { getNextAstNodeContainer } from '../model-util';
4446
import {
4547
isAtomicValueType,
48+
type TableRowValueType,
4649
type ValueType,
4750
type ValueTypeProvider,
4851
type WrapperFactoryProvider,
@@ -186,6 +189,13 @@ function inferTypeFromExpressionLiteral(
186189
valueTypeProvider,
187190
wrapperFactories,
188191
);
192+
} else if (isTableRowLiteral(expression)) {
193+
return inferTableRowType(
194+
expression,
195+
validationContext,
196+
valueTypeProvider,
197+
wrapperFactories,
198+
);
189199
} else if (isErrorLiteral(expression)) {
190200
return undefined;
191201
}
@@ -297,6 +307,28 @@ function inferCollectionElementTypes(
297307
return undefined;
298308
}
299309

310+
function inferTableRowType(
311+
tableRow: TableRowLiteral,
312+
validationContext: ValidationContext,
313+
valueTypeProvider: ValueTypeProvider,
314+
wrapperFactories: WrapperFactoryProvider,
315+
): TableRowValueType | undefined {
316+
const cellValueTypes = new Map<string, ValueType>();
317+
for (const cell of tableRow.cells) {
318+
const cellValueType = inferExpressionType(
319+
cell.expression,
320+
validationContext,
321+
valueTypeProvider,
322+
wrapperFactories,
323+
);
324+
if (cellValueType === undefined) {
325+
return undefined;
326+
}
327+
cellValueTypes.set(cell.name, cellValueType);
328+
}
329+
return valueTypeProvider.createTableRowValueTypeOf(cellValueTypes);
330+
}
331+
300332
function inferTypeFromValueKeyword(
301333
expression: ValueKeywordLiteral,
302334
validationContext: ValidationContext,

libs/language-server/src/lib/ast/wrappers/value-type/primitive/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ export { type ConstraintValuetype } from './constraint-value-type';
1818
export { type DecimalValuetype } from './decimal-value-type';
1919
export { type IntegerValuetype } from './integer-value-type';
2020
export { type RegexValuetype } from './regex-value-type';
21+
export { type TableRowValueType } from './table-row-value-type';
2122
export { type TextValuetype } from './text-value-type';
23+
export { type TransformValuetype } from './transform-value-type';
2224
export { type ValuetypeAssignmentValuetype } from './value-type-assignment-value-type';
2325
export { type ValuetypeDefinitionValuetype } from './value-type-definition-value-type';
24-
export { type TransformValuetype } from './transform-value-type';
2526

2627
export {
2728
ValueTypeProvider,

libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type-provider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { TextValuetype } from './text-value-type';
1818
import { TransformValuetype } from './transform-value-type';
1919
import { ValuetypeAssignmentValuetype } from './value-type-assignment-value-type';
2020
import { ValuetypeDefinitionValuetype } from './value-type-definition-value-type';
21+
import { TableRowValueType } from './table-row-value-type';
2122

2223
/**
2324
* Should be created as singleton due to the equality comparison of primitive value types.
@@ -32,6 +33,10 @@ export class ValueTypeProvider {
3233
): CollectionValueType<I> {
3334
return new CollectionValueType(input);
3435
}
36+
37+
createTableRowValueTypeOf(input: Map<string, ValueType>): TableRowValueType {
38+
return new TableRowValueType(input);
39+
}
3540
}
3641

3742
export class PrimitiveValueTypeProvider {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// SPDX-FileCopyrightText: 2026 Friedrich-Alexander-Universitat Erlangen-Nurnberg
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-only
4+
5+
import {
6+
type TableRow,
7+
type InternalValidValueRepresentation,
8+
} from '../../../expressions/internal-value-representation';
9+
import { type ValueType, type ValueTypeVisitor } from '../value-type';
10+
11+
import { PrimitiveValueType } from './primitive-value-type';
12+
import { TABLEROW_TYPEGUARD } from '../../../expressions';
13+
14+
export class TableRowValueType extends PrimitiveValueType<TableRow> {
15+
constructor(private schema: Map<string, ValueType>) {
16+
super();
17+
}
18+
19+
acceptVisitor<R>(visitor: ValueTypeVisitor<R>): R {
20+
return visitor.visitTableRow(this);
21+
}
22+
23+
override isAllowedAsRuntimeParameter(): boolean {
24+
return false;
25+
}
26+
27+
override getName(): 'TableRow' {
28+
return 'TableRow';
29+
}
30+
31+
private equalSchema(otherSchema: Map<string, ValueType>): boolean {
32+
if (this.schema.size !== otherSchema.size) {
33+
return false;
34+
}
35+
for (const [columnName, cellValue] of this.schema) {
36+
const otherCellValue = otherSchema.get(columnName);
37+
if (cellValue !== otherCellValue) {
38+
return false;
39+
}
40+
if (otherCellValue === undefined && !otherSchema.has(columnName)) {
41+
return false;
42+
}
43+
}
44+
return true;
45+
}
46+
47+
override equals(target: ValueType): boolean {
48+
return (
49+
target instanceof TableRowValueType && this.equalSchema(target.schema)
50+
);
51+
}
52+
53+
override isInternalValidValueRepresentation(
54+
operandValue: InternalValidValueRepresentation,
55+
): operandValue is TableRow {
56+
return TABLEROW_TYPEGUARD(operandValue);
57+
}
58+
}

libs/language-server/src/lib/ast/wrappers/value-type/value-type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
type BooleanValuetype,
1414
type CellRangeValuetype,
1515
type CollectionValueType,
16+
type TableRowValueType,
1617
type ConstraintValuetype,
1718
type DecimalValuetype,
1819
type EmptyCollectionValueType,
@@ -90,6 +91,7 @@ export abstract class ValueTypeVisitor<R = unknown> {
9091
abstract visitCollection(
9192
valueType: CollectionValueType | EmptyCollectionValueType,
9293
): R;
94+
abstract visitTableRow(valueType: TableRowValueType): R;
9395
abstract visitTransform(valueType: TransformValuetype): R;
9496

9597
abstract visitAtomicValueType(valueType: AtomicValueType): R;

0 commit comments

Comments
 (0)