import * as assert from "@esfx/internal-assert" ; import { Equaler } from "@esfx/equatable" ; import { Grouping } from "@esfx/iter-grouping" ; import { Lookup } from "@esfx/iter-lookup" ; import { identity , tuple } from '@esfx/fn' ; import { empty } from './queries' ; import { union , map , defaultIfEmpty } from './subqueries' ; import { createGroupings } from './internal/utils' ; class GroupJoinIterable < O , I , K , R > implements Iterable < R > { private _outer : Iterable < O > ; private _inner : Iterable < I > ; private _outerKeySelector : ( element : O ) => K ; private _innerKeySelector : ( element : I ) => K ; private _resultSelector : ( outer : O , inner : Iterable < I > ) => R ; private _keyEqualer ? : Equaler < K > ; constructor ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { this . _outer = outer ; this . _inner = inner ; this . _outerKeySelector = outerKeySelector ; this . _innerKeySelector = innerKeySelector ; this . _resultSelector = resultSelector ; this . _keyEqualer = keyEqualer ; } * [ Symbol . iterator ] ( ) { const outerKeySelector = this . _outerKeySelector ; const resultSelector = this . _resultSelector ; const map = createGroupings ( this . _inner , this . _innerKeySelector , identity , this . _keyEqualer ) ; for ( const outerElement of this . _outer ) { const outerKey = outerKeySelector ( outerElement ) ; const innerElements = map . get ( outerKey ) || empty < I > ( ) ; yield resultSelector ( outerElement , innerElements ) ; } } } param outer param inner param outerKeySelector param innerKeySelector param resultSelector param keyEqualer category export function groupJoin < O , I , K , R > ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { assert . mustBeIterableObject ( outer , "outer" ) ; assert . mustBeIterableObject ( inner , "inner" ) ; assert . mustBeFunction ( outerKeySelector , "outerKeySelector" ) ; assert . mustBeFunction ( innerKeySelector , "innerKeySelector" ) ; assert . mustBeFunction ( resultSelector , "resultSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; return new GroupJoinIterable ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ) ; } class JoinIterable < O , I , K , R > implements Iterable < R > { private _outer : Iterable < O > ; private _inner : Iterable < I > ; private _outerKeySelector : ( element : O ) => K ; private _innerKeySelector : ( element : I ) => K ; private _resultSelector : ( outer : O , inner : I ) => R ; private _keyEqualer ? : Equaler < K > ; constructor ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { this . _outer = outer ; this . _inner = inner ; this . _outerKeySelector = outerKeySelector ; this . _innerKeySelector = innerKeySelector ; this . _resultSelector = resultSelector ; this . _keyEqualer = keyEqualer ; } * [ Symbol . iterator ] ( ) { const outerKeySelector = this . _outerKeySelector ; const resultSelector = this . _resultSelector ; const map = createGroupings ( this . _inner , this . _innerKeySelector , identity , this . _keyEqualer ) ; for ( const outerElement of this . _outer ) { const outerKey = outerKeySelector ( outerElement ) ; const innerElements = map . get ( outerKey ) ; if ( innerElements != undefined ) { for ( const innerElement of innerElements ) { yield resultSelector ( outerElement , innerElement ) ; } } } } } param outer param inner param outerKeySelector param innerKeySelector param resultSelector param keyEqualer category export function join < O , I , K , R > ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { assert . mustBeIterableObject ( outer , "outer" ) ; assert . mustBeIterableObject ( inner , "inner" ) ; assert . mustBeFunction ( outerKeySelector , "outerKeySelector" ) ; assert . mustBeFunction ( innerKeySelector , "innerKeySelector" ) ; assert . mustBeFunction ( resultSelector , "resultSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; return new JoinIterable ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ) ; } function selectGroupingKey < K , V > ( grouping ) { return grouping . key ; } class FullJoinIterable < O , I , K , R > implements Iterable < R > { private _outer : Iterable < O > ; private _inner : Iterable < I > ; private _outerKeySelector : ( element : O ) => K ; private _innerKeySelector : ( element : I ) => K ; private _resultSelector : ( outer : O | undefined , inner : I | undefined ) => R ; private _keyEqualer ? : Equaler < K > ; constructor ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { this . _outer = outer ; this . _inner = inner ; this . _outerKeySelector = outerKeySelector ; this . _innerKeySelector = innerKeySelector ; this . _resultSelector = resultSelector ; this . _keyEqualer = keyEqualer ; } * [ Symbol . iterator ] ( ) { const resultSelector = this . _resultSelector ; const outerLookup = new Lookup < K , O > ( createGroupings ( this . _outer , this . _outerKeySelector , identity , this . _keyEqualer ) ) ; const innerLookup = new Lookup < K , I > ( createGroupings ( this . _inner , this . _innerKeySelector , identity , this . _keyEqualer ) ) ; const keys = union ( map ( outerLookup , selectGroupingKey ) , map ( innerLookup , selectGroupingKey ) , this . _keyEqualer ) ; for ( const key of keys ) { const outer = defaultIfEmpty < O | undefined > ( outerLookup . get ( key ) , undefined ) ; const inner = defaultIfEmpty < I | undefined > ( innerLookup . get ( key ) , undefined ) ; for ( const outerElement of outer ) { for ( const innerElement of inner ) { yield resultSelector ( outerElement , innerElement ) ; } } } } } param outer param inner param outerKeySelector param innerKeySelector param resultSelector param keyEqualer category export function fullJoin < O , I , K , R > ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ? ) { assert . mustBeIterableObject ( outer , "outer" ) ; assert . mustBeIterableObject ( inner , "inner" ) ; assert . mustBeFunction ( outerKeySelector , "outerKeySelector" ) ; assert . mustBeFunction ( innerKeySelector , "innerKeySelector" ) ; assert . mustBeFunction ( resultSelector , "resultSelector" ) ; assert . mustBeTypeOrUndefined ( Equaler . hasInstance , keyEqualer , "keyEqualer" ) ; return new FullJoinIterable ( outer , inner , outerKeySelector , innerKeySelector , resultSelector , keyEqualer ) ; } class ZipIterable < T , U , R > implements Iterable < R > { private _left : Iterable < T > ; private _right : Iterable < U > ; private _selector : ( left : T , right : U ) => R ; constructor ( left , right , selector ) { this . _left = left ; this . _right = right ; this . _selector = selector ; } * [ Symbol . iterator ] ( ) { const selector = this . _selector ; const leftIterator = this . _left [ Symbol . iterator ] ( ) ; let leftResult ; try { const rightIterator = this . _right [ Symbol . iterator ] ( ) ; let rightResult ; try { for ( ; ; ) { leftResult = leftIterator . next ( ) ; rightResult = rightIterator . next ( ) ; if ( leftResult . done || rightResult . done ) break ; yield selector ( leftResult . value , rightResult . value ) ; } } finally { if ( rightResult && ! rightResult . done ) { rightIterator . return ?. ( ) ; } } } finally { if ( leftResult && ! leftResult . done ) { leftIterator . return ?. ( ) ; } } } } param left param right category export function zip < T , U > ( left , right ) ; param left param right param selector category export function zip < T , U , R > ( left , right , selector ) ; export function zip < T , U , R > ( left , right , selector = tuple ) { assert . mustBeIterableObject ( left , "left" ) ; assert . mustBeIterableObject ( right , "right" ) ; assert . mustBeFunction ( selector , "selector" ) ; return new ZipIterable ( left , right , selector ) ; }