@@ -22,6 +22,8 @@ import {
2222 type IOTypeImplementation ,
2323 type IoTypeVisitor ,
2424} from './io-type-implementation' ;
25+ import { ConstraintExecutor } from '../../constraints' ;
26+ import { type ExecutionContext } from '../../execution-context' ;
2527
2628export interface TableColumn <
2729 T extends InternalValidValueRepresentation = InternalValidValueRepresentation ,
@@ -30,7 +32,7 @@ export interface TableColumn<
3032 valueType : ValueType ;
3133}
3234
33- export type TableRow = Record <
35+ export type TableRow = Map <
3436 string ,
3537 InternalValidValueRepresentation | InternalErrorValueRepresentation
3638> ;
@@ -42,12 +44,14 @@ export type TableRow = Record<
4244export class Table implements IOTypeImplementation < IOType . TABLE > {
4345 public readonly ioType = IOType . TABLE ;
4446
45- private numberOfRows = 0 ;
46-
47- private columns = new Map < string , TableColumn > ( ) ;
48-
49- public constructor ( numberOfRows = 0 ) {
50- this . numberOfRows = numberOfRows ;
47+ public constructor (
48+ private numberOfRows : number ,
49+ private columns : Map < string , TableColumn > ,
50+ private constraints : ConstraintExecutor [ ] ,
51+ ) {
52+ assert ( this . numberOfRows !== undefined ) ;
53+ assert ( this . columns !== undefined ) ;
54+ assert ( this . constraints !== undefined ) ;
5155 }
5256
5357 addColumn ( name : string , column : TableColumn ) : void {
@@ -60,32 +64,44 @@ export class Table implements IOTypeImplementation<IOType.TABLE> {
6064 * NOTE: This method will only add the row if the table has at least one column!
6165 * @param row data of this row for each column
6266 */
63- addRow ( row : TableRow ) : void {
64- const rowLength = Object . keys ( row ) . length ;
67+ addRow (
68+ row : Record <
69+ string ,
70+ InternalValidValueRepresentation | InternalErrorValueRepresentation
71+ > ,
72+ ) : void ;
73+ addRow ( row : TableRow ) : void ;
74+ addRow (
75+ row :
76+ | TableRow
77+ | Record <
78+ string ,
79+ InternalValidValueRepresentation | InternalErrorValueRepresentation
80+ > ,
81+ ) : void {
82+ const rowLength = row instanceof Map ? row . size : Object . keys ( row ) . length ;
6583 assert (
6684 rowLength === this . columns . size ,
6785 `Added row has the wrong dimension (expected: ${ this . columns . size } , actual: ${ rowLength } )` ,
6886 ) ;
69- if ( rowLength === 0 ) {
70- return ;
87+
88+ if ( rowLength > 0 ) {
89+ this . numberOfRows ++ ;
7190 }
72- assert (
73- Object . keys ( row ) . every ( ( x ) => this . hasColumn ( x ) ) ,
74- 'Added row does not fit the columns in the table' ,
75- ) ;
7691
77- Object . entries ( row ) . forEach ( ( [ columnName , value ] ) => {
92+ const rowValues =
93+ row instanceof Map ? [ ...row . entries ( ) ] : Object . entries ( row ) ;
94+
95+ for ( const [ columnName , cellValue ] of rowValues ) {
7896 const column = this . columns . get ( columnName ) ;
79- assert ( column !== undefined ) ;
97+ assert ( column !== undefined , 'All added rows fit columns in the table' ) ;
8098
8199 assert (
82- ERROR_TYPEGUARD ( value ) ||
83- column . valueType . isInternalValidValueRepresentation ( value ) ,
100+ ERROR_TYPEGUARD ( cellValue ) ||
101+ column . valueType . isInternalValidValueRepresentation ( cellValue ) ,
84102 ) ;
85- column . values . push ( value ) ;
86- } ) ;
87-
88- this . numberOfRows ++ ;
103+ column . values . push ( cellValue ) ;
104+ }
89105 }
90106
91107 getNumberOfRows ( ) : number {
@@ -108,12 +124,7 @@ export class Table implements IOTypeImplementation<IOType.TABLE> {
108124 return this . columns . get ( name ) ;
109125 }
110126
111- getRow (
112- rowId : number ,
113- ) : Map <
114- string ,
115- InternalValidValueRepresentation | InternalErrorValueRepresentation
116- > {
127+ getRow ( rowId : number ) : TableRow {
117128 const numberOfRows = this . getNumberOfRows ( ) ;
118129 if ( rowId >= numberOfRows ) {
119130 throw new Error (
@@ -133,6 +144,26 @@ export class Table implements IOTypeImplementation<IOType.TABLE> {
133144 return row ;
134145 }
135146
147+ findUnfullfilledRows (
148+ executionContext : ExecutionContext ,
149+ onInvalidRow ?: ( rowIndex : number , row : TableRow ) => void ,
150+ ) : void {
151+ for ( let rowIdx = 0 ; rowIdx < this . numberOfRows ; rowIdx ++ ) {
152+ const row = this . getRow ( rowIdx ) ;
153+
154+ const allConstraintsFulfilled = this . constraints . every ( ( constraint ) =>
155+ constraint . isValid ( row , executionContext ) ,
156+ ) ;
157+ if ( allConstraintsFulfilled ) {
158+ continue ;
159+ }
160+
161+ if ( onInvalidRow !== undefined ) {
162+ onInvalidRow ( rowIdx , row ) ;
163+ }
164+ }
165+ }
166+
136167 static generateDropTableStatement ( tableName : string ) : string {
137168 return `DROP TABLE IF EXISTS "${ tableName } ";` ;
138169 }
@@ -186,16 +217,19 @@ export class Table implements IOTypeImplementation<IOType.TABLE> {
186217 }
187218
188219 clone ( ) : Table {
189- const cloned = new Table ( ) ;
190- cloned . numberOfRows = this . numberOfRows ;
191- [ ...this . columns . entries ( ) ] . forEach ( ( [ columnName , column ] ) => {
192- cloned . addColumn ( columnName , {
220+ const copiedColumns = new Map < string , TableColumn > ( ) ;
221+ [ ...this . columns . entries ( ) ] . map ( ( [ columnName , column ] ) => {
222+ copiedColumns . set ( columnName , {
193223 values : cloneInternalValue ( column . values ) ,
194224 valueType : column . valueType ,
195225 } ) ;
196226 } ) ;
197227
198- return cloned ;
228+ const copiedConstraints = this . constraints . map (
229+ ( constraint ) => new ConstraintExecutor ( constraint . astNode ) ,
230+ ) ;
231+
232+ return new Table ( this . numberOfRows , copiedColumns , copiedConstraints ) ;
199233 }
200234
201235 acceptVisitor < R > ( visitor : IoTypeVisitor < R > ) : R {
0 commit comments