33
44import { Table } from './Table.js';
55import { BindData } from './Sql.js';
6- import { DerivedTable, TableFields, TableField, CalculatedField, SqlServerFunctions } from './Views.js';
6+ import { DerivedTable, TableFields, TableField, CalculatedField, SqlServerFunctions, FieldComparisons } from './Views.js';
77export { JoinTables, JoinTablesRecordIds };
88// *** DEBUG END ***/
99
@@ -74,19 +74,20 @@ class JoinTables { // skipcq: JS-0128
7474 /** @property {DerivedTable } - result table after tables are joined */
7575 this . derivedTable = new DerivedTable ( ) ;
7676
77- ast . JOIN . forEach ( joinTable => this . joinNextTable ( joinTable , ast . FROM . table . toUpperCase ( ) ) ) ;
77+ ast . JOIN . forEach ( joinTable => this . joinNextTable ( joinTable , ast . FROM . table . toUpperCase ( ) , ast . FROM . as ) ) ;
7878 }
7979
8080 /**
8181 * Updates derived table with join to new table.
8282 * @param {Object } astJoin
8383 * @param {String } leftTableName
84+ * @param {String } leftAlias
8485 */
85- joinNextTable ( astJoin , leftTableName ) {
86+ joinNextTable ( astJoin , leftTableName , leftAlias ) {
8687 const recIds = this . joinCondition ( astJoin , leftTableName ) ;
87-
8888 const joinFieldsInfo = this . joinTableIDs . getJoinFieldsInfo ( ) ;
89- this . derivedTable = JoinTables . joinTables ( joinFieldsInfo , astJoin , recIds ) ;
89+
90+ this . derivedTable = JoinTables . joinTables ( joinFieldsInfo , astJoin , recIds , leftAlias ) ;
9091
9192 // Field locations have changed to the derived table, so update our
9293 // virtual field list with proper settings.
@@ -190,7 +191,7 @@ class JoinTables { // skipcq: JS-0128
190191 for ( let i = 0 ; i < recIds [ 0 ] . length ; i ++ ) {
191192 let temp = [ ] ;
192193
193- recIds . forEach ( rec => { temp = temp . concat ( rec [ i ] ) } ) ;
194+ recIds . forEach ( rec => { temp = temp . concat ( rec [ i ] ) } ) ;
194195
195196 if ( typeof temp [ 0 ] !== 'undefined' ) {
196197 result [ i ] = Array . from ( new Set ( temp ) ) ;
@@ -225,9 +226,10 @@ class JoinTables { // skipcq: JS-0128
225226 * @param {LeftRightJoinFields } leftRightFieldInfo - left table field of join
226227 * @param {Object } joinTable - AST that contains join type.
227228 * @param {MatchingJoinRecordIDs } recIds
229+ * @param {String } leftAlias
228230 * @returns {DerivedTable } - new derived table after join of left and right tables.
229231 */
230- static joinTables ( leftRightFieldInfo , joinTable , recIds ) {
232+ static joinTables ( leftRightFieldInfo , joinTable , recIds , leftAlias ) {
231233 let derivedTable = null ;
232234 let rightDerivedTable = null ;
233235
@@ -238,6 +240,7 @@ class JoinTables { // skipcq: JS-0128
238240 . setRightField ( leftRightFieldInfo . rightSideInfo . fieldInfo )
239241 . setLeftRecords ( recIds . leftJoinRecordIDs )
240242 . setIsOuterJoin ( true )
243+ . setJoinTableAlias ( leftAlias , joinTable . as )
241244 . createTable ( ) ;
242245 break ;
243246
@@ -247,6 +250,7 @@ class JoinTables { // skipcq: JS-0128
247250 . setRightField ( leftRightFieldInfo . rightSideInfo . fieldInfo )
248251 . setLeftRecords ( recIds . leftJoinRecordIDs )
249252 . setIsOuterJoin ( false )
253+ . setJoinTableAlias ( leftAlias , joinTable . as )
250254 . createTable ( ) ;
251255 break ;
252256
@@ -256,6 +260,7 @@ class JoinTables { // skipcq: JS-0128
256260 . setRightField ( leftRightFieldInfo . leftSideInfo . fieldInfo )
257261 . setLeftRecords ( recIds . leftJoinRecordIDs )
258262 . setIsOuterJoin ( true )
263+ . setJoinTableAlias ( leftAlias , joinTable . as )
259264 . createTable ( ) ;
260265
261266 break ;
@@ -266,13 +271,15 @@ class JoinTables { // skipcq: JS-0128
266271 . setRightField ( leftRightFieldInfo . rightSideInfo . fieldInfo )
267272 . setLeftRecords ( recIds . leftJoinRecordIDs )
268273 . setIsOuterJoin ( true )
274+ . setJoinTableAlias ( joinTable . as )
269275 . createTable ( ) ;
270276
271277 rightDerivedTable = new DerivedTable ( )
272278 . setLeftField ( leftRightFieldInfo . rightSideInfo . fieldInfo )
273279 . setRightField ( leftRightFieldInfo . leftSideInfo . fieldInfo )
274280 . setLeftRecords ( recIds . rightJoinRecordIDs )
275281 . setIsOuterJoin ( true )
282+ . setJoinTableAlias ( joinTable . as )
276283 . createTable ( ) ;
277284
278285 derivedTable . tableInfo . concat ( rightDerivedTable . tableInfo ) ; // skipcq: JS-D008
@@ -413,6 +420,7 @@ class JoinTablesRecordIds {
413420 * @typedef {Object } LeftRightJoinFields
414421 * @property {JoinSideInfo } leftSideInfo
415422 * @property {JoinSideInfo } rightSideInfo
423+ * @property {String } operator
416424 *
417425 */
418426
@@ -435,9 +443,11 @@ class JoinTablesRecordIds {
435443
436444 const left = typeof astJoin . cond === 'undefined' ? astJoin . left : astJoin . cond . left ;
437445 const right = typeof astJoin . cond === 'undefined' ? astJoin . right : astJoin . cond . right ;
446+ const operator = typeof astJoin . cond === 'undefined' ? astJoin . operator : astJoin . cond . operator ;
438447
439448 leftFieldInfo = this . getTableInfoFromCalculatedField ( left ) ;
440449 rightFieldInfo = this . getTableInfoFromCalculatedField ( right ) ;
450+ const isSelfJoin = leftFieldInfo . originalTable === rightFieldInfo . originalTable ;
441451
442452 /** @type {JoinSideInfo } */
443453 const leftSideInfo = {
@@ -451,14 +461,15 @@ class JoinTablesRecordIds {
451461 }
452462
453463 // joinTable.table is the RIGHT table, so switch if equal to condition left.
454- if ( typeof leftFieldInfo !== 'undefined' && this . rightTableName === leftFieldInfo . originalTable ) {
464+ if ( typeof leftFieldInfo !== 'undefined' && this . rightTableName === leftFieldInfo . originalTable && ! isSelfJoin ) {
455465 return {
456466 leftSideInfo : rightSideInfo ,
457- rightSideInfo : leftSideInfo
467+ rightSideInfo : leftSideInfo ,
468+ operator : operator
458469 } ;
459470 }
460471
461- return { leftSideInfo, rightSideInfo } ;
472+ return { leftSideInfo, rightSideInfo, operator } ;
462473 }
463474
464475 /**
@@ -568,7 +579,7 @@ class JoinTablesRecordIds {
568579 }
569580
570581 /**
571- * Returns array of each matching record ID from right table for every record in left table.
582+ * Returns array of each CONDITIONAL matching record ID from right table for every record in left table.
572583 * If the right table entry could NOT be found, -1 is set for that record index.
573584 * @param {JoinSideInfo } leftField - left table field
574585 * @param {JoinSideInfo } rightField - right table field
@@ -581,23 +592,37 @@ class JoinTablesRecordIds {
581592 // First record is the column title.
582593 leftRecordsIDs . push ( [ 0 ] ) ;
583594
595+ const conditionFunction = FieldComparisons . getComparisonFunction ( this . joinFields . operator ) ;
584596 const leftTableData = leftField . fieldInfo . tableInfo . tableData ;
585-
586- // Map the RIGHT JOIN key to record numbers.
587597 const keyFieldMap = this . createKeyFieldRecordMap ( rightField ) ;
588598
589599 for ( let leftTableRecordNum = 1 ; leftTableRecordNum < leftTableData . length ; leftTableRecordNum ++ ) {
590600 const keyMasterJoinField = this . getJoinColumnData ( leftField , leftTableRecordNum ) ;
601+ let rightRecordIDs = [ ] ;
602+
603+ if ( this . joinFields . operator === '=' ) {
604+ // "=" - special case.
605+ // Most common case AND far fewer comparisons - especially if right table is large.
606+ rightRecordIDs = keyFieldMap . has ( keyMasterJoinField ) ? keyFieldMap . get ( keyMasterJoinField ) : [ ] ;
607+ }
608+ else {
609+ // @ts -ignore
610+ for ( const [ key , data ] of keyFieldMap ) {
611+ if ( conditionFunction ( keyMasterJoinField , key ) ) {
612+ rightRecordIDs . unshift ( ...data ) ;
613+ }
614+ }
615+ }
591616
592617 // For the current LEFT TABLE record, record the linking RIGHT TABLE records.
593- if ( ! keyFieldMap . has ( keyMasterJoinField ) ) {
618+ if ( rightRecordIDs . length === 0 ) {
594619 if ( type !== "inner" ) {
595620 leftRecordsIDs [ leftTableRecordNum ] = [ - 1 ] ;
596621 }
597622 }
598623 else if ( type !== "outer" ) {
599624 // Excludes all match recordgs (is outer the right word for this?)
600- leftRecordsIDs [ leftTableRecordNum ] = keyFieldMap . get ( keyMasterJoinField ) ;
625+ leftRecordsIDs [ leftTableRecordNum ] = rightRecordIDs ;
601626 }
602627 }
603628
@@ -612,9 +637,9 @@ class JoinTablesRecordIds {
612637 */
613638 getJoinColumnData ( fieldInfo , recordNumber ) {
614639 let keyMasterJoinField = null ;
615- const tableColumnNumber = fieldInfo . fieldInfo . tableColumn ;
616640
617- if ( typeof tableColumnNumber !== 'undefined' ) {
641+ if ( typeof fieldInfo . fieldInfo . getTableColumn === 'function' ) {
642+ const tableColumnNumber = fieldInfo . fieldInfo . getTableColumn ( fieldInfo . fieldInfo . fieldName ) ;
618643 keyMasterJoinField = fieldInfo . fieldInfo . tableInfo . tableData [ recordNumber ] [ tableColumnNumber ] ;
619644 }
620645 else {
@@ -632,7 +657,7 @@ class JoinTablesRecordIds {
632657 createKeyFieldRecordMap ( rightField ) {
633658 let keyFieldMap = null ;
634659
635- if ( typeof rightField . fieldInfo . tableColumn !== 'undefined ') {
660+ if ( typeof rightField . fieldInfo . getTableColumn === 'function ') {
636661 keyFieldMap = rightField . fieldInfo . tableInfo . createKeyFieldRecordMap ( rightField . fieldInfo . fieldName ) ;
637662 }
638663 else {
0 commit comments