aggregate.web.js 243 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400
  1. !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.aggregate=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. "use strict";
  3. /**
  4. * This class is a simplified implementation of the cursors used in MongoDB for reading from an Array of documents.
  5. * @param {Array} items The array source of the data
  6. **/
  7. var klass = module.exports = function Cursor(items){
  8. if (!(items instanceof Array)) throw new Error("arg `items` must be an Array");
  9. this.cachedData = items.slice(0); // keep a copy so array changes when using async doc srcs do not cause side effects
  10. this.length = items.length;
  11. this.offset = 0;
  12. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  13. proto.ok = function ok(){
  14. return (this.offset < this.length) || this.hasOwnProperty("curr");
  15. };
  16. proto.advance = function advance(){
  17. if (this.offset >= this.length){
  18. delete this.curr;
  19. return false;
  20. }
  21. this.curr = this.cachedData[this.offset++];
  22. return this.curr;
  23. };
  24. proto.current = function current(){
  25. if (!this.hasOwnProperty("curr")) this.advance();
  26. return this.curr;
  27. };
  28. },{}],2:[function(require,module,exports){
  29. "use strict";
  30. /**
  31. * Used to aggregate `inputs` using a MongoDB-style `pipeline`
  32. *
  33. * If `inputs` is given, it will run the `inputs` through the `pipeline` and call the `callback` with the results.
  34. * If `inputs` is omitted, it will return an "aggregator" function so you can reuse the given `pipeline` against various `inputs`.
  35. *
  36. * NOTE: you should be mindful about reusing the same `pipeline` against disparate `inputs` because document coming in can alter the state of it's `DocumentSource`s
  37. *
  38. * @method aggregate
  39. * @namespace mungedb
  40. * @module mungedb-aggregate
  41. * @param pipeline {Array} The list of pipeline document sources in JSON format
  42. * @param [ctx] {Object} Optional context object to pass through to pipeline
  43. * @param [inputs] {Array} Optional inputs to pass through the `docSrcs` pipeline
  44. * @param [callback] {Function} Optional callback if using async extensions, called when done
  45. * @param callback.err {Error} The Error if one occurred
  46. * @param callback.docs {Array} The resulting documents
  47. **/
  48. exports = module.exports = function aggregate(pipeline, ctx, inputs, callback) { // function-style interface; i.e., return the utility function directly as the require
  49. var DocumentSource = exports.pipeline.documentSources.DocumentSource;
  50. if (ctx instanceof Array || ctx instanceof DocumentSource) callback = inputs, inputs = ctx, ctx = {};
  51. var pipelineInst = exports.pipeline.Pipeline.parseCommand({
  52. pipeline: pipeline
  53. }, ctx),
  54. aggregator = function aggregator(ctx, inputs, callback) {
  55. if (ctx instanceof Array || ctx instanceof DocumentSource) callback = inputs, inputs = ctx, ctx = {};
  56. if (!callback) callback = exports.SYNC_CALLBACK;
  57. if (!inputs) return callback("arg `inputs` is required");
  58. // rebuild the pipeline on subsequent calls
  59. if (!pipelineInst) {
  60. pipelineInst = exports.pipeline.Pipeline.parseCommand({
  61. pipeline: pipeline
  62. }, ctx);
  63. }
  64. // use or build input src
  65. var src;
  66. if(inputs instanceof DocumentSource){
  67. src = inputs;
  68. }else{
  69. try{
  70. pipelineInst.collectionName = inputs; //NOTE: use the given `inputs` directly; not really a "name" but we don't really have collection names in mungedb-aggregate
  71. src = exports.pipeline.PipelineD.prepareCursorSource(pipelineInst, pipelineInst.ctx);
  72. }catch(err){
  73. return callback(err);
  74. }
  75. }
  76. // run the pipeline against the input src
  77. var results = pipelineInst.run(src, callback === exports.SYNC_CALLBACK ? undefined : function aggregated(err, results){
  78. if(err) return callback(err);
  79. return callback(null, results.result);
  80. });
  81. pipelineInst = null; // unset so that subsequent calls can rebuild the pipeline
  82. return results;
  83. };
  84. if(inputs) return aggregator(ctx, inputs, callback);
  85. return aggregator;
  86. };
  87. // sync callback for aggregate if none was provided
  88. exports.SYNC_CALLBACK = function(err, docs){
  89. if (err) throw err;
  90. return docs;
  91. };
  92. // package-style interface; i.e., return a function underneath of the require
  93. exports.aggregate = exports;
  94. //Expose these so that mungedb-aggregate can be extended.
  95. exports.Cursor = require("./Cursor");
  96. exports.pipeline = require("./pipeline/");
  97. // version info
  98. exports.version = "r2.4.0-rc0";
  99. exports.gitVersion = "cb8efcd6a2f05d35655ed9f9b947cc4a99ade8db";
  100. },{"./Cursor":1,"./pipeline/":62}],3:[function(require,module,exports){
  101. "use strict";
  102. /**
  103. * Represents a `Document` (i.e., an `Object`) in `mongo` but in `munge` this is only a set of static helpers since we treat all `Object`s like `Document`s.
  104. * @class Document
  105. * @namespace mungedb-aggregate.pipeline
  106. * @module mungedb-aggregate
  107. * @constructor
  108. **/
  109. var Document = module.exports = function Document(){
  110. if(this.constructor == Document) throw new Error("Never create instances! Use static helpers only.");
  111. }, klass = Document, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  112. // DEPENDENCIES
  113. var Value = require("./Value");
  114. // STATIC MEMBERS
  115. /**
  116. * Shared "_id"
  117. * @static
  118. * @property ID_PROPERTY_NAME
  119. **/
  120. klass.ID_PROPERTY_NAME = "_id";
  121. /**
  122. * Compare two documents.
  123. *
  124. * BSON document field order is significant, so this just goes through the fields in order.
  125. * The comparison is done in roughly the same way as strings are compared, but comparing one field at a time instead of one character at a time.
  126. *
  127. * @static
  128. * @method compare
  129. * @param rL left document
  130. * @param rR right document
  131. * @returns an integer less than zero, zero, or an integer greater than zero, depending on whether rL < rR, rL == rR, or rL > rR
  132. **/
  133. klass.compare = function compare(l, r){ //TODO: might be able to replace this with a straight compare of docs using JSON.stringify()
  134. var lPropNames = Object.getOwnPropertyNames(l),
  135. lPropNamesLength = lPropNames.length,
  136. rPropNames = Object.getOwnPropertyNames(r),
  137. rPropNamesLength = rPropNames.length;
  138. for(var i = 0; true; ++i) {
  139. if (i >= lPropNamesLength) {
  140. if (i >= rPropNamesLength) return 0; // documents are the same length
  141. return -1; // left document is shorter
  142. }
  143. if (i >= rPropNamesLength) return 1; // right document is shorter
  144. var nameCmp = Value.compare(lPropNames[i], rPropNames[i]);
  145. if (nameCmp !== 0) return nameCmp; // field names are unequal
  146. var valueCmp = Value.compare(l[lPropNames[i]], r[rPropNames[i]]);
  147. if (valueCmp) return valueCmp; // fields are unequal
  148. }
  149. /* NOTREACHED */
  150. throw new Error("This should never happen"); //verify(false)
  151. // return 0;
  152. };
  153. /**
  154. * Clone a document
  155. * @static
  156. * @method clone
  157. * @param document
  158. **/
  159. klass.clone = function(document){
  160. var obj = {};
  161. for(var key in document){
  162. if(document.hasOwnProperty(key)){
  163. var withObjVal = document[key];
  164. if(withObjVal === null) { // necessary to handle null values without failing
  165. obj[key] = withObjVal;
  166. }
  167. else if(withObjVal.constructor === Object){
  168. obj[key] = Document.clone(withObjVal);
  169. }else{
  170. obj[key] = withObjVal;
  171. }
  172. }
  173. }
  174. return obj;
  175. };
  176. // proto.addField = function addField(){ throw new Error("Instead of `Document#addField(key,val)` you should just use `obj[key] = val`"); }
  177. // proto.setField = function addField(){ throw new Error("Instead of `Document#setField(key,val)` you should just use `obj[key] = val`"); }
  178. // proto.getField = function getField(){ throw new Error("Instead of `Document#getField(key)` you should just use `var val = obj[key];`"); }
  179. },{"./Value":7}],4:[function(require,module,exports){
  180. "use strict";
  181. /**
  182. * Constructor for field paths.
  183. *
  184. * The constructed object will have getPathLength() > 0.
  185. * Uassert if any component field names do not pass validation.
  186. *
  187. * @class FieldPath
  188. * @namespace mungedb-aggregate.pipeline
  189. * @module mungedb-aggregate
  190. * @constructor
  191. * @param fieldPath the dotted field path string or non empty pre-split vector.
  192. **/
  193. var FieldPath = module.exports = function FieldPath(path) {
  194. var fields = typeof path === "object" && typeof path.length === "number" ? path : path.split(".");
  195. if(fields.length === 0) throw new Error("FieldPath cannot be constructed from an empty vector (String or Array).; code 16409");
  196. for(var i = 0, n = fields.length; i < n; ++i){
  197. var field = fields[i];
  198. if(field.length === 0) throw new Error("FieldPath field names may not be empty strings; code 15998");
  199. if(field[0] == "$") throw new Error("FieldPath field names may not start with '$'; code 16410");
  200. if(field.indexOf("\0") != -1) throw new Error("FieldPath field names may not contain '\\0'; code 16411");
  201. if(field.indexOf(".") != -1) throw new Error("FieldPath field names may not contain '.'; code 16412");
  202. }
  203. this.path = path;
  204. this.fields = fields;
  205. }, klass = FieldPath, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  206. // STATIC MEMBERS
  207. klass.PREFIX = "$";
  208. // PROTOTYPE MEMBERS
  209. /**
  210. * Get the full path.
  211. *
  212. * @method getPath
  213. * @param fieldPrefix whether or not to include the field prefix
  214. * @returns the complete field path
  215. **/
  216. proto.getPath = function getPath(withPrefix) {
  217. return ( !! withPrefix ? FieldPath.PREFIX : "") + this.fields.join(".");
  218. };
  219. /**
  220. * A FieldPath like this but missing the first element (useful for recursion). Precondition getPathLength() > 1.
  221. *
  222. * @method tail
  223. **/
  224. proto.tail = function tail() {
  225. return new FieldPath(this.fields.slice(1));
  226. };
  227. /**
  228. * Get a particular path element from the path.
  229. *
  230. * @method getFieldName
  231. * @param i the zero based index of the path element.
  232. * @returns the path element
  233. **/
  234. proto.getFieldName = function getFieldName(i){ //TODO: eventually replace this with just using .fields[i] directly
  235. return this.fields[i];
  236. };
  237. /**
  238. * Get the number of path elements in the field path.
  239. *
  240. * @method getPathLength
  241. * @returns the number of path elements
  242. **/
  243. proto.getPathLength = function getPathLength() {
  244. return this.fields.length;
  245. };
  246. },{}],5:[function(require,module,exports){
  247. "use strict";
  248. var async = require("async");
  249. /**
  250. * mongodb "commands" (sent via db.$cmd.findOne(...)) subclass to make a command. define a singleton object for it.
  251. * @class Pipeline
  252. * @namespace mungedb-aggregate.pipeline
  253. * @module mungedb-aggregate
  254. * @constructor
  255. **/
  256. // CONSTRUCTOR
  257. var Pipeline = module.exports = function Pipeline(theCtx){
  258. this.collectionName = null;
  259. this.sourceVector = null;
  260. this.explain = false;
  261. this.splitMongodPipeline = false;
  262. this.ctx = theCtx;
  263. }, klass = Pipeline, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  264. var DocumentSource = require("./documentSources/DocumentSource"),
  265. LimitDocumentSource = require('./documentSources/LimitDocumentSource'),
  266. MatchDocumentSource = require('./documentSources/MatchDocumentSource'),
  267. ProjectDocumentSource = require('./documentSources/ProjectDocumentSource'),
  268. SkipDocumentSource = require('./documentSources/SkipDocumentSource'),
  269. UnwindDocumentSource = require('./documentSources/UnwindDocumentSource'),
  270. GroupDocumentSource = require('./documentSources/GroupDocumentSource'),
  271. SortDocumentSource = require('./documentSources/SortDocumentSource');
  272. klass.COMMAND_NAME = "aggregate";
  273. klass.PIPELINE_NAME = "pipeline";
  274. klass.EXPLAIN_NAME = "explain";
  275. klass.FROM_ROUTER_NAME = "fromRouter";
  276. klass.SPLIT_MONGOD_PIPELINE_NAME = "splitMongodPipeline";
  277. klass.SERVER_PIPELINE_NAME = "serverPipeline";
  278. klass.MONGOS_PIPELINE_NAME = "mongosPipeline";
  279. klass.stageDesc = {};//attaching this to the class for test cases
  280. klass.stageDesc[LimitDocumentSource.limitName] = LimitDocumentSource.createFromJson;
  281. klass.stageDesc[MatchDocumentSource.matchName] = MatchDocumentSource.createFromJson;
  282. klass.stageDesc[ProjectDocumentSource.projectName] = ProjectDocumentSource.createFromJson;
  283. klass.stageDesc[SkipDocumentSource.skipName] = SkipDocumentSource.createFromJson;
  284. klass.stageDesc[UnwindDocumentSource.unwindName] = UnwindDocumentSource.createFromJson;
  285. klass.stageDesc[GroupDocumentSource.groupName] = GroupDocumentSource.createFromJson;
  286. klass.stageDesc[SortDocumentSource.sortName] = SortDocumentSource.createFromJson;
  287. /**
  288. * Create an `Array` of `DocumentSource`s from the given JSON pipeline
  289. * // NOTE: DEVIATION FROM MONGO: split out into a separate function to better allow extensions (was in parseCommand)
  290. * @static
  291. * @method parseDocumentSources
  292. * @param pipeline {Array} The JSON pipeline
  293. * @returns {Array} The parsed `DocumentSource`s
  294. **/
  295. klass.parseDocumentSources = function parseDocumentSources(pipeline, ctx){
  296. var sourceVector = [];
  297. for (var nSteps = pipeline.length, iStep = 0; iStep < nSteps; ++iStep) {
  298. // pull out the pipeline element as an object
  299. var pipeElement = pipeline[iStep];
  300. if (!(pipeElement instanceof Object)) throw new Error("pipeline element " + iStep + " is not an object; code 15942");
  301. var obj = pipeElement;
  302. // Parse a pipeline stage from 'obj'.
  303. if (Object.keys(obj).length !== 1) throw new Error("A pipeline stage specification object must contain exactly one field; code 16435");
  304. var stageName = Object.keys(obj)[0],
  305. stageSpec = obj[stageName];
  306. // Create a DocumentSource pipeline stage from 'stageSpec'.
  307. var desc = klass.stageDesc[stageName];
  308. if (!desc) throw new Error("Unrecognized pipeline stage name: '" + stageName + "'; code 16435");
  309. // Parse the stage
  310. var stage = desc(stageSpec, ctx);
  311. if (!stage) throw new Error("Stage must not be undefined!");
  312. stage.setPipelineStep(iStep);
  313. sourceVector.push(stage);
  314. }
  315. return sourceVector;
  316. };
  317. /**
  318. * Create a pipeline from the command.
  319. * @static
  320. * @method parseCommand
  321. * @param cmdObj {Object} The command object sent from the client
  322. * @param cmdObj.aggregate {Array} the thing to aggregate against; // NOTE: DEVIATION FROM MONGO: expects an Array of inputs rather than a collection name
  323. * @param cmdObj.pipeline {Object} the JSON pipeline of `DocumentSource` specs
  324. * @param cmdObj.explain {Boolean} should explain?
  325. * @param cmdObj.fromRouter {Boolean} is from router?
  326. * @param cmdObj.splitMongodPipeline {Boolean} should split?
  327. * @param ctx {Object} Not used yet in mungedb-aggregate
  328. * @returns {Array} the pipeline, if created, otherwise a NULL reference
  329. **/
  330. klass.parseCommand = function parseCommand(cmdObj, ctx){
  331. var pipelineNamespace = require("./"),
  332. Pipeline = pipelineNamespace.Pipeline, // using require in case Pipeline gets replaced with an extension
  333. pipelineInst = new Pipeline(ctx);
  334. //gather the specification for the aggregation
  335. var pipeline;
  336. for(var fieldName in cmdObj){
  337. var cmdElement = cmdObj[fieldName];
  338. if(fieldName == klass.COMMAND_NAME) pipelineInst.collectionName = cmdElement; //look for the aggregation command
  339. else if(fieldName == klass.PIPELINE_NAME) pipeline = cmdElement; //check for the pipeline of JSON doc srcs
  340. else if(fieldName == klass.EXPLAIN_NAME) pipelineInst.explain = cmdElement; //check for explain option
  341. else if(fieldName == klass.FROM_ROUTER_NAME) pipelineInst.fromRouter = cmdElement; //if the request came from the router, we're in a shard
  342. else if(fieldName == klass.SPLIT_MONGOD_PIPELINE_NAME) pipelineInst.splitMongodPipeline = cmdElement; //check for debug options
  343. // NOTE: DEVIATION FROM MONGO: Not implementing: "Ignore $auth information sent along with the command. The authentication system will use it, it's not a part of the pipeline."
  344. else throw new Error("unrecognized field " + JSON.stringify(fieldName));
  345. }
  346. /**
  347. * If we get here, we've harvested the fields we expect for a pipeline
  348. * Set up the specified document source pipeline.
  349. **/
  350. // NOTE: DEVIATION FROM MONGO: split this into a separate function to simplify and better allow for extensions (now in parseDocumentSources)
  351. var sourceVector = pipelineInst.sourceVector = Pipeline.parseDocumentSources(pipeline, ctx);
  352. /* if there aren't any pipeline stages, there's nothing more to do */
  353. if (!sourceVector.length) return pipelineInst;
  354. /* Move filters up where possible.
  355. CW TODO -- move filter past projections where possible, and noting corresponding field renaming.
  356. */
  357. /*
  358. Wherever there is a match immediately following a sort, swap them.
  359. This means we sort fewer items. Neither changes the documents in the stream, so this transformation shouldn't affect the result.
  360. We do this first, because then when we coalesce operators below, any adjacent matches will be combined.
  361. */
  362. for(var srcn = sourceVector.length, srci = 1; srci < srcn; ++srci) {
  363. var source = sourceVector[srci];
  364. if (source instanceof MatchDocumentSource) {
  365. var previous = sourceVector[srci - 1];
  366. if (previous instanceof SortDocumentSource) {
  367. /* swap this item with the previous */
  368. sourceVector[srci - 1] = source;
  369. sourceVector[srci] = previous;
  370. }
  371. }
  372. }
  373. /*
  374. Coalesce adjacent filters where possible. Two adjacent filters are equivalent to one filter whose predicate is the conjunction of the two original filters' predicates.
  375. For now, capture this by giving any DocumentSource the option to absorb it's successor; this will also allow adjacent projections to coalesce when possible.
  376. Run through the DocumentSources, and give each one the opportunity to coalesce with its successor. If successful, remove the successor.
  377. Move all document sources to a temporary list.
  378. */
  379. var tempVector = sourceVector.slice(0);
  380. sourceVector.length = 0;
  381. // move the first one to the final list
  382. sourceVector.push(tempVector[0]);
  383. // run through the sources, coalescing them or keeping them
  384. for(var tempn = tempVector.length, tempi = 1; tempi < tempn; ++tempi) {
  385. /*
  386. If we can't coalesce the source with the last, then move it to the final list, and make it the new last.
  387. (If we succeeded, then we're still on the same last, and there's no need to move or do anything with the source -- the destruction of tempVector will take care of the rest.)
  388. */
  389. var lastSource = sourceVector[sourceVector.length - 1],
  390. temp = tempVector[tempi];
  391. if (!temp || !lastSource) throw new Error("null document sources found");
  392. if (!lastSource.coalesce(temp)){
  393. sourceVector.push(temp);
  394. }
  395. }
  396. // optimize the elements in the pipeline
  397. for(var i = 0, l = sourceVector.length; i<l; i++) {
  398. var iter = sourceVector[i];
  399. if (!iter) throw new Error("Pipeline received empty document as argument");
  400. iter.optimize();
  401. }
  402. return pipelineInst;
  403. };
  404. // sync callback for Pipeline#run if omitted
  405. klass.SYNC_CALLBACK = function(err, results){
  406. if (err) throw err;
  407. return results.result;
  408. };
  409. function ifError(err) {
  410. if (err) throw err;
  411. }
  412. /**
  413. * Run the pipeline
  414. * @method run
  415. * @param inputSource {DocumentSource} The input document source for the pipeline
  416. * @param [callback] {Function} Optional callback function if using async extensions
  417. **/
  418. proto.run = function run(inputSource, callback){
  419. if (inputSource && !(inputSource instanceof DocumentSource)) throw new Error("arg `inputSource` must be an instance of DocumentSource");
  420. if (!callback) callback = klass.SYNC_CALLBACK;
  421. var self = this;
  422. if (callback === klass.SYNC_CALLBACK) { // SYNCHRONOUS MODE
  423. inputSource.setSource(undefined, ifError); //TODO: HACK: temp solution to the fact that we need to initialize our source since we're using setSource as a workaround for the lack of real async cursors
  424. var source = inputSource;
  425. for(var i = 0, l = self.sourceVector.length; i < l; i++){
  426. var temp = self.sourceVector[i];
  427. temp.setSource(source, ifError);
  428. source = temp;
  429. }
  430. /*
  431. Iterate through the resulting documents, and add them to the result.
  432. We do this even if we're doing an explain, in order to capture the document counts and other stats.
  433. However, we don't capture the result documents for explain.
  434. */
  435. var resultArray = [];
  436. try{
  437. for(var hasDoc = !source.eof(); hasDoc; hasDoc = source.advance()) {
  438. var document = source.getCurrent();
  439. resultArray.push(document); // add the document to the result set
  440. //Commenting out this assertion for munge. MUHAHAHA!!!
  441. // object will be too large, assert. the extra 1KB is for headers
  442. //if(resultArray.len() < BSONObjMaxUserSize - 1024) throw new Error("aggregation result exceeds maximum document size (" + BSONObjMaxUserSize / (1024 * 1024) + "MB); code 16389");
  443. }
  444. } catch (err) {
  445. return callback(err);
  446. }
  447. var result = {
  448. result: resultArray
  449. // ,ok: true; //not actually in here... where does this come from?
  450. };
  451. return callback(null, result);
  452. } else { // ASYNCHRONOUS MODE //TODO: move this up to a higher level package?
  453. return inputSource.setSource(undefined, function(err){ //TODO: HACK: temp solution to the fact that we need to initialize our source since we're using setSource as a workaround for the lack of real async cursors
  454. if (err) return callback(err);
  455. // chain together the sources we found
  456. var source = inputSource;
  457. async.eachSeries(
  458. self.sourceVector,
  459. function eachSrc(temp, next){
  460. temp.setSource(source, function(err){
  461. if (err) return next(err);
  462. source = temp;
  463. return next();
  464. });
  465. },
  466. function doneSrcs(err){ //source is left pointing at the last source in the chain
  467. if (err) return callback(err);
  468. /*
  469. Iterate through the resulting documents, and add them to the result.
  470. We do this even if we're doing an explain, in order to capture the document counts and other stats.
  471. However, we don't capture the result documents for explain.
  472. */
  473. // the array in which the aggregation results reside
  474. var resultArray = [];
  475. try{
  476. for(var hasDoc = !source.eof(); hasDoc; hasDoc = source.advance()) {
  477. var document = source.getCurrent();
  478. resultArray.push(document); // add the document to the result set
  479. //Commenting out this assertion for munge. MUHAHAHA!!!
  480. // object will be too large, assert. the extra 1KB is for headers
  481. //if(resultArray.len() < BSONObjMaxUserSize - 1024) throw new Error("aggregation result exceeds maximum document size (" + BSONObjMaxUserSize / (1024 * 1024) + "MB); code 16389");
  482. }
  483. } catch (err) {
  484. return callback(err);
  485. }
  486. var result = {
  487. result: resultArray
  488. // ,ok: true; //not actually in here... where does this come from?
  489. };
  490. return callback(null, result);
  491. }
  492. );
  493. });
  494. }
  495. };
  496. },{"./":62,"./documentSources/DocumentSource":19,"./documentSources/GroupDocumentSource":21,"./documentSources/LimitDocumentSource":22,"./documentSources/MatchDocumentSource":23,"./documentSources/ProjectDocumentSource":24,"./documentSources/SkipDocumentSource":25,"./documentSources/SortDocumentSource":26,"./documentSources/UnwindDocumentSource":27,"async":63}],6:[function(require,module,exports){
  497. "use strict";
  498. /**
  499. * Pipeline helper for reading data
  500. * @class PipelineD
  501. * @namespace mungedb-aggregate.pipeline
  502. * @module mungedb-aggregate
  503. * @constructor
  504. **/
  505. var PipelineD = module.exports = function PipelineD(){
  506. if(this.constructor == PipelineD) throw new Error("Never create instances of this! Use the static helpers only.");
  507. }, klass = PipelineD, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  508. // DEPENDENCIES
  509. var DocumentSource = require('./documentSources/DocumentSource'),
  510. CursorDocumentSource = require('./documentSources/CursorDocumentSource'),
  511. Cursor = require('../Cursor');
  512. /**
  513. * Create a Cursor wrapped in a DocumentSourceCursor, which is suitable to be the first source for a pipeline to begin with.
  514. * This source will feed the execution of the pipeline.
  515. *
  516. * //NOTE: DEVIATION FROM THE MONGO: We don't have special optimized cursors; You could support something similar by overriding `Pipeline#run` to call `DocumentSource#coalesce` on the `inputSource` if you really need it.
  517. *
  518. * This method looks for early pipeline stages that can be folded into
  519. * the underlying cursor, and when a cursor can absorb those, they
  520. * are removed from the head of the pipeline. For example, an
  521. * early match can be removed and replaced with a Cursor that will
  522. * do an index scan.
  523. *
  524. * @param pipeline {Pipeline} the logical "this" for this operation
  525. * @param ctx {Object} Context for expressions
  526. * @returns {CursorDocumentSource} the cursor that was created
  527. **/
  528. klass.prepareCursorSource = function prepareCursorSource(pipeline, /*dbName,*/ expCtx){
  529. var sources = pipeline.sourceVector;
  530. //NOTE: SKIPPED: look for initial match
  531. //NOTE: SKIPPED: create a query object
  532. //Look for an initial simple project; we'll avoid constructing Values for fields that won't make it through the projection
  533. var projection = {};
  534. var deps = [];
  535. var status = DocumentSource.GetDepsReturn.SEE_NEXT;
  536. for (var i=0; i < sources.length && status != DocumentSource.GetDepsReturn.EXHAUSTIVE; i++) {
  537. status = sources[i].getDependencies(deps);
  538. }
  539. if (status == DocumentSource.GetDepsReturn.EXHAUSTIVE) {
  540. projection = DocumentSource.depsToProjection(deps);
  541. }
  542. //NOTE: SKIPPED: Look for an initial sort
  543. //NOTE: SKIPPED: Create the sort object
  544. // //get the full "namespace" name
  545. // var fullName = dbName + "." + pipeline.collectionName;
  546. //NOTE: SKIPPED: if(DEV) log messages
  547. //Create the necessary context to use a Cursor
  548. //NOTE: SKIPPED: pSortedCursor bit
  549. //NOTE: SKIPPED: pUnsortedCursor bit
  550. var cursorWithContext = new CursorDocumentSource.CursorWithContext(/*fullName*/);
  551. // Now add the Cursor to cursorWithContext
  552. cursorWithContext._cursor = new Cursor( pipeline.collectionName );
  553. // wrap the cursor with a DocumentSource and return that
  554. var source = new CursorDocumentSource( cursorWithContext, expCtx );
  555. // source.namespace = fullName;
  556. //NOTE: SKIPPED: Note the query and sort
  557. if (Object.keys(projection).length) source.setProjection(projection);
  558. return source;
  559. };
  560. },{"../Cursor":1,"./documentSources/CursorDocumentSource":18,"./documentSources/DocumentSource":19}],7:[function(require,module,exports){
  561. "use strict";
  562. /**
  563. * Represents a `Value` (i.e., an `Object`) in `mongo` but in `munge` this is only a set of static helpers since we treat all `Object`s like `Value`s.
  564. * @class Value
  565. * @namespace mungedb-aggregate.pipeline
  566. * @module mungedb-aggregate
  567. * @constructor
  568. **/
  569. var Value = module.exports = function Value(){
  570. if(this.constructor == Value) throw new Error("Never create instances of this! Use the static helpers only.");
  571. }, klass = Value, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  572. // PRIVATE STUFF
  573. function getTypeVerifier(type, IClass, isStrict) {
  574. return function verifyType(value) {
  575. if (typeof(value) != type) throw new Error("typeof value is not: " + type + "; actual: " + typeof(value));
  576. if (typeof(IClass) == "function" && !(isStrict ? value.constructor == IClass : value instanceof IClass)) throw new Error("instanceof value is not: " + IClass.name + "; actual: " + value.constructor.name);
  577. return value;
  578. };
  579. }
  580. // STATIC MEMBERS
  581. klass.verifyNumber = getTypeVerifier("number", Number); //NOTE: replaces #getDouble(), #getInt(), and #getLong()
  582. klass.verifyString = getTypeVerifier("string", String);
  583. klass.verifyDocument = getTypeVerifier("object", Object, true); //TODO: change to verifyObject? since we're not using actual Document instances
  584. klass.verifyArray = getTypeVerifier("object", Array, true);
  585. klass.verifyDate = getTypeVerifier("object", Date, true);
  586. klass.verifyRegExp = getTypeVerifier("object", RegExp, true); //NOTE: renamed from #getRegex()
  587. //TODO: klass.verifyOid = ...?
  588. //TODO: klass.VerifyTimestamp = ...?
  589. klass.verifyBool = getTypeVerifier("boolean", Boolean, true);
  590. klass.coerceToBool = function coerceToBool(value) {
  591. if (typeof(value) == "string") return true;
  592. return !!value; // including null or undefined
  593. };
  594. klass.coerceToInt =
  595. klass.coerceToLong =
  596. klass.coerceToDouble =
  597. klass._coerceToNumber = function _coerceToNumber(value) { //NOTE: replaces .coerceToInt(), .coerceToLong(), and .coerceToDouble()
  598. if (value === null) return 0;
  599. switch (typeof(value)) {
  600. case "undefined":
  601. return 0;
  602. case "number":
  603. return value;
  604. case "object":
  605. switch (value.constructor.name) {
  606. case "Long":
  607. return parseInt(value.toString(), 10);
  608. case "Double":
  609. return parseFloat(value.value, 10);
  610. default:
  611. throw new Error("can't convert from BSON type " + value.constructor.name + " to int; codes 16003, 16004, 16005");
  612. }
  613. return value;
  614. default:
  615. throw new Error("can't convert from BSON type " + typeof(value) + " to int; codes 16003, 16004, 16005");
  616. }
  617. };
  618. klass.coerceToDate = function coerceToDate(value) {
  619. //TODO: Support Timestamp BSON type?
  620. if (value instanceof Date) return value;
  621. throw new Error("can't convert from BSON type " + typeof(value) + " to Date; uassert code 16006");
  622. };
  623. //TODO: klass.coerceToTimeT = ...? try to use as Date first rather than having coerceToDate return Date.parse or dateObj.getTime() or similar
  624. //TODO: klass.coerceToTm = ...?
  625. klass.coerceToString = function coerceToString(value) {
  626. if (value === null) return "";
  627. switch (typeof(value)) {
  628. case "undefined":
  629. return "";
  630. case "number":
  631. return value.toString();
  632. case "string":
  633. return value;
  634. default:
  635. throw new Error("can't convert from BSON type " + typeof(value) + " to String; uassert code 16007");
  636. }
  637. };
  638. klass.canonicalize = function canonicalize(x) {
  639. var xType = typeof(x);
  640. if(xType == "object") xType = x === null ? "null" : x.constructor.name;
  641. switch (xType) {
  642. case "MinKey":
  643. return -1;
  644. case "MaxKey":
  645. return 127;
  646. case "EOO":
  647. case "undefined":
  648. case undefined:
  649. return 0;
  650. case "jstNULL":
  651. case "null":
  652. case "Null":
  653. return 5;
  654. case "NumberDouble":
  655. case "NumberInt":
  656. case "NumberLong":
  657. case "number":
  658. return 10;
  659. case "Symbol":
  660. case "string":
  661. return 15;
  662. case "Object":
  663. return 20;
  664. case "Array":
  665. return 25;
  666. case "Binary":
  667. return 30;
  668. case "ObjectId":
  669. return 35;
  670. case "ObjectID":
  671. return 35;
  672. case "boolean":
  673. case "Boolean":
  674. return 40;
  675. case "Date":
  676. case "Timestamp":
  677. return 45;
  678. case "RegEx":
  679. case "RegExp":
  680. return 50;
  681. case "DBRef":
  682. return 55;
  683. case "Code":
  684. return 60;
  685. case "CodeWScope":
  686. return 65;
  687. default:
  688. // Default value for Object
  689. return 20;
  690. }
  691. };
  692. klass.cmp = function cmp(l, r){
  693. return l < r ? -1 : l > r ? 1 : 0;
  694. };
  695. //TODO: klass.coerceToTimestamp = ...?
  696. /**
  697. * Compare two Values.
  698. *
  699. * @static
  700. * @method compare
  701. * @param rL left value
  702. * @param rR right value
  703. * @returns an integer less than zero, zero, or an integer greater than zero, depending on whether rL < rR, rL == rR, or rL > rR
  704. **/
  705. var Document; // loaded lazily below //TODO: a dirty hack; need to investigate and clean up
  706. klass.compare = function compare(l, r) {
  707. //NOTE: deviation from mongo code: we have to do some coercing for null "types" because of javascript
  708. var lt = l === null ? "null" : typeof(l),
  709. rt = r === null ? "null" : typeof(r),
  710. ret;
  711. // NOTE: deviation from mongo code: javascript types do not work quite the same, so for proper results we always canonicalize, and we don't need the "speed" hack
  712. ret = (klass.cmp(klass.canonicalize(l), klass.canonicalize(r)));
  713. if(ret !== 0) return ret;
  714. // Numbers
  715. if (lt === "number" && rt === "number"){
  716. //NOTE: deviation from Mongo code: they handle NaN a bit differently
  717. if (isNaN(l)) return isNaN(r) ? 0 : -1;
  718. if (isNaN(r)) return 1;
  719. return klass.cmp(l,r);
  720. }
  721. // CW TODO for now, only compare like values
  722. if (lt !== rt) throw new Error("can't compare values of BSON types [" + lt + " " + l.constructor.name + "] and [" + rt + ":" + r.constructor.name + "]; code 16016");
  723. // Compare everything else
  724. switch (lt) {
  725. case "number":
  726. throw new Error("number types should have been handled earlier!");
  727. case "string":
  728. return klass.cmp(l,r);
  729. case "boolean":
  730. return l == r ? 0 : l ? 1 : -1;
  731. case "undefined": //NOTE: deviation from mongo code: we are comparing null to null or undefined to undefined (otherwise the ret stuff above would have caught it)
  732. case "null":
  733. return 0;
  734. case "object":
  735. if (l instanceof Array) {
  736. for (var i = 0, ll = l.length, rl = r.length; true ; ++i) {
  737. if (i > ll) {
  738. if (i > rl) return 0; // arrays are same length
  739. return -1; // left array is shorter
  740. }
  741. if (i > rl) return 1; // right array is shorter
  742. var cmp = Value.compare(l[i], r[i]);
  743. if (cmp !== 0) return cmp;
  744. }
  745. throw new Error("logic error in Value.compare for Array types!");
  746. }
  747. if (l instanceof Date) return klass.cmp(l,r);
  748. if (l instanceof RegExp) return klass.cmp(l,r);
  749. if (Document === undefined) Document = require("./Document"); //TODO: a dirty hack; need to investigate and clean up
  750. return Document.compare(l, r);
  751. default:
  752. throw new Error("unhandled left hand type:" + lt);
  753. }
  754. };
  755. //TODO: klass.hashCombine = ...?
  756. //TODO: klass.getWidestNumeric = ...?
  757. //TODO: klass.getApproximateSize = ...?
  758. //TODO: klass.addRef = ...?
  759. //TODO: klass.release = ...?
  760. },{"./Document":3}],8:[function(require,module,exports){
  761. "use strict";
  762. /**
  763. * A base class for all pipeline accumulators. Uses NaryExpression as a base class.
  764. *
  765. * @class Accumulator
  766. * @namespace mungedb-aggregate.pipeline.accumulators
  767. * @module mungedb-aggregate
  768. * @constructor
  769. **/
  770. var Accumulator = module.exports = function Accumulator(){
  771. if (arguments.length !== 0) throw new Error("zero args expected");
  772. base.call(this);
  773. }, klass = Accumulator, base = require("../expressions/NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  774. // DEPENDENCIES
  775. // var Value = require("../Value"),
  776. proto.getFactory = function getFactory(){
  777. return klass; // using the ctor rather than a separate .create() method
  778. };
  779. /**
  780. * Adds the operand after checking the current limit
  781. * The equal is there because it checks *before* adding the requested argument.
  782. * Cannot use checkArgLimit because Accumulator must return a different error code.
  783. *
  784. * @param expr the operand to add
  785. **/
  786. proto.addOperand = function addOperand(expr) {
  787. if (this.operands.length >= 1) throw new Error("code 15943; group accumulator " + this.getOpName() + " only accepts one operand");
  788. base.prototype.addOperand.call(this, expr);
  789. };
  790. proto.toJSON = function toJSON(isExpressionRequired){
  791. var rep = {};
  792. rep[this.getOpName()] = this.operands[0].toJSON(isExpressionRequired);
  793. return rep;
  794. };
  795. /**
  796. * Convenience method for doing this for accumulators. The pattern
  797. * is always the same, so a common implementation works, but requires
  798. * knowing the operator name.
  799. *
  800. * @param {Object} pBuilder the builder to add to
  801. * @param {String} fieldName the projected name
  802. * @param {String} opName the operator name
  803. * @param {Boolean} requireExpression pass down if the expression is needed
  804. **/
  805. // proto.opToBson = function opToBson(pBuilder, opName, fieldName, requireExpression) {
  806. // if (this.operands.length == 1) throw new Error("this should never happen");
  807. // var builder = new BSONObjBuilder();
  808. // this.operands[0].addToBsonObj(builder, opName, requireExpression);
  809. // pBuilder.append(fieldName, builder.done());
  810. // };
  811. /**
  812. * Wrapper around opToBson
  813. *
  814. * @param {Object} pBuilder the builder to add to
  815. * @param {String} fieldName the projected name
  816. * @param {Boolean} requireExpression pass down if the expression is needed
  817. **/
  818. // proto.addToBsonObj = function addToBsonObj(pBuilder, fieldName, requireExpression) {
  819. // this.opToBson(pBuilder, this.getOpName(), fieldName, requireExpression);
  820. // };
  821. /**
  822. * Make sure that nobody adds an accumulator to an array
  823. *
  824. * @param {Object} pBuilder the builder to add to
  825. **/
  826. proto.addToBsonArray = function addToBsonArray(pBuilder) {
  827. if (false) throw new Error("this should never happen"); // these can't appear in arrays
  828. };
  829. /**
  830. * If this function is not overridden in the sub classes,
  831. * then throw an error
  832. *
  833. **/
  834. proto.getValue = function getValue() {
  835. throw new Error("You need to define this function on your accumulator");
  836. };
  837. },{"../expressions/NaryExpression":49}],9:[function(require,module,exports){
  838. "use strict";
  839. /**
  840. * Create an expression that finds the sum of n operands.
  841. * @class AddSoSetAccumulator
  842. * @namespace mungedb-aggregate.pipeline.accumulators
  843. * @module mungedb-aggregate
  844. * @constructor
  845. **/
  846. var AddToSetAccumulator = module.exports = function AddToSetAccumulator(/* ctx */){
  847. if (arguments.length !== 0) throw new Error("zero args expected");
  848. this.set = {};
  849. //this.itr = undefined; /* Shoudln't need an iterator for the set */
  850. //this.ctx = undefined; /* Not using the context object currently as it is related to sharding */
  851. base.call(this);
  852. }, klass = AddToSetAccumulator, Accumulator = require("./Accumulator"), base = Accumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  853. // PROTOTYPE MEMBERS
  854. proto.getOpName = function getOpName(){
  855. return "$addToSet";
  856. };
  857. proto.getFactory = function getFactory(){
  858. return klass; // using the ctor rather than a separate .create() method
  859. };
  860. proto.evaluate = function evaluate(doc) {
  861. if (arguments.length !== 1) throw new Error("One and only one arg expected");
  862. var rhs = this.operands[0].evaluate(doc);
  863. if (rhs === undefined) return;
  864. this.set[JSON.stringify(rhs)] = rhs;
  865. };
  866. proto.getValue = function getValue() {
  867. var setValues = [];
  868. for (var setKey in this.set) {
  869. setValues.push(this.set[setKey]);
  870. }
  871. return setValues;
  872. };
  873. },{"./Accumulator":8}],10:[function(require,module,exports){
  874. "use strict";
  875. /**
  876. * A class for constructing accumulators to calculate avg.
  877. * @class AvgAccumulator
  878. * @namespace mungedb-aggregate.pipeline.accumulators
  879. * @module mungedb-aggregate
  880. * @constructor
  881. **/
  882. var AvgAccumulator = module.exports = function AvgAccumulator(){
  883. this.subTotalName = "subTotal";
  884. this.countName = "count";
  885. this.totalIsANumber = true;
  886. base.call(this);
  887. }, klass = AvgAccumulator, SumAccumulator = require("./SumAccumulator"), base = SumAccumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  888. proto.getFactory = function getFactory(){
  889. return klass; // using the ctor rather than a separate .create() method
  890. };
  891. proto.getValue = function getValue(){
  892. if (this.totalIsANumber && this.count > 0) {
  893. return this.total / this.count;
  894. } else if (this.count === 0) {
  895. return 0;
  896. } else {
  897. throw new Error("$sum resulted in a non-numeric type");
  898. }
  899. };
  900. proto.getOpName = function getOpName(){
  901. return "$avg";
  902. };
  903. },{"./SumAccumulator":16}],11:[function(require,module,exports){
  904. "use strict";
  905. /**
  906. * Constructor for FirstAccumulator, wraps SingleValueAccumulator's constructor and adds flag to track whether we have started or not
  907. * @class FirstAccumulator
  908. * @namespace mungedb-aggregate.pipeline.accumulators
  909. * @module mungedb-aggregate
  910. * @constructor
  911. **/
  912. var FirstAccumulator = module.exports = function FirstAccumulator(){
  913. base.call(this);
  914. this.started = 0; //TODO: hack to get around falsy values making us keep going
  915. }, klass = FirstAccumulator, base = require("./SingleValueAccumulator"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  916. // PROTOTYPE MEMBERS
  917. proto.getOpName = function getOpName(){
  918. return "$first";
  919. };
  920. proto.getFactory = function getFactory(){
  921. return klass; // using the ctor rather than a separate .create() method
  922. };
  923. /**
  924. * Takes a document and returns the first value in the document
  925. * @param {Object} doc the document source
  926. * @return the first value
  927. **/
  928. proto.evaluate = function evaluate(doc){
  929. if (this.operands.length != 1) throw new Error("this should never happen");
  930. // only remember the first value seen
  931. if (!base.prototype.getValue.call(this) && this.started === 0) {
  932. this.value = this.operands[0].evaluate(doc);
  933. this.started = 1;
  934. }
  935. return this.value;
  936. };
  937. },{"./SingleValueAccumulator":15}],12:[function(require,module,exports){
  938. "use strict";
  939. /**
  940. * Constructor for LastAccumulator, wraps SingleValueAccumulator's constructor and finds the last document
  941. * @class LastAccumulator
  942. * @namespace mungedb-aggregate.pipeline.accumulators
  943. * @module mungedb-aggregate
  944. * @constructor
  945. **/
  946. var LastAccumulator = module.exports = function LastAccumulator(){
  947. base.call(this);
  948. }, klass = LastAccumulator, SingleValueAccumulator = require("./SingleValueAccumulator"), base = SingleValueAccumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  949. proto.evaluate = function evaluate(doc){
  950. if (this.operands.length != 1) throw new Error("this should never happen");
  951. this.value = this.operands[0].evaluate(doc);
  952. };
  953. proto.getOpName = function getOpName(){
  954. return "$last";
  955. };
  956. },{"./SingleValueAccumulator":15}],13:[function(require,module,exports){
  957. "use strict";
  958. /**
  959. * Constructor for MinMaxAccumulator, wraps SingleValueAccumulator's constructor and adds flag to track whether we have started or not
  960. * @class MinMaxAccumulator
  961. * @namespace mungedb-aggregate.pipeline.accumulators
  962. * @module mungedb-aggregate
  963. * @constructor
  964. **/
  965. var MinMaxAccumulator = module.exports = function MinMaxAccumulator(sense){
  966. if (arguments.length > 1) throw new Error("expects a single value");
  967. base.call(this);
  968. this.sense = sense; /* 1 for min, -1 for max; used to "scale" comparison */
  969. if (this.sense !== 1 && this.sense !== -1) throw new Error("this should never happen");
  970. }, klass = MinMaxAccumulator, base = require("./SingleValueAccumulator"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  971. // DEPENDENCIES
  972. var Value = require("../Value");
  973. // PROTOTYPE MEMBERS
  974. proto.getOpName = function getOpName(){
  975. if (this.sense == 1) return "$min";
  976. return "$max";
  977. };
  978. klass.createMin = function createMin(){
  979. return new MinMaxAccumulator(1);
  980. };
  981. klass.createMax = function createMax(){
  982. return new MinMaxAccumulator(-1);
  983. };
  984. /**
  985. * Takes a document and returns the first value in the document
  986. * @param {Object} doc the document source
  987. * @return the first value
  988. **/
  989. proto.evaluate = function evaluate(doc){
  990. if (this.operands.length != 1) throw new Error("this should never happen");
  991. var prhs = this.operands[0].evaluate(doc);
  992. // if this is the first value, just use it
  993. if (!this.hasOwnProperty('value')) {
  994. this.value = prhs;
  995. } else {
  996. // compare with the current value; swap if appropriate
  997. var cmp = Value.compare(this.value, prhs) * this.sense;
  998. if (cmp > 0) this.value = prhs;
  999. }
  1000. return this.value;
  1001. };
  1002. },{"../Value":7,"./SingleValueAccumulator":15}],14:[function(require,module,exports){
  1003. "use strict";
  1004. /**
  1005. * Constructor for PushAccumulator. Pushes items onto an array.
  1006. * @class PushAccumulator
  1007. * @namespace mungedb-aggregate.pipeline.accumulators
  1008. * @module mungedb-aggregate
  1009. * @constructor
  1010. **/
  1011. var PushAccumulator = module.exports = function PushAccumulator(){
  1012. this.values = [];
  1013. base.call(this);
  1014. }, klass = PushAccumulator, Accumulator = require("./Accumulator"), base = Accumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1015. proto.evaluate = function evaluate(doc){
  1016. if (this.operands.length != 1) throw new Error("this should never happen");
  1017. var v = this.operands[0].evaluate(doc);
  1018. if (v !== undefined) this.values.push(v);
  1019. return null;
  1020. };
  1021. proto.getValue = function getValue(){
  1022. return this.values;
  1023. };
  1024. proto.getOpName = function getOpName(){
  1025. return "$push";
  1026. };
  1027. },{"./Accumulator":8}],15:[function(require,module,exports){
  1028. "use strict";
  1029. /**
  1030. * This isn't a finished accumulator, but rather a convenient base class
  1031. * for others such as $first, $last, $max, $min, and similar. It just
  1032. * provides a holder for a single Value, and the getter for that. The
  1033. * holder is protected so derived classes can manipulate it.
  1034. *
  1035. * @class SingleValueAccumulator
  1036. * @namespace mungedb-aggregate.pipeline.accumulators
  1037. * @module mungedb-aggregate
  1038. * @constructor
  1039. **/
  1040. var SingleValueAccumulator = module.exports = function SingleValueAccumulator(){
  1041. if (arguments.length > 1) throw new Error("expects a single value");
  1042. base.call(this);
  1043. }, klass = SingleValueAccumulator, Accumulator = require("./Accumulator"), base = Accumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1044. // DEPENDENCIES
  1045. var Value = require("../Value");
  1046. proto.getValue = function getValue(){
  1047. return this.value;
  1048. };
  1049. },{"../Value":7,"./Accumulator":8}],16:[function(require,module,exports){
  1050. "use strict";
  1051. /**
  1052. * Accumulator for summing a field across documents
  1053. * @class SumAccumulator
  1054. * @namespace mungedb-aggregate.pipeline.accumulators
  1055. * @module mungedb-aggregate
  1056. * @constructor
  1057. **/
  1058. var SumAccumulator = module.exports = function SumAccumulator(){
  1059. this.total = 0;
  1060. this.count = 0;
  1061. this.totalIsANumber = true;
  1062. base.call(this);
  1063. }, klass = SumAccumulator, Accumulator = require("./Accumulator"), base = Accumulator, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1064. proto.evaluate = function evaluate(doc){
  1065. if (this.operands.length != 1) throw new Error("this should never happen");
  1066. var v = this.operands[0].evaluate(doc);
  1067. if (typeof v !== "number") { // do nothing with non-numeric types
  1068. return 0;
  1069. } else {
  1070. this.totalIsANumber = true;
  1071. this.total += v;
  1072. }
  1073. this.count++;
  1074. return 0;
  1075. };
  1076. proto.getValue = function getValue(){
  1077. if (this.totalIsANumber) {
  1078. return this.total;
  1079. }
  1080. throw new Error("$sum resulted in a non-numeric type");
  1081. };
  1082. proto.getOpName = function getOpName(){
  1083. return "$sum";
  1084. };
  1085. },{"./Accumulator":8}],17:[function(require,module,exports){
  1086. "use strict";
  1087. module.exports = {
  1088. Accumulator: require("./Accumulator"),
  1089. AddToSet: require("./AddToSetAccumulator"),
  1090. Avg: require("./AvgAccumulator"),
  1091. First: require("./FirstAccumulator"),
  1092. Last: require("./LastAccumulator"),
  1093. MinMax: require("./MinMaxAccumulator"),
  1094. Push: require("./PushAccumulator"),
  1095. Sum: require("./SumAccumulator")
  1096. };
  1097. },{"./Accumulator":8,"./AddToSetAccumulator":9,"./AvgAccumulator":10,"./FirstAccumulator":11,"./LastAccumulator":12,"./MinMaxAccumulator":13,"./PushAccumulator":14,"./SumAccumulator":16}],18:[function(require,module,exports){
  1098. (function (process){
  1099. "use strict";
  1100. /**
  1101. * Constructs and returns Documents from the objects produced by a supplied Cursor.
  1102. * An object of this type may only be used by one thread, see SERVER-6123.
  1103. *
  1104. * This is usually put at the beginning of a chain of document sources
  1105. * in order to fetch data from the database.
  1106. *
  1107. * @class CursorDocumentSource
  1108. * @namespace mungedb-aggregate.pipeline.documentSources
  1109. * @module mungedb-aggregate
  1110. * @constructor
  1111. * @param {CursorDocumentSource.CursorWithContext} cursorWithContext the cursor to use to fetch data
  1112. **/
  1113. var CursorDocumentSource = module.exports = CursorDocumentSource = function CursorDocumentSource(cursorWithContext, expCtx){
  1114. base.call(this, expCtx);
  1115. this.current = null;
  1116. // this.ns = null;
  1117. // /*
  1118. // The bson dependencies must outlive the Cursor wrapped by this
  1119. // source. Therefore, bson dependencies must appear before pCursor
  1120. // in order cause its destructor to be called *after* pCursor's.
  1121. // */
  1122. // this.query = null;
  1123. // this.sort = null;
  1124. this._projection = null;
  1125. this._cursorWithContext = cursorWithContext;
  1126. if (!this._cursorWithContext || !this._cursorWithContext._cursor) throw new Error("CursorDocumentSource requires a valid cursorWithContext");
  1127. }, klass = CursorDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1128. klass.CursorWithContext = (function (){
  1129. /**
  1130. * Holds a Cursor and all associated state required to access the cursor.
  1131. * @class CursorWithContext
  1132. * @namespace mungedb-aggregate.pipeline.documentSources.CursorDocumentSource
  1133. * @module mungedb-aggregate
  1134. * @constructor
  1135. **/
  1136. var klass = function CursorWithContext(ns){
  1137. this._cursor = null;
  1138. };
  1139. return klass;
  1140. })();
  1141. /**
  1142. * Release the Cursor and the read lock it requires, but without changing the other data.
  1143. * Releasing the lock is required for proper concurrency, see SERVER-6123. This
  1144. * functionality is also used by the explain version of pipeline execution.
  1145. *
  1146. * @method dispose
  1147. **/
  1148. proto.dispose = function dispose() {
  1149. this._cursorWithContext = null;
  1150. };
  1151. ///**
  1152. // * Record the namespace. Required for explain.
  1153. // *
  1154. // * @method setNamespace
  1155. // * @param {String} ns the namespace
  1156. // **/
  1157. //proto.setNamespace = function setNamespace(ns) {}
  1158. //
  1159. ///**
  1160. // * Record the query that was specified for the cursor this wraps, if any.
  1161. // * This should be captured after any optimizations are applied to
  1162. // * the pipeline so that it reflects what is really used.
  1163. // * This gets used for explain output.
  1164. // *
  1165. // * @method setQuery
  1166. // * @param {Object} pBsonObj the query to record
  1167. // **/
  1168. //proto.setQuery = function setQuery(pBsonObj) {};
  1169. //
  1170. //
  1171. ///**
  1172. // * Record the sort that was specified for the cursor this wraps, if any.
  1173. // * This should be captured after any optimizations are applied to
  1174. // * the pipeline so that it reflects what is really used.
  1175. // * This gets used for explain output.
  1176. // *
  1177. // * @method setSort
  1178. // * @param {Object} pBsonObj the query to record
  1179. // **/
  1180. //proto.setSort = function setSort(pBsonObj) {};
  1181. /**
  1182. * setProjection method
  1183. *
  1184. * @method setProjection
  1185. * @param {Object} projection
  1186. **/
  1187. proto.setProjection = function setProjection(projection) {
  1188. if (this._projection){
  1189. throw new Error("projection is already set");
  1190. }
  1191. //dont think we need this yet
  1192. // this._projection = new Projection();
  1193. // this._projection.init(projection);
  1194. //
  1195. // this.cursor().fields = this._projection;
  1196. this._projection = projection; //just for testing
  1197. };
  1198. //----------------virtuals from DocumentSource--------------
  1199. /**
  1200. * Is the source at EOF?
  1201. * @method eof
  1202. **/
  1203. proto.eof = function eof() {
  1204. if (!this.current) this.findNext(); // if we haven't gotten the first one yet, do so now
  1205. return (this.current === null);
  1206. };
  1207. /**
  1208. * Advance the state of the DocumentSource so that it will return the next Document.
  1209. * The default implementation returns false, after checking for interrupts.
  1210. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  1211. *
  1212. * @method advance
  1213. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  1214. **/
  1215. proto.advance = function advance() {
  1216. base.prototype.advance.call(this); // check for interrupts
  1217. if (!this.current) this.findNext(); // if we haven't gotten the first one yet, do so now
  1218. this.findNext();
  1219. return (this.current !== null);
  1220. };
  1221. /**
  1222. * some implementations do the equivalent of verify(!eof()) so check eof() first
  1223. * @method getCurrent
  1224. * @returns {Document} the current Document without advancing
  1225. **/
  1226. proto.getCurrent = function getCurrent() {
  1227. if (!this.current) this.findNext(); // if we haven't gotten the first one yet, do so now
  1228. return this.current;
  1229. };
  1230. /**
  1231. * Set the underlying source this source should use to get Documents
  1232. * from.
  1233. * It is an error to set the source more than once. This is to
  1234. * prevent changing sources once the original source has been started;
  1235. * this could break the state maintained by the DocumentSource.
  1236. * This pointer is not reference counted because that has led to
  1237. * some circular references. As a result, this doesn't keep
  1238. * sources alive, and is only intended to be used temporarily for
  1239. * the lifetime of a Pipeline::run().
  1240. *
  1241. * @method setSource
  1242. * @param source {DocumentSource} the underlying source to use
  1243. * @param callback {Function} a `mungedb-aggregate`-specific extension to the API to half-way support reading from async sources
  1244. **/
  1245. proto.setSource = function setSource(theSource, callback) {
  1246. if (theSource) throw new Error("CursorDocumentSource doesn't take a source"); //TODO: This needs to put back without the if once async is fully and properly supported
  1247. if (callback) return process.nextTick(callback);
  1248. };
  1249. /**
  1250. * Create an object that represents the document source. The object
  1251. * will have a single field whose name is the source's name. This
  1252. * will be used by the default implementation of addToBsonArray()
  1253. * to add this object to a pipeline being represented in BSON.
  1254. *
  1255. * @method sourceToJson
  1256. * @param {Object} pBuilder BSONObjBuilder: a blank object builder to write to
  1257. * @param {Boolean} explain create explain output
  1258. **/
  1259. proto.sourceToJson = function sourceToJson(pBuilder, explain) {
  1260. /* this has no analog in the BSON world, so only allow it for explain */
  1261. //if (explain){
  1262. ////we are not currently supporting explain in mungedb-aggregate
  1263. //}
  1264. };
  1265. //----------------private--------------
  1266. proto.findNext = function findNext(){
  1267. if ( !this._cursorWithContext ) {
  1268. this.current = null;
  1269. return;
  1270. }
  1271. for( ; this.cursor().ok(); this.cursor().advance() ) {
  1272. //yieldSometimes();
  1273. // if ( !this.cursor().ok() ) {
  1274. // // The cursor was exhausted during the yield.
  1275. // break;
  1276. // }
  1277. // if ( !this.cursor().currentMatches() || this.cursor().currentIsDup() )
  1278. // continue;
  1279. // grab the matching document
  1280. var documentObj;
  1281. // if (this.canUseCoveredIndex()) { ... Dont need any of this, I think
  1282. documentObj = this.cursor().current();
  1283. this.current = documentObj;
  1284. this.cursor().advance();
  1285. return;
  1286. }
  1287. // If we got here, there aren't any more documents.
  1288. // The CursorWithContext (and its read lock) must be released, see SERVER-6123.
  1289. this.dispose();
  1290. this.current = null;
  1291. };
  1292. proto.cursor = function cursor(){
  1293. if( this._cursorWithContext && this._cursorWithContext._cursor){
  1294. return this._cursorWithContext._cursor;
  1295. }
  1296. throw new Error("cursor not defined");
  1297. };
  1298. //proto.chunkMgr = function chunkMgr(){};
  1299. //proto.canUseCoveredIndex = function canUseCoveredIndex(){};
  1300. //proto.yieldSometimes = function yieldSometimes(){};
  1301. }).call(this,require('_process'))
  1302. },{"./DocumentSource":19,"_process":65}],19:[function(require,module,exports){
  1303. "use strict";
  1304. /**
  1305. * A base class for all document sources
  1306. * @class DocumentSource
  1307. * @namespace mungedb-aggregate.pipeline.documentSources
  1308. * @module mungedb-aggregate
  1309. * @constructor
  1310. * @param expCtx {ExpressionContext}
  1311. **/
  1312. var DocumentSource = module.exports = function DocumentSource(expCtx){
  1313. if(arguments.length !== 1) throw new Error("one arg expected");
  1314. /*
  1315. * Most DocumentSources have an underlying source they get their data
  1316. * from. This is a convenience for them.
  1317. * The default implementation of setSource() sets this; if you don't
  1318. * need a source, override that to verify(). The default is to
  1319. * verify() if this has already been set.
  1320. */
  1321. this.source = null;
  1322. /*
  1323. * The zero-based user-specified pipeline step. Used for diagnostics.
  1324. * Will be set to -1 for artificial pipeline steps that were not part
  1325. * of the original user specification.
  1326. */
  1327. this.step = -1;
  1328. this.expCtx = expCtx || {};
  1329. /*
  1330. * for explain: # of rows returned by this source
  1331. * This is *not* unsigned so it can be passed to JSONObjBuilder.append().
  1332. */
  1333. this.nRowsOut = 0;
  1334. }, klass = DocumentSource, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1335. /*
  1336. class DocumentSource :
  1337. public IntrusiveCounterUnsigned,
  1338. public StringWriter {
  1339. public:
  1340. virtual ~DocumentSource();
  1341. // virtuals from StringWriter
  1342. virtual void writeString(stringstream &ss) const;
  1343. */
  1344. /**
  1345. * Set the step for a user-specified pipeline step.
  1346. * @method setPipelineStep
  1347. * @param {Number} step number 0 to n.
  1348. **/
  1349. proto.setPipelineStep = function setPipelineStep(step) {
  1350. this.step = step;
  1351. };
  1352. /**
  1353. * Get the user-specified pipeline step.
  1354. * @method getPipelineStep
  1355. * @returns {Number} step
  1356. **/
  1357. proto.getPipelineStep = function getPipelineStep() {
  1358. return this.step;
  1359. };
  1360. /**
  1361. * Is the source at EOF?
  1362. * @method eof
  1363. **/
  1364. proto.eof = function eof() {
  1365. throw new Error("not implemented");
  1366. };
  1367. /**
  1368. * Advance the state of the DocumentSource so that it will return the next Document.
  1369. * The default implementation returns false, after checking for interrupts.
  1370. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  1371. *
  1372. * @method advance
  1373. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  1374. **/
  1375. proto.advance = function advance() {
  1376. //pExpCtx->checkForInterrupt(); // might not return
  1377. return false;
  1378. };
  1379. /**
  1380. * some implementations do the equivalent of verify(!eof()) so check eof() first
  1381. * @method getCurrent
  1382. * @returns {Document} the current Document without advancing
  1383. **/
  1384. proto.getCurrent = function getCurrent() {
  1385. throw new Error("not implemented");
  1386. };
  1387. /**
  1388. * Inform the source that it is no longer needed and may release its resources. After
  1389. * dispose() is called the source must still be able to handle iteration requests, but may
  1390. * become eof().
  1391. * NOTE: For proper mutex yielding, dispose() must be called on any DocumentSource that will
  1392. * not be advanced until eof(), see SERVER-6123.
  1393. *
  1394. * @method dispose
  1395. **/
  1396. proto.dispose = function dispose() {
  1397. if ( this.source ) {
  1398. // This is required for the DocumentSourceCursor to release its read lock, see
  1399. // SERVER-6123.
  1400. this.source.dispose();
  1401. }
  1402. };
  1403. /**
  1404. * Get the source's name.
  1405. * @method getSourceName
  1406. * @returns {String} the string name of the source as a constant string; this is static, and there's no need to worry about adopting it
  1407. **/
  1408. proto.getSourceName = function getSourceName() {
  1409. return "[UNKNOWN]";
  1410. };
  1411. /**
  1412. * Set the underlying source this source should use to get Documents
  1413. * from.
  1414. * It is an error to set the source more than once. This is to
  1415. * prevent changing sources once the original source has been started;
  1416. * this could break the state maintained by the DocumentSource.
  1417. * This pointer is not reference counted because that has led to
  1418. * some circular references. As a result, this doesn't keep
  1419. * sources alive, and is only intended to be used temporarily for
  1420. * the lifetime of a Pipeline::run().
  1421. *
  1422. * @method setSource
  1423. * @param {DocumentSource} source the underlying source to use
  1424. **/
  1425. proto.setSource = function setSource(theSource, callback) {
  1426. if (this.source) throw new Error("It is an error to set the source more than once");
  1427. this.source = theSource;
  1428. if (callback) return setTimeout(callback, 0);
  1429. };
  1430. /**
  1431. * Attempt to coalesce this DocumentSource with its successor in the
  1432. * document processing pipeline. If successful, the successor
  1433. * DocumentSource should be removed from the pipeline and discarded.
  1434. * If successful, this operation can be applied repeatedly, in an
  1435. * attempt to coalesce several sources together.
  1436. * The default implementation is to do nothing, and return false.
  1437. *
  1438. * @method coalesce
  1439. * @param {DocumentSource} nextSource the next source in the document processing chain.
  1440. * @returns {Boolean} whether or not the attempt to coalesce was successful or not; if the attempt was not successful, nothing has been changed
  1441. **/
  1442. proto.coalesce = function coalesce(nextSource) {
  1443. return false;
  1444. };
  1445. /**
  1446. * Optimize the pipeline operation, if possible. This is a local
  1447. * optimization that only looks within this DocumentSource. For best
  1448. * results, first coalesce compatible sources using coalesce().
  1449. * This is intended for any operations that include expressions, and
  1450. * provides a hook for those to optimize those operations.
  1451. * The default implementation is to do nothing.
  1452. *
  1453. * @method optimize
  1454. **/
  1455. proto.optimize = function optimize() {
  1456. };
  1457. klass.GetDepsReturn = {
  1458. NOT_SUPPORTED: "NOT_SUPPORTED", // This means the set should be ignored
  1459. EXHAUSTIVE: "EXHAUSTIVE", // This means that everything needed should be in the set
  1460. SEE_NEXT: "SEE_NEXT" // Add the next Source's deps to the set
  1461. };
  1462. /**
  1463. * Get the fields this operation needs to do its job.
  1464. * Deps should be in "a.b.c" notation
  1465. *
  1466. * @method getDependencies
  1467. * @param {Object} deps set (unique array) of strings
  1468. * @returns DocumentSource.GetDepsReturn
  1469. **/
  1470. proto.getDependencies = function getDependencies(deps) {
  1471. return klass.GetDepsReturn.NOT_SUPPORTED;
  1472. };
  1473. /**
  1474. * This takes dependencies from getDependencies and
  1475. * returns a projection that includes all of them
  1476. *
  1477. * @method depsToProjection
  1478. * @param {Object} deps set (unique array) of strings
  1479. * @returns {Object} JSONObj
  1480. **/
  1481. klass.depsToProjection = function depsToProjection(deps) {
  1482. var bb = {};
  1483. if (deps._id === undefined)
  1484. bb._id = 0;
  1485. var last = "";
  1486. Object.keys(deps).sort().forEach(function(it){
  1487. if (last !== "" && it.slice(0, last.length) === last){
  1488. // we are including a parent of *it so we don't need to
  1489. // include this field explicitly. In fact, due to
  1490. // SERVER-6527 if we included this field, the parent
  1491. // wouldn't be fully included.
  1492. return;
  1493. }
  1494. last = it + ".";
  1495. bb[it] = 1;
  1496. });
  1497. return bb;
  1498. };
  1499. /**
  1500. * Add the DocumentSource to the array builder.
  1501. * The default implementation calls sourceToJson() in order to
  1502. * convert the inner part of the object which will be added to the
  1503. * array being built here.
  1504. *
  1505. * @method addToJsonArray
  1506. * @param {Array} pBuilder JSONArrayBuilder: the array builder to add the operation to.
  1507. * @param {Boolean} explain create explain output
  1508. * @returns {Object}
  1509. **/
  1510. proto.addToJsonArray = function addToJsonArray(pBuilder, explain) {
  1511. pBuilder.push(this.sourceToJson({}, explain));
  1512. };
  1513. /**
  1514. * Create an object that represents the document source. The object
  1515. * will have a single field whose name is the source's name. This
  1516. * will be used by the default implementation of addToJsonArray()
  1517. * to add this object to a pipeline being represented in JSON.
  1518. *
  1519. * @method sourceToJson
  1520. * @param {Object} pBuilder JSONObjBuilder: a blank object builder to write to
  1521. * @param {Boolean} explain create explain output
  1522. **/
  1523. proto.sourceToJson = function sourceToJson(pBuilder, explain) {
  1524. throw new Error("not implemented");
  1525. };
  1526. /**
  1527. * Convert the DocumentSource instance to it's JSON Object representation; Used by the standard JSON.stringify() function
  1528. * @method toJSON
  1529. * @return {String} a JSON-encoded String that represents the DocumentSource
  1530. **/
  1531. proto.toJSON = function toJSON(){
  1532. var obj = {};
  1533. this.sourceToJson(obj);
  1534. return obj;
  1535. };
  1536. },{}],20:[function(require,module,exports){
  1537. "use strict";
  1538. /**
  1539. * A base class for filter document sources
  1540. * @class FilterBaseDocumentSource
  1541. * @namespace mungedb-aggregate.pipeline.documentSources
  1542. * @module mungedb-aggregate
  1543. * @constructor
  1544. * @param [ctx] {ExpressionContext}
  1545. **/
  1546. var FilterBaseDocumentSource = module.exports = function FilterBaseDocumentSource(ctx){
  1547. if (arguments.length > 1) throw new Error("up to one arg expected");
  1548. base.call(this, ctx);
  1549. this.unstarted = true;
  1550. this.hasNext = false;
  1551. this.current = null;
  1552. }, klass = FilterBaseDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1553. //TODO: Need to implement coalesce()
  1554. //TODO: Need to implement optimize()
  1555. /**
  1556. * Find the next acceptable source document, if there are any left.
  1557. * @method findNext
  1558. **/
  1559. proto.findNext = function findNext() {
  1560. /* only do this the first time */
  1561. if (this.unstarted) {
  1562. this.hasNext = !this.source.eof();
  1563. this.unstarted = false;
  1564. }
  1565. while(this.hasNext) {
  1566. var document = this.source.getCurrent();
  1567. this.hasNext = this.source.advance();
  1568. if (this.accept(document)) {
  1569. this.current = document;
  1570. return;
  1571. }
  1572. }
  1573. this.current = null;
  1574. };
  1575. /**
  1576. * Is the source at EOF?
  1577. * @method eof
  1578. **/
  1579. proto.eof = function eof() {
  1580. if (this.unstarted)
  1581. this.findNext();
  1582. return (this.current === null);
  1583. };
  1584. /**
  1585. * Advance the state of the DocumentSource so that it will return the next Document.
  1586. * The default implementation returns false, after checking for interrupts.
  1587. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  1588. *
  1589. * @method advance
  1590. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  1591. **/
  1592. proto.advance = function advance() {
  1593. base.prototype.advance.call(this); // check for interrupts
  1594. if (this.unstarted)
  1595. this.findNext();
  1596. /**
  1597. * This looks weird after the above, but is correct. Note that calling
  1598. * getCurrent() when first starting already yields the first document
  1599. * in the collection. Calling advance() without using getCurrent()
  1600. * first will skip over the first item.
  1601. **/
  1602. this.findNext();
  1603. return (this.current !== null);
  1604. };
  1605. /**
  1606. * some implementations do the equivalent of verify(!eof()) so check eof() first
  1607. * @method getCurrent
  1608. * @returns {Document} the current Document without advancing
  1609. **/
  1610. proto.getCurrent = function getCurrent() {
  1611. if (this.unstarted)
  1612. this.findNext();
  1613. if (this.current === null) throw new Error("This should never happen");
  1614. return this.current;
  1615. };
  1616. /**
  1617. * Test the given document against the predicate and report if it should be accepted or not.
  1618. * @param {object} document the document to test
  1619. * @returns {bool} true if the document matches the filter, false otherwise
  1620. **/
  1621. proto.accept = function accept(document) {
  1622. throw new Error("not implemented");
  1623. };
  1624. /**
  1625. * Create a JSONObj suitable for Matcher construction.
  1626. *
  1627. * This is used after filter analysis has moved as many filters to
  1628. * as early a point as possible in the document processing pipeline.
  1629. * See db/Matcher.h and the associated wiki documentation for the
  1630. * format. This conversion is used to move back to the low-level
  1631. * find() Cursor mechanism.
  1632. *
  1633. * @param builder the builder to write to
  1634. **/
  1635. proto.toMatcherJson = function toMatcherJson(builder) {
  1636. throw new Error("not implemented");
  1637. };
  1638. },{"./DocumentSource":19}],21:[function(require,module,exports){
  1639. "use strict";
  1640. var DocumentSource = require("./DocumentSource"),
  1641. Accumulators = require("../accumulators/"),
  1642. Document = require("../Document"),
  1643. Expression = require("../expressions/Expression"),
  1644. ConstantExpression = require("../expressions/ConstantExpression"),
  1645. FieldPathExpression = require("../expressions/FieldPathExpression");
  1646. /**
  1647. * A class for grouping documents together
  1648. * @class GroupDocumentSource
  1649. * @namespace mungedb-aggregate.pipeline.documentSources
  1650. * @module mungedb-aggregate
  1651. * @constructor
  1652. * @param [ctx] {ExpressionContext}
  1653. **/
  1654. var GroupDocumentSource = module.exports = function GroupDocumentSource(expCtx) {
  1655. if (arguments.length > 1) throw new Error("up to one arg expected");
  1656. base.call(this, expCtx);
  1657. this.populated = false;
  1658. this.idExpression = null;
  1659. this.groups = {}; // GroupsType Value -> Accumulators[]
  1660. this.groupsKeys = []; // This is to faciliate easier look up of groups
  1661. this.originalGroupsKeys = []; // This stores the original group key un-hashed/stringified/whatever
  1662. this.fieldNames = [];
  1663. this.accumulatorFactories = [];
  1664. this.expressions = [];
  1665. this.currentDocument = null;
  1666. this.currentGroupsKeysIndex = 0;
  1667. }, klass = GroupDocumentSource, base = DocumentSource, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1668. klass.groupOps = {
  1669. "$addToSet": Accumulators.AddToSet,
  1670. "$avg": Accumulators.Avg,
  1671. "$first": Accumulators.First,
  1672. "$last": Accumulators.Last,
  1673. "$max": Accumulators.MinMax.createMax,
  1674. "$min": Accumulators.MinMax.createMin,
  1675. "$push": Accumulators.Push,
  1676. "$sum": Accumulators.Sum
  1677. };
  1678. klass.groupName = "$group";
  1679. proto.getSourceName = function getSourceName() {
  1680. return klass.groupName;
  1681. };
  1682. /**
  1683. * Create an object that represents the document source. The object
  1684. * will have a single field whose name is the source's name. This
  1685. * will be used by the default implementation of addToJsonArray()
  1686. * to add this object to a pipeline being represented in JSON.
  1687. *
  1688. * @method sourceToJson
  1689. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  1690. * @param {Boolean} explain create explain output
  1691. **/
  1692. proto.sourceToJson = function sourceToJson(builder, explain) {
  1693. var idExp = this.idExpression,
  1694. insides = {
  1695. _id: idExp ? idExp.toJSON() : {}
  1696. },
  1697. aFac = this.accumulatorFactories,
  1698. aFacLen = aFac.length;
  1699. for(var i=0; i < aFacLen; ++i) {
  1700. var acc = new aFac[i](/*pExpCtx*/);
  1701. acc.addOperand(this.expressions[i]);
  1702. insides[this.fieldNames[i]] = acc.toJSON(true);
  1703. }
  1704. builder[this.getSourceName()] = insides;
  1705. };
  1706. klass.createFromJson = function createFromJson(groupObj, ctx) {
  1707. if (!(groupObj instanceof Object && groupObj.constructor === Object)) throw new Error("a group's fields must be specified in an object");
  1708. var idSet = false,
  1709. group = new GroupDocumentSource(ctx);
  1710. for (var groupFieldName in groupObj) {
  1711. if (groupObj.hasOwnProperty(groupFieldName)) {
  1712. var groupField = groupObj[groupFieldName];
  1713. if (groupFieldName === "_id") {
  1714. if(idSet) throw new Error("15948 a group's _id may only be specified once");
  1715. if (groupField instanceof Object && groupField.constructor === Object) {
  1716. var objCtx = new Expression.ObjectCtx({isDocumentOk:true});
  1717. group.idExpression = Expression.parseObject(groupField, objCtx);
  1718. idSet = true;
  1719. } else if (typeof groupField === "string") {
  1720. if (groupField[0] !== "$") {
  1721. group.idExpression = new ConstantExpression(groupField);
  1722. } else {
  1723. var pathString = Expression.removeFieldPrefix(groupField);
  1724. group.idExpression = new FieldPathExpression(pathString);
  1725. }
  1726. idSet = true;
  1727. } else {
  1728. var typeStr = group._getTypeStr(groupField);
  1729. switch (typeStr) {
  1730. case "number":
  1731. case "string":
  1732. case "boolean":
  1733. case "Object":
  1734. case "object": // null returns "object" Xp
  1735. case "Array":
  1736. group.idExpression = new ConstantExpression(groupField);
  1737. idSet = true;
  1738. break;
  1739. default:
  1740. throw new Error("a group's _id may not include fields of type " + typeStr + "");
  1741. }
  1742. }
  1743. } else {
  1744. if (groupFieldName.indexOf(".") !== -1) throw new Error("16414 the group aggregate field name '" + groupFieldName + "' cannot contain '.'");
  1745. if (groupFieldName[0] === "$") throw new Error("15950 the group aggregate field name '" + groupFieldName + "' cannot be an operator name");
  1746. if (group._getTypeStr(groupFieldName) === "Object") throw new Error("15951 the group aggregate field '" + groupFieldName + "' must be defined as an expression inside an object");
  1747. var subFieldCount = 0;
  1748. for (var subFieldName in groupField) {
  1749. if (groupField.hasOwnProperty(subFieldName)) {
  1750. var subField = groupField[subFieldName],
  1751. op = klass.groupOps[subFieldName];
  1752. if (!op) throw new Error("15952 unknown group operator '" + subFieldName + "'");
  1753. var groupExpression,
  1754. subFieldTypeStr = group._getTypeStr(subField);
  1755. if (subFieldTypeStr === "Object") {
  1756. var subFieldObjCtx = new Expression.ObjectCtx({isDocumentOk:true});
  1757. groupExpression = Expression.parseObject(subField, subFieldObjCtx);
  1758. } else if (subFieldTypeStr === "Array") {
  1759. throw new Error("15953 aggregating group operators are unary (" + subFieldName + ")");
  1760. } else {
  1761. groupExpression = Expression.parseOperand(subField);
  1762. }
  1763. group.addAccumulator(groupFieldName,op, groupExpression);
  1764. ++subFieldCount;
  1765. }
  1766. }
  1767. if (subFieldCount != 1) throw new Error("15954 the computed aggregate '" + groupFieldName + "' must specify exactly one operator");
  1768. }
  1769. }
  1770. }
  1771. if (!idSet) throw new Error("15955 a group specification must include an _id");
  1772. return group;
  1773. };
  1774. proto._getTypeStr = function _getTypeStr(obj) {
  1775. var typeofStr = typeof obj,
  1776. typeStr = (typeofStr == "object" && obj !== null) ? obj.constructor.name : typeofStr;
  1777. return typeStr;
  1778. };
  1779. proto.advance = function advance() {
  1780. base.prototype.advance.call(this); // Check for interupts ????
  1781. if(!this.populated) this.populate();
  1782. //verify(this.currentGroupsKeysIndex < this.groupsKeys.length);
  1783. ++this.currentGroupsKeysIndex;
  1784. if (this.currentGroupsKeysIndex >= this.groupsKeys.length) {
  1785. this.currentDocument = null;
  1786. return false;
  1787. }
  1788. this.currentDocument = this.makeDocument(this.currentGroupsKeysIndex);
  1789. return true;
  1790. };
  1791. proto.eof = function eof() {
  1792. if (!this.populated) this.populate();
  1793. return this.currentGroupsKeysIndex === this.groupsKeys.length;
  1794. };
  1795. proto.getCurrent = function getCurrent() {
  1796. if (!this.populated) this.populate();
  1797. return this.currentDocument;
  1798. };
  1799. proto.getDependencies = function getDependencies(deps) {
  1800. var self = this;
  1801. // add _id
  1802. this.idExpression.addDependencies(deps);
  1803. // add the rest
  1804. this.fieldNames.forEach(function (field, i) {
  1805. self.expressions[i].addDependencies(deps);
  1806. });
  1807. return DocumentSource.GetDepsReturn.EXHAUSTIVE;
  1808. };
  1809. proto.addAccumulator = function addAccumulator(fieldName, accumulatorFactory, expression) {
  1810. this.fieldNames.push(fieldName);
  1811. this.accumulatorFactories.push(accumulatorFactory);
  1812. this.expressions.push(expression);
  1813. };
  1814. proto.populate = function populate() {
  1815. for (var hasNext = !this.source.eof(); hasNext; hasNext = this.source.advance()) {
  1816. var group,
  1817. currentDocument = this.source.getCurrent(),
  1818. _id = this.idExpression.evaluate(currentDocument);
  1819. if (undefined === _id) _id = null;
  1820. var idHash = JSON.stringify(_id); //TODO: USE A REAL HASH. I didn't have time to take collision into account.
  1821. if (idHash in this.groups) {
  1822. group = this.groups[idHash];
  1823. } else {
  1824. this.groups[idHash] = group = [];
  1825. this.groupsKeys[this.currentGroupsKeysIndex] = idHash;
  1826. this.originalGroupsKeys[this.currentGroupsKeysIndex] = (_id && typeof _id === 'object') ? Document.clone(_id) : _id;
  1827. ++this.currentGroupsKeysIndex;
  1828. for (var ai = 0; ai < this.accumulatorFactories.length; ++ai) {
  1829. var accumulator = new this.accumulatorFactories[ai]();
  1830. accumulator.addOperand(this.expressions[ai]);
  1831. group.push(accumulator);
  1832. }
  1833. }
  1834. // tickle all the accumulators for the group we found
  1835. for (var gi = 0; gi < group.length; ++gi) {
  1836. group[gi].evaluate(currentDocument);
  1837. }
  1838. }
  1839. this.currentGroupsKeysIndex = 0; // Start the group
  1840. if (this.groupsKeys.length > 0) {
  1841. this.currentDocument = this.makeDocument(this.currentGroupsKeysIndex);
  1842. }
  1843. this.populated = true;
  1844. };
  1845. proto.makeDocument = function makeDocument(groupKeyIndex) {
  1846. var groupKey = this.groupsKeys[groupKeyIndex],
  1847. originalGroupKey = this.originalGroupsKeys[groupKeyIndex],
  1848. group = this.groups[groupKey],
  1849. doc = {};
  1850. doc[Document.ID_PROPERTY_NAME] = originalGroupKey;
  1851. for (var i = 0; i < this.fieldNames.length; ++i) {
  1852. var fieldName = this.fieldNames[i],
  1853. item = group[i];
  1854. if (item !== "null" && item !== undefined) {
  1855. doc[fieldName] = item.getValue();
  1856. }
  1857. }
  1858. return doc;
  1859. };
  1860. },{"../Document":3,"../accumulators/":17,"../expressions/ConstantExpression":35,"../expressions/Expression":40,"../expressions/FieldPathExpression":41,"./DocumentSource":19}],22:[function(require,module,exports){
  1861. "use strict";
  1862. /**
  1863. * A document source limiter
  1864. * @class LimitDocumentSource
  1865. * @namespace mungedb-aggregate.pipeline.documentSources
  1866. * @module mungedb-aggregate
  1867. * @constructor
  1868. * @param [ctx] {ExpressionContext}
  1869. **/
  1870. var LimitDocumentSource = module.exports = function LimitDocumentSource(ctx){
  1871. if (arguments.length > 1) throw new Error("up to one arg expected");
  1872. base.call(this, ctx);
  1873. this.limit = 0;
  1874. this.count = 0;
  1875. }, klass = LimitDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1876. klass.limitName = "$limit";
  1877. proto.getSourceName = function getSourceName(){
  1878. return klass.limitName;
  1879. };
  1880. proto.getFactory = function getFactory(){
  1881. return klass; // using the ctor rather than a separate .create() method
  1882. };
  1883. /**
  1884. * Coalesce limits together
  1885. * @param {Object} nextSource the next source
  1886. * @return {bool} return whether we can coalese together
  1887. **/
  1888. proto.coalesce = function coalesce(nextSource) {
  1889. var nextLimit = nextSource.constructor === LimitDocumentSource?nextSource:null;
  1890. // if it's not another $limit, we can't coalesce
  1891. if (!nextLimit) return false;
  1892. // we need to limit by the minimum of the two limits
  1893. if (nextLimit.limit < this.limit) this.limit = nextLimit.limit;
  1894. return true;
  1895. };
  1896. /**
  1897. * Is the source at EOF?
  1898. * @method eof
  1899. **/
  1900. proto.eof = function eof() {
  1901. return this.source.eof() || this.count >= this.limit;
  1902. };
  1903. /**
  1904. * some implementations do the equivalent of verify(!eof()) so check eof() first
  1905. * @method getCurrent
  1906. * @returns {Document} the current Document without advancing
  1907. **/
  1908. proto.getCurrent = function getCurrent() {
  1909. return this.source.getCurrent();
  1910. };
  1911. /**
  1912. * Advance the state of the DocumentSource so that it will return the next Document.
  1913. * The default implementation returns false, after checking for interrupts.
  1914. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  1915. *
  1916. * @method advance
  1917. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  1918. **/
  1919. proto.advance = function advance() {
  1920. base.prototype.advance.call(this); // check for interrupts
  1921. ++this.count;
  1922. if (this.count >= this.limit) {
  1923. return false;
  1924. }
  1925. this.current = this.source.getCurrent();
  1926. return this.source.advance();
  1927. };
  1928. /**
  1929. * Create an object that represents the document source. The object
  1930. * will have a single field whose name is the source's name. This
  1931. * will be used by the default implementation of addToJsonArray()
  1932. * to add this object to a pipeline being represented in JSON.
  1933. *
  1934. * @method sourceToJson
  1935. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  1936. * @param {Boolean} explain create explain output
  1937. **/
  1938. proto.sourceToJson = function sourceToJson(builder, explain) {
  1939. builder.$limit = this.limit;
  1940. };
  1941. /**
  1942. * Creates a new LimitDocumentSource with the input number as the limit
  1943. * @param {Number} JsonElement this thing is *called* Json, but it expects a number
  1944. **/
  1945. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  1946. if (typeof jsonElement !== "number") throw new Error("code 15957; the limit must be specified as a number");
  1947. var Limit = proto.getFactory(),
  1948. nextLimit = new Limit(ctx);
  1949. nextLimit.limit = jsonElement;
  1950. if ((nextLimit.limit <= 0) || isNaN(nextLimit.limit)) throw new Error("code 15958; the limit must be positive");
  1951. return nextLimit;
  1952. };
  1953. },{"./DocumentSource":19}],23:[function(require,module,exports){
  1954. "use strict";
  1955. var sift = require("sift"); //TODO: DEVIATION FROM MONGO: this was a temporary hack to get this done quickly but it is too inconsistent to keep; need a real port of MatchDocumentSource
  1956. /**
  1957. * A match document source built off of FilterBaseDocumentSource
  1958. *
  1959. * NOTE: THIS IS A DEVIATION FROM THE MONGO IMPLEMENTATION.
  1960. * TODO: internally uses `sift` to fake it, which has bugs, so we need to reimplement this by porting the MongoDB implementation
  1961. *
  1962. * @class MatchDocumentSource
  1963. * @namespace mungedb-aggregate.pipeline.documentSources
  1964. * @module mungedb-aggregate
  1965. * @constructor
  1966. * @param {Object} query the match query to use
  1967. * @param [ctx] {ExpressionContext}
  1968. **/
  1969. var MatchDocumentSource = module.exports = function MatchDocumentSource(query, ctx){
  1970. if (arguments.length > 2) throw new Error("up to two args expected");
  1971. if (!query) throw new Error("arg `query` is required");
  1972. base.call(this, ctx);
  1973. this.query = query; // save the query, so we can check it for deps later. THIS IS A DEVIATION FROM THE MONGO IMPLEMENTATION
  1974. this.matcher = sift(query);
  1975. }, klass = MatchDocumentSource, base = require('./FilterBaseDocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  1976. klass.matchName = "$match";
  1977. proto.getSourceName = function getSourceName(){
  1978. return klass.matchName;
  1979. };
  1980. /**
  1981. * Create an object that represents the document source. The object
  1982. * will have a single field whose name is the source's name. This
  1983. * will be used by the default implementation of addToJsonArray()
  1984. * to add this object to a pipeline being represented in JSON.
  1985. *
  1986. * @method sourceToJson
  1987. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  1988. * @param {Boolean} explain create explain output
  1989. **/
  1990. proto.sourceToJson = function sourceToJson(builder, explain) {
  1991. builder[this.getSourceName()] = this.matcher.query;
  1992. };
  1993. /**
  1994. * Test the given document against the predicate and report if it should be accepted or not.
  1995. * @param {object} document the document to test
  1996. * @returns {bool} true if the document matches the filter, false otherwise
  1997. **/
  1998. proto.accept = function accept(document) {
  1999. /**
  2000. * The matcher only takes BSON documents, so we have to make one.
  2001. *
  2002. * LATER
  2003. * We could optimize this by making a document with only the
  2004. * fields referenced by the Matcher. We could do this by looking inside
  2005. * the Matcher's BSON before it is created, and recording those. The
  2006. * easiest implementation might be to hold onto an ExpressionDocument
  2007. * in here, and give that pDocument to create the created subset of
  2008. * fields, and then convert that instead.
  2009. **/
  2010. return this.matcher.test(document);
  2011. };
  2012. /**
  2013. * Create a JSONObj suitable for Matcher construction.
  2014. *
  2015. * This is used after filter analysis has moved as many filters to
  2016. * as early a point as possible in the document processing pipeline.
  2017. * See db/Matcher.h and the associated wiki documentation for the
  2018. * format. This conversion is used to move back to the low-level
  2019. * find() Cursor mechanism.
  2020. *
  2021. * @param builder the builder to write to
  2022. **/
  2023. proto.toMatcherJson = function toMatcherJson(builder) {
  2024. var q = this.matcher.query;
  2025. for(var k in q){
  2026. builder[k] = q[k];
  2027. }
  2028. };
  2029. klass.uassertNoDisallowedClauses = function uassertNoDisallowedClauses(query) {
  2030. for(var key in query){
  2031. if(query.hasOwnProperty(key)){
  2032. // can't use the Matcher API because this would segfault the constructor
  2033. if (query[key] == "$where") throw new Error("code 16395; $where is not allowed inside of a $match aggregation expression");
  2034. // geo breaks if it is not the first portion of the pipeline
  2035. if (query[key] == "$near") throw new Error("code 16424; $near is not allowed inside of a $match aggregation expression");
  2036. if (query[key] == "$within") throw new Error("code 16425; $within is not allowed inside of a $match aggregation expression");
  2037. if (query[key] == "$nearSphere") throw new Error("code 16426; $nearSphere is not allowed inside of a $match aggregation expression");
  2038. if (query[key] instanceof Object && query[key].constructor === Object) this.uassertNoDisallowedClauses(query[key]);
  2039. }
  2040. }
  2041. };
  2042. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  2043. if (!(jsonElement instanceof Object) || jsonElement.constructor !== Object) throw new Error("code 15959 ; the match filter must be an expression in an object");
  2044. klass.uassertNoDisallowedClauses(jsonElement);
  2045. var matcher = new MatchDocumentSource(jsonElement, ctx);
  2046. return matcher;
  2047. };
  2048. },{"./FilterBaseDocumentSource":20,"sift":64}],24:[function(require,module,exports){
  2049. "use strict";
  2050. /**
  2051. * A base class for filter document sources
  2052. * @class ProjectDocumentSource
  2053. * @namespace mungedb-aggregate.pipeline.documentSources
  2054. * @module mungedb-aggregate
  2055. * @constructor
  2056. * @param [ctx] {ExpressionContext}
  2057. **/
  2058. var ProjectDocumentSource = module.exports = function ProjectDocumentSource(ctx){
  2059. if (arguments.length > 1) throw new Error("up to one arg expected");
  2060. base.call(this, ctx);
  2061. this.OE = new ObjectExpression();
  2062. this._raw = undefined;
  2063. }, klass = ProjectDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2064. // DEPENDENCIES
  2065. var Expression = require('../expressions/Expression');
  2066. var ObjectExpression = require('../expressions/ObjectExpression');
  2067. var Value = require('../Value');
  2068. klass.projectName = "$project";
  2069. /**
  2070. * Returns the name of project
  2071. * @return {string} the name of project
  2072. **/
  2073. proto.getSourceName = function getSourceName() {
  2074. return klass.projectName;
  2075. };
  2076. /**
  2077. * Returns the object that was used to construct the ProjectDocumentSource
  2078. * @return {object} the object that was used to construct the ProjectDocumentSource
  2079. **/
  2080. proto.getRaw = function getRaw() {
  2081. return this._raw;
  2082. };
  2083. /**
  2084. * Calls base document source eof()
  2085. * @return {bool} The result of base.source.eof()
  2086. **/
  2087. proto.eof = function eof() {
  2088. return this.source.eof();
  2089. };
  2090. /**
  2091. * Calls base document source advance()
  2092. * @return {bool} The result of base.source.advance()
  2093. **/
  2094. proto.advance = function advance() {
  2095. return this.source.advance();
  2096. };
  2097. /**
  2098. * Builds a new document(object) that represents this base document
  2099. * @return {object} A document that represents this base document
  2100. **/
  2101. proto.getCurrent = function getCurrent() {
  2102. var inDocument = this.source.getCurrent();
  2103. if (!inDocument) throw new Error('inDocument must be an object');
  2104. var resultDocument = {};
  2105. this.OE.addToDocument(resultDocument, inDocument, /*root=*/inDocument);
  2106. return resultDocument;
  2107. };
  2108. /**
  2109. * Optimizes the internal ObjectExpression
  2110. * @return
  2111. **/
  2112. proto.optimize = function optimize() {
  2113. this.OE.optimize();
  2114. };
  2115. proto.toJSON = function toJSON(){
  2116. var obj = {};
  2117. this.sourceToJson(obj);
  2118. return obj;
  2119. };
  2120. /**
  2121. * Places a $project key inside the builder object with value of this.OE
  2122. * @method sourceToJson
  2123. * @param {builder} An object (was ported from BsonBuilder)
  2124. * @return
  2125. **/
  2126. proto.sourceToJson = function sourceToJson(builder, explain) {
  2127. var insides = this.OE.toJSON(true);
  2128. builder[this.getSourceName()] = insides;
  2129. };
  2130. /**
  2131. * Builds a new ProjectDocumentSource from an object
  2132. * @method createFromJson
  2133. * @return {ProjectDocmentSource} a ProjectDocumentSource instance
  2134. **/
  2135. klass.createFromJson = function(jsonElement, expCtx) {
  2136. if (!(jsonElement instanceof Object) || jsonElement.constructor !== Object) throw new Error('Error 15969. Specification must be an object but was ' + typeof jsonElement);
  2137. var objectContext = new Expression.ObjectCtx({
  2138. isDocumentOk: true,
  2139. isTopLevel: true,
  2140. isInclusionOk: true
  2141. });
  2142. var project = new ProjectDocumentSource(expCtx);
  2143. project._raw = jsonElement;
  2144. var parsed = Expression.parseObject(jsonElement, objectContext);
  2145. var exprObj = parsed;
  2146. if (!exprObj instanceof ObjectExpression) throw new Error("16402, parseObject() returned wrong type of Expression");
  2147. if (!exprObj.getFieldCount()) throw new Error("16403, $projection requires at least one output field");
  2148. project.OE = exprObj;
  2149. return project;
  2150. };
  2151. /**
  2152. * Adds dependencies to the contained ObjectExpression
  2153. * @param {deps} An object that is treated as a set of strings
  2154. * @return A string that is part of the GetDepsReturn enum
  2155. **/
  2156. proto.getDependencies = function getDependencies(deps) {
  2157. var path = [];
  2158. this.OE.addDependencies(deps, path);
  2159. return base.GetDepsReturn.EXHAUSTIVE;
  2160. };
  2161. },{"../Value":7,"../expressions/Expression":40,"../expressions/ObjectExpression":51,"./DocumentSource":19}],25:[function(require,module,exports){
  2162. "use strict";
  2163. /**
  2164. * A document source skipper
  2165. * @class SkipDocumentSource
  2166. * @namespace mungedb-aggregate.pipeline.documentSources
  2167. * @module mungedb-aggregate
  2168. * @constructor
  2169. * @param [ctx] {ExpressionContext}
  2170. **/
  2171. var SkipDocumentSource = module.exports = function SkipDocumentSource(ctx){
  2172. if (arguments.length > 1) throw new Error("up to one arg expected");
  2173. base.call(this, ctx);
  2174. this.skip = 0;
  2175. this.count = 0;
  2176. }, klass = SkipDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2177. klass.skipName = "$skip";
  2178. proto.getSourceName = function getSourceName(){
  2179. return klass.skipName;
  2180. };
  2181. /**
  2182. * Coalesce skips together
  2183. * @param {Object} nextSource the next source
  2184. * @return {bool} return whether we can coalese together
  2185. **/
  2186. proto.coalesce = function coalesce(nextSource) {
  2187. var nextSkip = nextSource.constructor === SkipDocumentSource?nextSource:null;
  2188. // if it's not another $skip, we can't coalesce
  2189. if (!nextSkip) return false;
  2190. // we need to skip over the sum of the two consecutive $skips
  2191. this.skip += nextSkip.skip;
  2192. return true;
  2193. };
  2194. proto.skipper = function skipper() {
  2195. if (this.count === 0) {
  2196. while (!this.source.eof() && this.count++ < this.skip) {
  2197. this.source.advance();
  2198. }
  2199. }
  2200. if (this.source.eof()) {
  2201. this.current = null;
  2202. return;
  2203. }
  2204. this.current = this.source.getCurrent();
  2205. };
  2206. /**
  2207. * Is the source at EOF?
  2208. * @method eof
  2209. **/
  2210. proto.eof = function eof() {
  2211. this.skipper();
  2212. return this.source.eof();
  2213. };
  2214. /**
  2215. * some implementations do the equivalent of verify(!eof()) so check eof() first
  2216. * @method getCurrent
  2217. * @returns {Document} the current Document without advancing
  2218. **/
  2219. proto.getCurrent = function getCurrent() {
  2220. this.skipper();
  2221. return this.source.getCurrent();
  2222. };
  2223. /**
  2224. * Advance the state of the DocumentSource so that it will return the next Document.
  2225. * The default implementation returns false, after checking for interrupts.
  2226. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  2227. *
  2228. * @method advance
  2229. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  2230. **/
  2231. proto.advance = function advance() {
  2232. base.prototype.advance.call(this); // check for interrupts
  2233. if (this.eof()) {
  2234. this.current = null;
  2235. return false;
  2236. }
  2237. this.current = this.source.getCurrent();
  2238. return this.source.advance();
  2239. };
  2240. /**
  2241. * Create an object that represents the document source. The object
  2242. * will have a single field whose name is the source's name. This
  2243. * will be used by the default implementation of addToJsonArray()
  2244. * to add this object to a pipeline being represented in JSON.
  2245. *
  2246. * @method sourceToJson
  2247. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  2248. * @param {Boolean} explain create explain output
  2249. **/
  2250. proto.sourceToJson = function sourceToJson(builder, explain) {
  2251. builder.$skip = this.skip;
  2252. };
  2253. /**
  2254. * Creates a new SkipDocumentSource with the input number as the skip
  2255. *
  2256. * @param {Number} JsonElement this thing is *called* Json, but it expects a number
  2257. **/
  2258. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  2259. if (typeof jsonElement !== "number") throw new Error("code 15972; the value to skip must be a number");
  2260. var nextSkip = new SkipDocumentSource(ctx);
  2261. nextSkip.skip = jsonElement;
  2262. if (nextSkip.skip < 0 || isNaN(nextSkip.skip)) throw new Error("code 15956; the number to skip cannot be negative");
  2263. return nextSkip;
  2264. };
  2265. },{"./DocumentSource":19}],26:[function(require,module,exports){
  2266. "use strict";
  2267. /**
  2268. * A document source sorter
  2269. *
  2270. * //NOTE: DEVIATION FROM THE MONGO: We don't have shards, this inherits from DocumentSource, instead of SplittableDocumentSource
  2271. *
  2272. * @class SortDocumentSource
  2273. * @namespace mungedb-aggregate.pipeline.documentSources
  2274. * @module mungedb-aggregate
  2275. * @constructor
  2276. * @param [ctx] {ExpressionContext}
  2277. **/
  2278. var SortDocumentSource = module.exports = function SortDocumentSource(ctx){
  2279. if (arguments.length > 1) throw new Error("up to one arg expected");
  2280. base.call(this, ctx);
  2281. /*
  2282. * Before returning anything, this source must fetch everything from
  2283. * the underlying source and group it. populate() is used to do that
  2284. * on the first call to any method on this source. The populated
  2285. * boolean indicates that this has been done
  2286. **/
  2287. this.populated = false;
  2288. this.current = null;
  2289. this.docIterator = null; // a number tracking our position in the documents array
  2290. this.documents = []; // an array of documents
  2291. this.vSortKey = [];
  2292. this.vAscending = [];
  2293. }, klass = SortDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2294. // DEPENDENCIES
  2295. var FieldPathExpression = require("../expressions/FieldPathExpression"),
  2296. Value = require("../Value");
  2297. klass.sortName = "$sort";
  2298. proto.getSourceName = function getSourceName(){
  2299. return klass.sortName;
  2300. };
  2301. proto.getFactory = function getFactory(){
  2302. return klass; // using the ctor rather than a separate .create() method
  2303. };
  2304. klass.GetDepsReturn = {
  2305. SEE_NEXT: "SEE_NEXT" // Add the next Source's deps to the set
  2306. };
  2307. proto.getDependencies = function getDependencies(deps) {
  2308. for(var i = 0; i < this.vSortKey.length; ++i) {
  2309. this.vSortKey[i].addDependencies(deps);
  2310. }
  2311. return klass.GetDepsReturn.SEE_NEXT;
  2312. };
  2313. /**
  2314. * Is the source at EOF?
  2315. * @method eof
  2316. * @return {bool} return if we have hit the end of input
  2317. **/
  2318. proto.eof = function eof() {
  2319. if (!this.populated) this.populate();
  2320. return (this.docIterator == this.documents.length);
  2321. };
  2322. /**
  2323. * some implementations do the equivalent of verify(!eof()) so check eof() first
  2324. * @method getCurrent
  2325. * @returns {Document} the current Document without advancing
  2326. **/
  2327. proto.getCurrent = function getCurrent() {
  2328. if (!this.populated) this.populate();
  2329. return this.current;
  2330. };
  2331. /**
  2332. * Advance the state of the DocumentSource so that it will return the next Document.
  2333. * The default implementation returns false, after checking for interrupts.
  2334. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  2335. *
  2336. * @method advance
  2337. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  2338. **/
  2339. proto.advance = function advance() {
  2340. base.prototype.advance.call(this); // check for interrupts
  2341. if (!this.populated) this.populate();
  2342. if (this.docIterator == this.documents.length) throw new Error("This should never happen");
  2343. ++this.docIterator;
  2344. if (this.docIterator == this.documents.length) {
  2345. this.current = null;
  2346. return false;
  2347. }
  2348. this.current = this.documents[this.docIterator];
  2349. return true;
  2350. };
  2351. /**
  2352. * Create an object that represents the document source. The object
  2353. * will have a single field whose name is the source's name. This
  2354. * will be used by the default implementation of addToJsonArray()
  2355. * to add this object to a pipeline being represented in JSON.
  2356. *
  2357. * @method sourceToJson
  2358. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  2359. * @param {Boolean} explain create explain output
  2360. **/
  2361. proto.sourceToJson = function sourceToJson(builder, explain) {
  2362. var insides = {};
  2363. this.sortKeyToJson(insides, false);
  2364. builder[this.getSourceName()] = insides;
  2365. };
  2366. /**
  2367. * Add sort key field.
  2368. *
  2369. * Adds a sort key field to the key being built up. A concatenated
  2370. * key is built up by calling this repeatedly.
  2371. *
  2372. * @param {String} fieldPath the field path to the key component
  2373. * @param {bool} ascending if true, use the key for an ascending sort, otherwise, use it for descending
  2374. **/
  2375. proto.addKey = function addKey(fieldPath, ascending) {
  2376. var pathExpr = new FieldPathExpression(fieldPath);
  2377. this.vSortKey.push(pathExpr);
  2378. if (ascending === true || ascending === false) {
  2379. this.vAscending.push(ascending);
  2380. } else {
  2381. throw new Error("ascending must be true or false");
  2382. }
  2383. };
  2384. proto.populate = function populate() {
  2385. /* make sure we've got a sort key */
  2386. if (this.vSortKey.length === null) throw new Error("This should never happen");
  2387. /* pull everything from the underlying source */
  2388. for(var hasNext = !this.source.eof(); hasNext; hasNext = this.source.advance()) {
  2389. var doc = this.source.getCurrent();
  2390. this.documents.push(doc);
  2391. }
  2392. this.vSortKeyFPEs = this.vSortKey.map(function(aSortKey){
  2393. return new FieldPathExpression(aSortKey.getFieldPath(false));
  2394. });
  2395. /* sort the list */
  2396. this.documents.sort(SortDocumentSource.prototype.compare.bind(this));
  2397. /* start the sort iterator */
  2398. this.docIterator = 0;
  2399. if (this.docIterator < this.documents.length) {
  2400. this.current = this.documents[this.docIterator];
  2401. }
  2402. this.populated = true;
  2403. };
  2404. /**
  2405. * Compare two documents according to the specified sort key.
  2406. *
  2407. * @param {Object} pL the left side doc
  2408. * @param {Object} pR the right side doc
  2409. * @returns {Number} a number less than, equal to, or greater than zero, indicating pL < pR, pL == pR, or pL > pR, respectively
  2410. **/
  2411. proto.compare = function compare(pL,pR) {
  2412. /**
  2413. * populate() already checked that there is a non-empty sort key,
  2414. * so we shouldn't have to worry about that here.
  2415. *
  2416. * However, the tricky part is what to do is none of the sort keys are
  2417. * present. In this case, consider the document less.
  2418. **/
  2419. var n = this.vSortKey.length;
  2420. for(var i = 0; i < n; ++i) {
  2421. /* evaluate the sort keys */
  2422. var pathExpr = this.vSortKeyFPEs[i];
  2423. var left = pathExpr.evaluate(pL), right = pathExpr.evaluate(pR);
  2424. /*
  2425. Compare the two values; if they differ, return. If they are
  2426. the same, move on to the next key.
  2427. */
  2428. var cmp = Value.compare(left, right);
  2429. if (cmp) {
  2430. /* if necessary, adjust the return value by the key ordering */
  2431. if (!this.vAscending[i])
  2432. cmp = -cmp;
  2433. return cmp;
  2434. }
  2435. }
  2436. /**
  2437. * If we got here, everything matched (or didn't exist), so we'll
  2438. * consider the documents equal for purposes of this sort
  2439. **/
  2440. return 0;
  2441. };
  2442. /**
  2443. * Write out an object whose contents are the sort key.
  2444. *
  2445. * @param {Object} builder initialized object builder.
  2446. * @param {bool} fieldPrefix specify whether or not to include the field
  2447. **/
  2448. proto.sortKeyToJson = function sortKeyToJson(builder, usePrefix) {
  2449. // add the key fields
  2450. var n = this.vSortKey.length;
  2451. for(var i = 0; i < n; ++i) {
  2452. // create the "field name"
  2453. var ss = this.vSortKey[i].getFieldPath(usePrefix); // renamed write to get
  2454. // push a named integer based on the sort order
  2455. builder[ss] = this.vAscending[i] > 0 ? 1 : -1;
  2456. }
  2457. };
  2458. /**
  2459. * Creates a new SortDocumentSource
  2460. * @param {Object} jsonElement
  2461. **/
  2462. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  2463. if (typeof jsonElement !== "object") throw new Error("code 15973; the " + klass.sortName + " key specification must be an object");
  2464. var Sort = proto.getFactory(),
  2465. nextSort = new Sort(ctx);
  2466. /* check for then iterate over the sort object */
  2467. var sortKeys = 0;
  2468. for(var key in jsonElement) {
  2469. var sortOrder = 0;
  2470. if (typeof jsonElement[key] !== "number") throw new Error("code 15974; " + klass.sortName + " key ordering must be specified using a number");
  2471. sortOrder = jsonElement[key];
  2472. if ((sortOrder != 1) && (sortOrder !== -1)) throw new Error("code 15975; " + klass.sortName + " key ordering must be 1 (for ascending) or 0 (for descending)");
  2473. nextSort.addKey(key, (sortOrder > 0));
  2474. ++sortKeys;
  2475. }
  2476. if (sortKeys <= 0) throw new Error("code 15976; " + klass.sortName + " must have at least one sort key");
  2477. return nextSort;
  2478. };
  2479. },{"../Value":7,"../expressions/FieldPathExpression":41,"./DocumentSource":19}],27:[function(require,module,exports){
  2480. "use strict";
  2481. /**
  2482. * A document source unwinder
  2483. * @class UnwindDocumentSource
  2484. * @namespace mungedb-aggregate.pipeline.documentSources
  2485. * @module mungedb-aggregate
  2486. * @constructor
  2487. * @param [ctx] {ExpressionContext}
  2488. **/
  2489. var UnwindDocumentSource = module.exports = function UnwindDocumentSource(ctx){
  2490. if (arguments.length > 1) throw new Error("up to one arg expected");
  2491. base.call(this, ctx);
  2492. // Configuration state.
  2493. this._unwindPath = null;
  2494. // Iteration state.
  2495. this._unwinder = null;
  2496. }, klass = UnwindDocumentSource, base = require('./DocumentSource'), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2497. var DocumentSource = base,
  2498. FieldPath = require('../FieldPath'),
  2499. Document = require('../Document'),
  2500. Expression = require('../expressions/Expression');
  2501. klass.Unwinder = (function(){
  2502. /**
  2503. * Helper class to unwind arrays within a series of documents.
  2504. * @param {String} unwindPath is the field path to the array to unwind.
  2505. **/
  2506. var klass = function Unwinder(unwindPath){
  2507. // Path to the array to unwind.
  2508. this._unwindPath = unwindPath;
  2509. // The souce document to unwind.
  2510. this._document = null;
  2511. // Document indexes of the field path components.
  2512. this._unwindPathFieldIndexes = [];
  2513. // Iterator over the array within _document to unwind.
  2514. this._unwindArrayIterator = null;
  2515. // The last value returned from _unwindArrayIterator.
  2516. //this._unwindArrayIteratorCurrent = undefined; //dont define this yet
  2517. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2518. /**
  2519. * Reset the unwinder to unwind a new document.
  2520. * @param {Object} document
  2521. **/
  2522. proto.resetDocument = function resetDocument(document){
  2523. if (!document) throw new Error("document is required!");
  2524. // Reset document specific attributes.
  2525. this._document = document;
  2526. this._unwindPathFieldIndexes.length = 0;
  2527. this._unwindArrayIterator = null;
  2528. delete this._unwindArrayIteratorCurrent;
  2529. var pathValue = this.extractUnwindValue(); // sets _unwindPathFieldIndexes
  2530. if (!pathValue || pathValue.length === 0) return; // The path does not exist.
  2531. if (!(pathValue instanceof Array)) throw new Error(UnwindDocumentSource.unwindName + ": value at end of field path must be an array; code 15978");
  2532. // Start the iterator used to unwind the array.
  2533. this._unwindArrayIterator = pathValue.slice(0);
  2534. this._unwindArrayIteratorCurrent = this._unwindArrayIterator.splice(0,1)[0];
  2535. };
  2536. /**
  2537. * eof
  2538. * @returns {Boolean} true if done unwinding the last document passed to resetDocument().
  2539. **/
  2540. proto.eof = function eof(){
  2541. return !this.hasOwnProperty("_unwindArrayIteratorCurrent");
  2542. };
  2543. /**
  2544. * Try to advance to the next document unwound from the document passed to resetDocument().
  2545. * @returns {Boolean} true if advanced to a new unwound document, but false if done advancing.
  2546. **/
  2547. proto.advance = function advance(){
  2548. if (!this._unwindArrayIterator) {
  2549. // resetDocument() has not been called or the supplied document had no results to
  2550. // unwind.
  2551. delete this._unwindArrayIteratorCurrent;
  2552. } else if (!this._unwindArrayIterator.length) {
  2553. // There are no more results to unwind.
  2554. delete this._unwindArrayIteratorCurrent;
  2555. } else {
  2556. this._unwindArrayIteratorCurrent = this._unwindArrayIterator.splice(0, 1)[0];
  2557. }
  2558. };
  2559. /**
  2560. * Get the current document unwound from the document provided to resetDocument(), using
  2561. * the current value in the array located at the provided unwindPath. But return
  2562. * intrusive_ptr<Document>() if resetDocument() has not been called or the results to unwind
  2563. * have been exhausted.
  2564. *
  2565. * @returns {Object}
  2566. **/
  2567. proto.getCurrent = function getCurrent(){
  2568. if (!this.hasOwnProperty("_unwindArrayIteratorCurrent")) {
  2569. return null;
  2570. }
  2571. // Clone all the documents along the field path so that the end values are not shared across
  2572. // documents that have come out of this pipeline operator. This is a partial deep clone.
  2573. // Because the value at the end will be replaced, everything along the path leading to that
  2574. // will be replaced in order not to share that change with any other clones (or the
  2575. // original).
  2576. var clone = Document.clone(this._document);
  2577. var current = clone;
  2578. var n = this._unwindPathFieldIndexes.length;
  2579. if (!n) throw new Error("unwindFieldPathIndexes are empty");
  2580. for (var i = 0; i < n; ++i) {
  2581. var fi = this._unwindPathFieldIndexes[i];
  2582. var fp = current[fi];
  2583. if (i + 1 < n) {
  2584. // For every object in the path but the last, clone it and continue on down.
  2585. var next = Document.clone(fp);
  2586. current[fi] = next;
  2587. current = next;
  2588. } else {
  2589. // In the last nested document, subsitute the current unwound value.
  2590. current[fi] = this._unwindArrayIteratorCurrent;
  2591. }
  2592. }
  2593. return clone;
  2594. };
  2595. /**
  2596. * Get the value at the unwind path, otherwise an empty pointer if no such value
  2597. * exists. The _unwindPathFieldIndexes attribute will be set as the field path is traversed
  2598. * to find the value to unwind.
  2599. *
  2600. * @returns {Object}
  2601. **/
  2602. proto.extractUnwindValue = function extractUnwindValue() {
  2603. var current = this._document;
  2604. var pathValue;
  2605. var pathLength = this._unwindPath.getPathLength();
  2606. for (var i = 0; i < pathLength; ++i) {
  2607. var idx = this._unwindPath.getFieldName(i);
  2608. if (!current.hasOwnProperty(idx)) return null; // The target field is missing.
  2609. // Record the indexes of the fields down the field path in order to quickly replace them
  2610. // as the documents along the field path are cloned.
  2611. this._unwindPathFieldIndexes.push(idx);
  2612. pathValue = current[idx];
  2613. if (i < pathLength - 1) {
  2614. if (typeof pathValue !== 'object') return null; // The next field in the path cannot exist (inside a non object).
  2615. current = pathValue; // Move down the object tree.
  2616. }
  2617. }
  2618. return pathValue;
  2619. };
  2620. return klass;
  2621. })();
  2622. /**
  2623. * Lazily construct the _unwinder and initialize the iterator state of this DocumentSource.
  2624. * To be called by all members that depend on the iterator state.
  2625. **/
  2626. proto.lazyInit = function lazyInit(){
  2627. if (!this._unwinder) {
  2628. if (!this._unwindPath){
  2629. throw new Error("unwind path does not exist!");
  2630. }
  2631. this._unwinder = new klass.Unwinder(this._unwindPath);
  2632. if (!this.source.eof()) {
  2633. // Set up the first source document for unwinding.
  2634. this._unwinder.resetDocument(this.source.getCurrent());
  2635. }
  2636. this.mayAdvanceSource();
  2637. }
  2638. };
  2639. /**
  2640. * If the _unwinder is exhausted and the source may be advanced, advance the source and
  2641. * reset the _unwinder's source document.
  2642. **/
  2643. proto.mayAdvanceSource = function mayAdvanceSource(){
  2644. while(this._unwinder.eof()) {
  2645. // The _unwinder is exhausted.
  2646. if (this.source.eof()) return; // The source is exhausted.
  2647. if (!this.source.advance()) return; // The source is exhausted.
  2648. // Reset the _unwinder with source's next document.
  2649. this._unwinder.resetDocument(this.source.getCurrent());
  2650. }
  2651. };
  2652. /**
  2653. * Specify the field to unwind.
  2654. **/
  2655. proto.unwindPath = function unwindPath(fieldPath){
  2656. // Can't set more than one unwind path.
  2657. if (this._unwindPath) throw new Error(this.getSourceName() + " can't unwind more than one path; code 15979");
  2658. // Record the unwind path.
  2659. this._unwindPath = new FieldPath(fieldPath);
  2660. };
  2661. klass.unwindName = "$unwind";
  2662. proto.getSourceName = function getSourceName(){
  2663. return klass.unwindName;
  2664. };
  2665. /**
  2666. * Get the fields this operation needs to do its job.
  2667. * Deps should be in "a.b.c" notation
  2668. *
  2669. * @method getDependencies
  2670. * @param {Object} deps set (unique array) of strings
  2671. * @returns DocumentSource.GetDepsReturn
  2672. **/
  2673. proto.getDependencies = function getDependencies(deps) {
  2674. if (!this._unwindPath) throw new Error("unwind path does not exist!");
  2675. deps[this._unwindPath.getPath(false)] = 1;
  2676. return DocumentSource.GetDepsReturn.SEE_NEXT;
  2677. };
  2678. /**
  2679. * Is the source at EOF?
  2680. * @method eof
  2681. **/
  2682. proto.eof = function eof() {
  2683. this.lazyInit();
  2684. return this._unwinder.eof();
  2685. };
  2686. /**
  2687. * some implementations do the equivalent of verify(!eof()) so check eof() first
  2688. * @method getCurrent
  2689. * @returns {Document} the current Document without advancing
  2690. **/
  2691. proto.getCurrent = function getCurrent() {
  2692. this.lazyInit();
  2693. return this._unwinder.getCurrent();
  2694. };
  2695. /**
  2696. * Advance the state of the DocumentSource so that it will return the next Document.
  2697. * The default implementation returns false, after checking for interrupts.
  2698. * Derived classes can call the default implementation in their own implementations in order to check for interrupts.
  2699. *
  2700. * @method advance
  2701. * @returns {Boolean} whether there is another document to fetch, i.e., whether or not getCurrent() will succeed. This default implementation always returns false.
  2702. **/
  2703. proto.advance = function advance() {
  2704. base.prototype.advance.call(this); // check for interrupts
  2705. this.lazyInit();
  2706. this._unwinder.advance();
  2707. this.mayAdvanceSource();
  2708. return !this._unwinder.eof();
  2709. };
  2710. /**
  2711. * Create an object that represents the document source. The object
  2712. * will have a single field whose name is the source's name. This
  2713. * will be used by the default implementation of addToJsonArray()
  2714. * to add this object to a pipeline being represented in JSON.
  2715. *
  2716. * @method sourceToJson
  2717. * @param {Object} builder JSONObjBuilder: a blank object builder to write to
  2718. * @param {Boolean} explain create explain output
  2719. **/
  2720. proto.sourceToJson = function sourceToJson(builder, explain) {
  2721. if (!this._unwindPath) throw new Error("unwind path does not exist!");
  2722. builder[this.getSourceName()] = this._unwindPath.getPath(true);
  2723. };
  2724. /**
  2725. * Creates a new UnwindDocumentSource with the input path as the path to unwind
  2726. * @param {String} JsonElement this thing is *called* Json, but it expects a string
  2727. **/
  2728. klass.createFromJson = function createFromJson(jsonElement, ctx) {
  2729. // The value of $unwind should just be a field path.
  2730. if (jsonElement.constructor !== String) throw new Error("the " + klass.unwindName + " field path must be specified as a string; code 15981");
  2731. var pathString = Expression.removeFieldPrefix(jsonElement);
  2732. var unwind = new UnwindDocumentSource(ctx);
  2733. unwind.unwindPath(pathString);
  2734. return unwind;
  2735. };
  2736. },{"../Document":3,"../FieldPath":4,"../expressions/Expression":40,"./DocumentSource":19}],28:[function(require,module,exports){
  2737. "use strict";
  2738. module.exports = {
  2739. CursorDocumentSource: require("./CursorDocumentSource.js"),
  2740. DocumentSource: require("./DocumentSource.js"),
  2741. FilterBaseDocumentSource: require("./FilterBaseDocumentSource.js"),
  2742. GroupDocumentSource: require("./GroupDocumentSource.js"),
  2743. LimitDocumentSource: require("./LimitDocumentSource.js"),
  2744. MatchDocumentSource: require("./MatchDocumentSource.js"),
  2745. ProjectDocumentSource: require("./ProjectDocumentSource.js"),
  2746. SkipDocumentSource: require("./SkipDocumentSource.js"),
  2747. SortDocumentSource: require("./SortDocumentSource.js"),
  2748. UnwindDocumentSource: require("./UnwindDocumentSource.js")
  2749. };
  2750. },{"./CursorDocumentSource.js":18,"./DocumentSource.js":19,"./FilterBaseDocumentSource.js":20,"./GroupDocumentSource.js":21,"./LimitDocumentSource.js":22,"./MatchDocumentSource.js":23,"./ProjectDocumentSource.js":24,"./SkipDocumentSource.js":25,"./SortDocumentSource.js":26,"./UnwindDocumentSource.js":27}],29:[function(require,module,exports){
  2751. "use strict";
  2752. /**
  2753. * Create an expression that finds the sum of n operands.
  2754. * @class AddExpression
  2755. * @namespace mungedb-aggregate.pipeline.expressions
  2756. * @module mungedb-aggregate
  2757. * @constructor
  2758. **/
  2759. var AddExpression = module.exports = function AddExpression(){
  2760. if (arguments.length !== 0) throw new Error("zero args expected");
  2761. base.call(this);
  2762. }, klass = AddExpression, NaryExpression = require("./NaryExpression"), base = NaryExpression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2763. // DEPENDENCIES
  2764. var Value = require("../Value");
  2765. // PROTOTYPE MEMBERS
  2766. proto.getOpName = function getOpName(){
  2767. return "$add";
  2768. };
  2769. proto.getFactory = function getFactory(){
  2770. return klass; // using the ctor rather than a separate .create() method
  2771. };
  2772. /**
  2773. * Takes an array of one or more numbers and adds them together, returning the sum.
  2774. * @method @evaluate
  2775. **/
  2776. proto.evaluate = function evaluate(doc) {
  2777. var total = 0;
  2778. for (var i = 0, n = this.operands.length; i < n; ++i) {
  2779. var value = this.operands[i].evaluate(doc);
  2780. if (value instanceof Date) throw new Error("$add does not support dates; code 16415");
  2781. if (typeof value == "string") throw new Error("$add does not support strings; code 16416");
  2782. total += Value.coerceToDouble(value);
  2783. }
  2784. if (typeof total != "number") throw new Error("$add resulted in a non-numeric type; code 16417");
  2785. return total;
  2786. };
  2787. },{"../Value":7,"./NaryExpression":49}],30:[function(require,module,exports){
  2788. "use strict";
  2789. /**
  2790. * Create an expression that finds the conjunction of n operands. The
  2791. * conjunction uses short-circuit logic; the expressions are evaluated in the
  2792. * order they were added to the conjunction, and the evaluation stops and
  2793. * returns false on the first operand that evaluates to false.
  2794. *
  2795. * @class AndExpression
  2796. * @namespace mungedb-aggregate.pipeline.expressions
  2797. * @module mungedb-aggregate
  2798. * @constructor
  2799. **/
  2800. var AndExpression = module.exports = function AndExpression(){
  2801. if (arguments.length !== 0) throw new Error("zero args expected");
  2802. base.call(this);
  2803. }, klass = AndExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2804. // DEPENDENCIES
  2805. var Value = require("../Value"),
  2806. ConstantExpression = require("./ConstantExpression"),
  2807. CoerceToBoolExpression = require("./CoerceToBoolExpression");
  2808. // PROTOTYPE MEMBERS
  2809. proto.getOpName = function getOpName(){
  2810. return "$and";
  2811. };
  2812. proto.getFactory = function getFactory(){
  2813. return klass; // using the ctor rather than a separate .create() method
  2814. };
  2815. /**
  2816. * Takes an array one or more values and returns true if all of the values in the array are true. Otherwise $and returns false.
  2817. * @method evaluate
  2818. **/
  2819. proto.evaluate = function evaluate(doc) {
  2820. for (var i = 0, n = this.operands.length; i < n; ++i) {
  2821. var value = this.operands[i].evaluate(doc);
  2822. if (!Value.coerceToBool(value)) return false;
  2823. }
  2824. return true;
  2825. };
  2826. proto.optimize = function optimize() {
  2827. var expr = base.prototype.optimize.call(this); //optimize the conjunction as much as possible
  2828. // if the result isn't a conjunction, we can't do anything
  2829. if (!(expr instanceof AndExpression)) return expr;
  2830. var andExpr = expr;
  2831. // Check the last argument on the result; if it's not constant (as promised by ExpressionNary::optimize(),) then there's nothing we can do.
  2832. var n = andExpr.operands.length;
  2833. // ExpressionNary::optimize() generates an ExpressionConstant for {$and:[]}.
  2834. if (!n) throw new Error("requires operands!");
  2835. var lastExpr = andExpr.operands[n - 1];
  2836. if (!(lastExpr instanceof ConstantExpression)) return expr;
  2837. // Evaluate and coerce the last argument to a boolean. If it's false, then we can replace this entire expression.
  2838. var last = Value.coerceToBool(lastExpr.evaluate());
  2839. if (!last) return new ConstantExpression(false);
  2840. // If we got here, the final operand was true, so we don't need it anymore.
  2841. // If there was only one other operand, we don't need the conjunction either.
  2842. // Note we still need to keep the promise that the result will be a boolean.
  2843. if (n == 2) return new CoerceToBoolExpression(andExpr.operands[0]);
  2844. //Remove the final "true" value, and return the new expression.
  2845. //CW TODO: Note that because of any implicit conversions, we may need to apply an implicit boolean conversion.
  2846. andExpr.operands.length = n - 1; //truncate the array
  2847. return expr;
  2848. };
  2849. //TODO: proto.toMatcherBson
  2850. },{"../Value":7,"./CoerceToBoolExpression":31,"./ConstantExpression":35,"./NaryExpression":49}],31:[function(require,module,exports){
  2851. "use strict";
  2852. /**
  2853. * internal expression for coercing things to booleans
  2854. * @class CoerceToBoolExpression
  2855. * @namespace mungedb-aggregate.pipeline.expressions
  2856. * @module mungedb-aggregate
  2857. * @constructor
  2858. **/
  2859. var CoerceToBoolExpression = module.exports = function CoerceToBoolExpression(expression){
  2860. if (arguments.length !== 1) throw new Error("args expected: expression");
  2861. this.expression = expression;
  2862. base.call(this);
  2863. }, klass = CoerceToBoolExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2864. // DEPENDENCIES
  2865. var Value = require("../Value"),
  2866. AndExpression = require("./AndExpression"),
  2867. OrExpression = require("./OrExpression"),
  2868. NotExpression = require("./NotExpression");
  2869. // PROTOTYPE MEMBERS
  2870. proto.evaluate = function evaluate(doc){
  2871. var result = this.expression.evaluate(doc);
  2872. return Value.coerceToBool(result);
  2873. };
  2874. proto.optimize = function optimize() {
  2875. this.expression = this.expression.optimize(); // optimize the operand
  2876. // if the operand already produces a boolean, then we don't need this
  2877. // LATER - Expression to support a "typeof" query?
  2878. var expr = this.expression;
  2879. if(expr instanceof AndExpression ||
  2880. expr instanceof OrExpression ||
  2881. expr instanceof NotExpression ||
  2882. expr instanceof CoerceToBoolExpression)
  2883. return expr;
  2884. return this;
  2885. };
  2886. proto.addDependencies = function addDependencies(deps, path) {
  2887. return this.expression.addDependencies(deps);
  2888. };
  2889. proto.toJSON = function toJSON() {
  2890. // Serializing as an $and expression which will become a CoerceToBool
  2891. return {$and:[this.expression.toJSON()]};
  2892. };
  2893. //TODO: proto.addToBsonObj --- may be required for $project to work
  2894. //TODO: proto.addToBsonArray
  2895. },{"../Value":7,"./AndExpression":30,"./Expression":40,"./NotExpression":50,"./OrExpression":52}],32:[function(require,module,exports){
  2896. "use strict";
  2897. /**
  2898. * Generic comparison expression that gets used for $eq, $ne, $lt, $lte, $gt, $gte, and $cmp.
  2899. * @class CompareExpression
  2900. * @namespace mungedb-aggregate.pipeline.expressions
  2901. * @module mungedb-aggregate
  2902. * @constructor
  2903. **/
  2904. var CompareExpression = module.exports = function CompareExpression(cmpOp) {
  2905. if (arguments.length !== 1) throw new Error("args expected: cmpOp");
  2906. this.cmpOp = cmpOp;
  2907. base.call(this);
  2908. }, klass = CompareExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2909. // DEPENDENCIES
  2910. var Value = require("../Value"),
  2911. Expression = require("./Expression"),
  2912. ConstantExpression = require("./ConstantExpression"),
  2913. FieldPathExpression = require("./FieldPathExpression"),
  2914. FieldRangeExpression = require("./FieldRangeExpression");
  2915. // NESTED CLASSES
  2916. /**
  2917. * Lookup table for truth value returns
  2918. *
  2919. * @param truthValues truth value for -1, 0, 1
  2920. * @param reverse reverse comparison operator
  2921. * @param name string name
  2922. **/
  2923. var CmpLookup = (function(){ // emulating a struct
  2924. // CONSTRUCTOR
  2925. var klass = function CmpLookup(truthValues, reverse, name) {
  2926. if(arguments.length !== 3) throw new Error("args expected: truthValues, reverse, name");
  2927. this.truthValues = truthValues;
  2928. this.reverse = reverse;
  2929. this.name = name;
  2930. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  2931. return klass;
  2932. })();
  2933. // PRIVATE STATIC MEMBERS
  2934. /**
  2935. * a table of cmp type lookups to truth values
  2936. * @private
  2937. **/
  2938. var cmpLookupMap = [ //NOTE: converted from this Array to a Dict/Object below using CmpLookup#name as the key
  2939. // -1 0 1 reverse name (taking advantage of the fact that our 'enums' are strings below)
  2940. new CmpLookup([false, true, false], Expression.CmpOp.EQ, Expression.CmpOp.EQ),
  2941. new CmpLookup([true, false, true], Expression.CmpOp.NE, Expression.CmpOp.NE),
  2942. new CmpLookup([false, false, true], Expression.CmpOp.LT, Expression.CmpOp.GT),
  2943. new CmpLookup([false, true, true], Expression.CmpOp.LTE, Expression.CmpOp.GTE),
  2944. new CmpLookup([true, false, false], Expression.CmpOp.GT, Expression.CmpOp.LT),
  2945. new CmpLookup([true, true, false], Expression.CmpOp.GTE, Expression.CmpOp.LTE),
  2946. new CmpLookup([false, false, false], Expression.CmpOp.CMP, Expression.CmpOp.CMP)
  2947. ].reduce(function(r,o){r[o.name]=o;return r;},{});
  2948. // PROTOTYPE MEMBERS
  2949. proto.addOperand = function addOperand(expr) {
  2950. this.checkArgLimit(2);
  2951. base.prototype.addOperand.call(this, expr);
  2952. };
  2953. proto.evaluate = function evaluate(doc) {
  2954. this.checkArgCount(2);
  2955. var left = this.operands[0].evaluate(doc),
  2956. right = this.operands[1].evaluate(doc),
  2957. cmp = Expression.signum(Value.compare(left, right));
  2958. if (this.cmpOp == Expression.CmpOp.CMP) return cmp;
  2959. return cmpLookupMap[this.cmpOp].truthValues[cmp + 1] || false;
  2960. };
  2961. proto.optimize = function optimize(){
  2962. var expr = base.prototype.optimize.call(this); // first optimize the comparison operands
  2963. if (!(expr instanceof CompareExpression)) return expr; // if no longer a comparison, there's nothing more we can do.
  2964. // check to see if optimizing comparison operator is supported // CMP and NE cannot use ExpressionFieldRange which is what this optimization uses
  2965. var newOp = this.cmpOp;
  2966. if (newOp == Expression.CmpOp.CMP || newOp == Expression.CmpOp.NE) return expr;
  2967. // There's one localized optimization we recognize: a comparison between a field and a constant. If we recognize that pattern, replace it with an ExpressionFieldRange.
  2968. // When looking for this pattern, note that the operands could appear in any order. If we need to reverse the sense of the comparison to put it into the required canonical form, do so.
  2969. var leftExpr = this.operands[0],
  2970. rightExpr = this.operands[1];
  2971. var fieldPathExpr, constantExpr;
  2972. if (leftExpr instanceof FieldPathExpression) {
  2973. fieldPathExpr = leftExpr;
  2974. if (!(rightExpr instanceof ConstantExpression)) return expr; // there's nothing more we can do
  2975. constantExpr = rightExpr;
  2976. } else {
  2977. // if the first operand wasn't a path, see if it's a constant
  2978. if (!(leftExpr instanceof ConstantExpression)) return expr; // there's nothing more we can do
  2979. constantExpr = leftExpr;
  2980. // the left operand was a constant; see if the right is a path
  2981. if (!(rightExpr instanceof FieldPathExpression)) return expr; // there's nothing more we can do
  2982. fieldPathExpr = rightExpr;
  2983. // these were not in canonical order, so reverse the sense
  2984. newOp = cmpLookupMap[newOp].reverse;
  2985. }
  2986. return new FieldRangeExpression(fieldPathExpr, newOp, constantExpr.getValue());
  2987. };
  2988. proto.getOpName = function getOpName(){
  2989. return this.cmpOp;
  2990. };
  2991. },{"../Value":7,"./ConstantExpression":35,"./Expression":40,"./FieldPathExpression":41,"./FieldRangeExpression":42,"./NaryExpression":49}],33:[function(require,module,exports){
  2992. "use strict";
  2993. /**
  2994. * Creates an expression that concatenates a set of string operands.
  2995. * @class ConcatExpression
  2996. * @namespace mungedb-aggregate.pipeline.expressions
  2997. * @module mungedb-aggregate
  2998. * @constructor
  2999. **/
  3000. var ConcatExpression = module.exports = function ConcatExpression(){
  3001. if (arguments.length !== 0) throw new Error("zero args expected");
  3002. base.call(this);
  3003. }, klass = ConcatExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3004. // DEPENDENCIES
  3005. var Value = require("../Value");
  3006. // PROTOTYPE MEMBERS
  3007. proto.getOpName = function getOpName(){
  3008. return "$concat";
  3009. };
  3010. proto.getFactory = function getFactory(){
  3011. return klass; // using the ctor rather than a separate .create() method
  3012. };
  3013. /**
  3014. * Concats a string of values together.
  3015. * @method evaluate
  3016. **/
  3017. proto.evaluate = function evaluate(doc) {
  3018. var result = "";
  3019. for (var i = 0, n = this.operands.length; i < n; ++i) {
  3020. var val = this.operands[i].evaluate(doc);
  3021. if (val === null) return null; // if any operand is null, return null for all
  3022. if (typeof(val) != "string") throw new Error("$concat only supports strings, not " + typeof(val) + "; code 16702");
  3023. result = result + Value.coerceToString(val);
  3024. }
  3025. return result;
  3026. };
  3027. },{"../Value":7,"./NaryExpression":49}],34:[function(require,module,exports){
  3028. "use strict";
  3029. /**
  3030. * $cond expression; @see evaluate
  3031. * @class AndExpression
  3032. * @namespace mungedb-aggregate.pipeline.expressions
  3033. * @module mungedb-aggregate
  3034. * @constructor
  3035. **/
  3036. var CondExpression = module.exports = function CondExpression(){
  3037. if (arguments.length !== 0) throw new Error("zero args expected");
  3038. base.call(this);
  3039. }, klass = CondExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3040. // DEPENDENCIES
  3041. var Value = require("../Value");
  3042. // PROTOTYPE MEMBERS
  3043. proto.getOpName = function getOpName(){
  3044. return "$cond";
  3045. };
  3046. proto.addOperand = function addOperand(expr) {
  3047. this.checkArgLimit(3);
  3048. base.prototype.addOperand.call(this, expr);
  3049. };
  3050. /**
  3051. * Use the $cond operator with the following syntax: { $cond: [ <boolean-expression>, <true-case>, <false-case> ] }
  3052. * @method evaluate
  3053. **/
  3054. proto.evaluate = function evaluate(doc){
  3055. this.checkArgCount(3);
  3056. var pCond = this.operands[0].evaluate(doc),
  3057. idx = Value.coerceToBool(pCond) ? 1 : 2;
  3058. return this.operands[idx].evaluate(doc);
  3059. };
  3060. },{"../Value":7,"./NaryExpression":49}],35:[function(require,module,exports){
  3061. "use strict";
  3062. /**
  3063. * Internal expression for constant values
  3064. * @class ConstantExpression
  3065. * @namespace mungedb-aggregate.pipeline.expressions
  3066. * @module mungedb-aggregate
  3067. * @constructor
  3068. **/
  3069. var ConstantExpression = module.exports = function ConstantExpression(value){
  3070. if (arguments.length !== 1) throw new Error("args expected: value");
  3071. this.value = value; //TODO: actually make read-only in terms of JS?
  3072. base.call(this);
  3073. }, klass = ConstantExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3074. // PROTOTYPE MEMBERS
  3075. proto.getOpName = function getOpName(){
  3076. return "$const";
  3077. };
  3078. /**
  3079. * Get the constant value represented by this Expression.
  3080. * @method getValue
  3081. * @returns the value
  3082. **/
  3083. proto.getValue = function getValue(){ //TODO: convert this to an instance field rather than a property
  3084. return this.value;
  3085. };
  3086. proto.addDependencies = function addDependencies(deps, path) {
  3087. // nothing to do
  3088. };
  3089. /**
  3090. * Get the constant value represented by this Expression.
  3091. * @method evaluate
  3092. **/
  3093. proto.evaluate = function evaluate(doc){
  3094. return this.value;
  3095. };
  3096. proto.optimize = function optimize() {
  3097. return this; // nothing to do
  3098. };
  3099. proto.toJSON = function(isExpressionRequired){
  3100. return isExpressionRequired ? {$const: this.value} : this.value;
  3101. };
  3102. //TODO: proto.addToBsonObj --- may be required for $project to work -- my hope is that we can implement toJSON methods all around and use that instead
  3103. //TODO: proto.addToBsonArray
  3104. },{"./Expression":40}],36:[function(require,module,exports){
  3105. "use strict";
  3106. /**
  3107. * Get the DayOfMonth from a date.
  3108. * @class DayOfMonthExpression
  3109. * @namespace mungedb-aggregate.pipeline.expressions
  3110. * @module mungedb-aggregate
  3111. * @constructor
  3112. **/
  3113. var DayOfMonthExpression = module.exports = function DayOfMonthExpression(){
  3114. if (arguments.length !== 0) throw new Error("zero args expected");
  3115. base.call(this);
  3116. }, klass = DayOfMonthExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3117. // PROTOTYPE MEMBERS
  3118. proto.getOpName = function getOpName(){
  3119. return "$dayOfMonth";
  3120. };
  3121. proto.addOperand = function addOperand(expr) {
  3122. this.checkArgLimit(1);
  3123. base.prototype.addOperand.call(this, expr);
  3124. };
  3125. /**
  3126. * Takes a date and returns the day of the month as a number between 1 and 31.
  3127. * @method evaluate
  3128. **/
  3129. proto.evaluate = function evaluate(doc){
  3130. this.checkArgCount(1);
  3131. var date = this.operands[0].evaluate(doc);
  3132. return date.getUTCDate();
  3133. };
  3134. },{"./NaryExpression":49}],37:[function(require,module,exports){
  3135. "use strict";
  3136. /**
  3137. * Get the DayOfWeek from a date.
  3138. * @class DayOfWeekExpression
  3139. * @namespace mungedb-aggregate.pipeline.expressions
  3140. * @module mungedb-aggregate
  3141. * @constructor
  3142. **/
  3143. var DayOfWeekExpression = module.exports = function DayOfWeekExpression(){
  3144. if (arguments.length !== 0) throw new Error("zero args expected");
  3145. base.call(this);
  3146. }, klass = DayOfWeekExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3147. // PROTOTYPE MEMBERS
  3148. proto.getOpName = function getOpName(){
  3149. return "$dayOfWeek";
  3150. };
  3151. proto.addOperand = function addOperand(expr) {
  3152. this.checkArgLimit(1);
  3153. base.prototype.addOperand.call(this, expr);
  3154. };
  3155. /**
  3156. * Takes a date and returns the day of the week as a number between 1 (Sunday) and 7 (Saturday.)
  3157. * @method evaluate
  3158. **/
  3159. proto.evaluate = function evaluate(doc){
  3160. this.checkArgCount(1);
  3161. var date = this.operands[0].evaluate(doc);
  3162. return date.getUTCDay()+1;
  3163. };
  3164. },{"./NaryExpression":49}],38:[function(require,module,exports){
  3165. "use strict";
  3166. /**
  3167. * Get the DayOfYear from a date.
  3168. * @class DayOfYearExpression
  3169. * @namespace mungedb-aggregate.pipeline.expressions
  3170. * @module mungedb-aggregate
  3171. * @constructor
  3172. **/
  3173. var DayOfYearExpression = module.exports = function DayOfYearExpression(){
  3174. if(arguments.length !== 0) throw new Error("zero args expected");
  3175. base.call(this);
  3176. }, klass = DayOfYearExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3177. // PROTOTYPE MEMBERS
  3178. proto.getOpName = function getOpName(){
  3179. return "$dayOfYear";
  3180. };
  3181. proto.addOperand = function addOperand(expr) {
  3182. this.checkArgLimit(1);
  3183. base.prototype.addOperand.call(this, expr);
  3184. };
  3185. /**
  3186. * Takes a date and returns the day of the year as a number between 1 and 366.
  3187. * @method evaluate
  3188. **/
  3189. proto.evaluate = function evaluate(doc){
  3190. //NOTE: the below silliness is to deal with the leap year scenario when we should be returning 366
  3191. this.checkArgCount(1);
  3192. var date = this.operands[0].evaluate(doc);
  3193. return klass.getDateDayOfYear(date);
  3194. };
  3195. // STATIC METHODS
  3196. klass.getDateDayOfYear = function getDateDayOfYear(d){
  3197. var y11 = new Date(d.getUTCFullYear(), 0, 1), // same year, first month, first day; time omitted
  3198. ymd = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()+1); // same y,m,d; time omitted, add 1 because days start at 1
  3199. return Math.ceil((ymd - y11) / 86400000); //NOTE: 86400000 ms is 1 day
  3200. };
  3201. },{"./NaryExpression":49}],39:[function(require,module,exports){
  3202. "use strict";
  3203. /**
  3204. * A $divide pipeline expression.
  3205. * @see evaluate
  3206. * @class DivideExpression
  3207. * @namespace mungedb-aggregate.pipeline.expressions
  3208. * @module mungedb-aggregate
  3209. * @constructor
  3210. **/
  3211. var DivideExpression = module.exports = function DivideExpression(){
  3212. if (arguments.length !== 0) throw new Error("zero args expected");
  3213. base.call(this);
  3214. }, klass = DivideExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3215. // DEPENDENCIES
  3216. var Value = require("../Value");
  3217. // PROTOTYPE MEMBERS
  3218. proto.getOpName = function getOpName(){ //TODO: try to move this to a static and/or instance field instead of a getter function
  3219. return "$divide";
  3220. };
  3221. proto.addOperand = function addOperand(expr){
  3222. this.checkArgLimit(2);
  3223. base.prototype.addOperand.call(this, expr);
  3224. };
  3225. /**
  3226. * Takes an array that contains a pair of numbers and returns the value of the first number divided by the second number.
  3227. * @method evaluate
  3228. **/
  3229. proto.evaluate = function evaluate(doc) {
  3230. this.checkArgCount(2);
  3231. var left = this.operands[0].evaluate(doc),
  3232. right = this.operands[1].evaluate(doc);
  3233. if (!(left instanceof Date) && (!right instanceof Date)) throw new Error("$divide does not support dates; code 16373");
  3234. right = Value.coerceToDouble(right);
  3235. if (right === 0) return undefined;
  3236. left = Value.coerceToDouble(left);
  3237. return left / right;
  3238. };
  3239. },{"../Value":7,"./NaryExpression":49}],40:[function(require,module,exports){
  3240. "use strict";
  3241. /**
  3242. * A base class for all pipeline expressions; Performs common expressions within an Op.
  3243. *
  3244. * NOTE: An object expression can take any of the following forms:
  3245. *
  3246. * f0: {f1: ..., f2: ..., f3: ...}
  3247. * f0: {$operator:[operand1, operand2, ...]}
  3248. *
  3249. * @class Expression
  3250. * @namespace mungedb-aggregate.pipeline.expressions
  3251. * @module mungedb-aggregate
  3252. * @constructor
  3253. **/
  3254. var Expression = module.exports = function Expression(){
  3255. if (arguments.length !== 0) throw new Error("zero args expected");
  3256. }, klass = Expression, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3257. // DEPENDENCIES
  3258. var Document = require("../Document");
  3259. // NESTED CLASSES
  3260. /**
  3261. * Reference to the `mungedb-aggregate.pipeline.expressions.Expression.ObjectCtx` class
  3262. * @static
  3263. * @property ObjectCtx
  3264. **/
  3265. var ObjectCtx = Expression.ObjectCtx = (function(){
  3266. // CONSTRUCTOR
  3267. /**
  3268. * Utility class for parseObject() below. isDocumentOk indicates that it is OK to use a Document in the current context.
  3269. *
  3270. * NOTE: deviation from Mongo code: accepts an `Object` of settings rather than a bitmask to help simplify the interface a little bit
  3271. *
  3272. * @class ObjectCtx
  3273. * @namespace mungedb-aggregate.pipeline.expressions.Expression
  3274. * @module mungedb-aggregate
  3275. * @constructor
  3276. * @param opts
  3277. * @param [opts.isDocumentOk] {Boolean}
  3278. * @param [opts.isTopLevel] {Boolean}
  3279. * @param [opts.isInclusionOk] {Boolean}
  3280. **/
  3281. var klass = function ObjectCtx(opts /*= {isDocumentOk:..., isTopLevel:..., isInclusionOk:...}*/){
  3282. if(!(opts instanceof Object && opts.constructor == Object)) throw new Error("opts is required and must be an Object containing named args");
  3283. for (var k in opts) { // assign all given opts to self so long as they were part of klass.prototype as undefined properties
  3284. if (opts.hasOwnProperty(k) && proto.hasOwnProperty(k) && proto[k] === undefined) this[k] = opts[k];
  3285. }
  3286. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3287. // PROTOTYPE MEMBERS
  3288. proto.isDocumentOk =
  3289. proto.isTopLevel =
  3290. proto.isInclusionOk = undefined;
  3291. return klass;
  3292. })();
  3293. /**
  3294. * Reference to the `mungedb-aggregate.pipeline.expressions.Expression.OpDesc` class
  3295. * @static
  3296. * @property OpDesc
  3297. **/
  3298. var OpDesc = Expression.OpDesc = (function(){
  3299. // CONSTRUCTOR
  3300. /**
  3301. * Decribes how and when to create an Op instance
  3302. *
  3303. * @class OpDesc
  3304. * @namespace mungedb-aggregate.pipeline.expressions.Expression
  3305. * @module mungedb-aggregate
  3306. * @constructor
  3307. * @param name
  3308. * @param factory
  3309. * @param flags
  3310. * @param argCount
  3311. **/
  3312. var klass = function OpDesc(name, factory, flags, argCount){
  3313. var firstArg = arguments[0];
  3314. if (firstArg instanceof Object && firstArg.constructor == Object) { //TODO: using this?
  3315. var opts = firstArg;
  3316. for (var k in opts) { // assign all given opts to self so long as they were part of klass.prototype as undefined properties
  3317. if (opts.hasOwnProperty(k) && proto.hasOwnProperty(k) && proto[k] === undefined) this[k] = opts[k];
  3318. }
  3319. } else {
  3320. this.name = name;
  3321. this.factory = factory;
  3322. this.flags = flags || 0;
  3323. this.argCount = argCount || 0;
  3324. }
  3325. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3326. // STATIC MEMBERS
  3327. klass.FIXED_COUNT = 1;
  3328. klass.OBJECT_ARG = 2;
  3329. // PROTOTYPE MEMBERS
  3330. proto.name =
  3331. proto.factory =
  3332. proto.flags =
  3333. proto.argCount = undefined;
  3334. /**
  3335. * internal `OpDesc#name` comparer
  3336. * @method cmp
  3337. * @param that the other `OpDesc` instance
  3338. **/
  3339. proto.cmp = function cmp(that) {
  3340. return this.name < that.name ? -1 : this.name > that.name ? 1 : 0;
  3341. };
  3342. return klass;
  3343. })();
  3344. // END OF NESTED CLASSES
  3345. /**
  3346. * @class Expression
  3347. * @namespace mungedb-aggregate.pipeline.expressions
  3348. * @module mungedb-aggregate
  3349. **/
  3350. var kinds = {
  3351. UNKNOWN: "UNKNOWN",
  3352. OPERATOR: "OPERATOR",
  3353. NOT_OPERATOR: "NOT_OPERATOR"
  3354. };
  3355. // STATIC MEMBERS
  3356. /**
  3357. * Enumeration of comparison operators. These are shared between a few expression implementations, so they are factored out here.
  3358. *
  3359. * @static
  3360. * @property CmpOp
  3361. **/
  3362. klass.CmpOp = {
  3363. EQ: "$eq", // return true for a == b, false otherwise
  3364. NE: "$ne", // return true for a != b, false otherwise
  3365. GT: "$gt", // return true for a > b, false otherwise
  3366. GTE: "$gte", // return true for a >= b, false otherwise
  3367. LT: "$lt", // return true for a < b, false otherwise
  3368. LTE: "$lte", // return true for a <= b, false otherwise
  3369. CMP: "$cmp" // return -1, 0, 1 for a < b, a == b, a > b
  3370. };
  3371. // DEPENDENCIES (later in this file as compared to others to ensure that the required statics are setup first)
  3372. var FieldPathExpression = require("./FieldPathExpression"),
  3373. ObjectExpression = require("./ObjectExpression"),
  3374. ConstantExpression = require("./ConstantExpression"),
  3375. CompareExpression = require("./CompareExpression");
  3376. // DEFERRED DEPENDENCIES
  3377. /**
  3378. * Expressions, as exposed to users
  3379. *
  3380. * @static
  3381. * @property opMap
  3382. **/
  3383. setTimeout(function(){ // Even though `opMap` is deferred, force it to load early rather than later to prevent even *more* potential silliness
  3384. Object.defineProperty(klass, "opMap", {value:klass.opMap});
  3385. }, 0);
  3386. Object.defineProperty(klass, "opMap", { //NOTE: deferred requires using a getter to allow circular requires (to maintain the ported API)
  3387. configurable: true,
  3388. get: function getOpMapOnce() {
  3389. return Object.defineProperty(klass, "opMap", {
  3390. value: [ //NOTE: rather than OpTable because it gets converted to a dict via OpDesc#name in the Array#reduce() below
  3391. new OpDesc("$add", require("./AddExpression"), 0),
  3392. new OpDesc("$and", require("./AndExpression"), 0),
  3393. new OpDesc("$cmp", CompareExpression.bind(null, Expression.CmpOp.CMP), OpDesc.FIXED_COUNT, 2),
  3394. new OpDesc("$concat", require("./ConcatExpression"), 0),
  3395. new OpDesc("$cond", require("./CondExpression"), OpDesc.FIXED_COUNT, 3),
  3396. // $const handled specially in parseExpression
  3397. new OpDesc("$dayOfMonth", require("./DayOfMonthExpression"), OpDesc.FIXED_COUNT, 1),
  3398. new OpDesc("$dayOfWeek", require("./DayOfWeekExpression"), OpDesc.FIXED_COUNT, 1),
  3399. new OpDesc("$dayOfYear", require("./DayOfYearExpression"), OpDesc.FIXED_COUNT, 1),
  3400. new OpDesc("$divide", require("./DivideExpression"), OpDesc.FIXED_COUNT, 2),
  3401. new OpDesc("$eq", CompareExpression.bind(null, Expression.CmpOp.EQ), OpDesc.FIXED_COUNT, 2),
  3402. new OpDesc("$gt", CompareExpression.bind(null, Expression.CmpOp.GT), OpDesc.FIXED_COUNT, 2),
  3403. new OpDesc("$gte", CompareExpression.bind(null, Expression.CmpOp.GTE), OpDesc.FIXED_COUNT, 2),
  3404. new OpDesc("$hour", require("./HourExpression"), OpDesc.FIXED_COUNT, 1),
  3405. new OpDesc("$ifNull", require("./IfNullExpression"), OpDesc.FIXED_COUNT, 2),
  3406. new OpDesc("$lt", CompareExpression.bind(null, Expression.CmpOp.LT), OpDesc.FIXED_COUNT, 2),
  3407. new OpDesc("$lte", CompareExpression.bind(null, Expression.CmpOp.LTE), OpDesc.FIXED_COUNT, 2),
  3408. new OpDesc("$minute", require("./MinuteExpression"), OpDesc.FIXED_COUNT, 1),
  3409. new OpDesc("$mod", require("./ModExpression"), OpDesc.FIXED_COUNT, 2),
  3410. new OpDesc("$month", require("./MonthExpression"), OpDesc.FIXED_COUNT, 1),
  3411. new OpDesc("$multiply", require("./MultiplyExpression"), 0),
  3412. new OpDesc("$ne", CompareExpression.bind(null, Expression.CmpOp.NE), OpDesc.FIXED_COUNT, 2),
  3413. new OpDesc("$not", require("./NotExpression"), OpDesc.FIXED_COUNT, 1),
  3414. new OpDesc("$or", require("./OrExpression"), 0),
  3415. new OpDesc("$second", require("./SecondExpression"), OpDesc.FIXED_COUNT, 1),
  3416. new OpDesc("$strcasecmp", require("./StrcasecmpExpression"), OpDesc.FIXED_COUNT, 2),
  3417. new OpDesc("$substr", require("./SubstrExpression"), OpDesc.FIXED_COUNT, 3),
  3418. new OpDesc("$subtract", require("./SubtractExpression"), OpDesc.FIXED_COUNT, 2),
  3419. new OpDesc("$toLower", require("./ToLowerExpression"), OpDesc.FIXED_COUNT, 1),
  3420. new OpDesc("$toUpper", require("./ToUpperExpression"), OpDesc.FIXED_COUNT, 1),
  3421. new OpDesc("$week", require("./WeekExpression"), OpDesc.FIXED_COUNT, 1),
  3422. new OpDesc("$year", require("./YearExpression"), OpDesc.FIXED_COUNT, 1)
  3423. ].reduce(function(r,o){r[o.name]=o; return r;}, {})
  3424. }).opMap;
  3425. }
  3426. });
  3427. /**
  3428. * Parse an Object. The object could represent a functional expression or a Document expression.
  3429. *
  3430. * An object expression can take any of the following forms:
  3431. *
  3432. * f0: {f1: ..., f2: ..., f3: ...}
  3433. * f0: {$operator:[operand1, operand2, ...]}
  3434. *
  3435. * @static
  3436. * @method parseObject
  3437. * @param obj the element representing the object
  3438. * @param ctx a MiniCtx representing the options above
  3439. * @returns the parsed Expression
  3440. **/
  3441. klass.parseObject = function parseObject(obj, ctx){
  3442. if(!(ctx instanceof ObjectCtx)) throw new Error("ctx must be ObjectCtx");
  3443. var kind = kinds.UNKNOWN,
  3444. expr, // the result
  3445. exprObj; // the alt result
  3446. if (obj === undefined) return new ObjectExpression();
  3447. var fieldNames = Object.keys(obj);
  3448. for (var fc = 0, n = fieldNames.length; fc < n; ++fc) {
  3449. var fn = fieldNames[fc];
  3450. if (fn[0] === "$") {
  3451. if (fc !== 0) throw new Error("the operator must be the only field in a pipeline object (at '" + fn + "'.; code 16410");
  3452. if(ctx.isTopLevel) throw new Error("$expressions are not allowed at the top-level of $project; code 16404");
  3453. kind = kinds.OPERATOR; //we've determined this "object" is an operator expression
  3454. expr = Expression.parseExpression(fn, obj[fn]);
  3455. } else {
  3456. if (kind === kinds.OPERATOR) throw new Error("this object is already an operator expression, and can't be used as a document expression (at '" + fn + "'.; code 15990");
  3457. if (!ctx.isTopLevel && fn.indexOf(".") != -1) throw new Error("dotted field names are only allowed at the top level; code 16405");
  3458. if (expr === undefined) { // if it's our first time, create the document expression
  3459. if (!ctx.isDocumentOk) throw new Error("document not allowed in this context"); // CW TODO error: document not allowed in this context
  3460. expr = exprObj = new ObjectExpression();
  3461. kind = kinds.NOT_OPERATOR; //this "object" is not an operator expression
  3462. }
  3463. var fv = obj[fn];
  3464. switch (typeof(fv)) {
  3465. case "object":
  3466. // it's a nested document
  3467. var subCtx = new ObjectCtx({
  3468. isDocumentOk: ctx.isDocumentOk,
  3469. isInclusionOk: ctx.isInclusionOk
  3470. });
  3471. exprObj.addField(fn, Expression.parseObject(fv, subCtx));
  3472. break;
  3473. case "string":
  3474. // it's a renamed field // CW TODO could also be a constant
  3475. var pathExpr = new FieldPathExpression(Expression.removeFieldPrefix(fv));
  3476. exprObj.addField(fn, pathExpr);
  3477. break;
  3478. case "boolean":
  3479. case "number":
  3480. // it's an inclusion specification
  3481. if (fv) {
  3482. if (!ctx.isInclusionOk) throw new Error("field inclusion is not allowed inside of $expressions; code 16420");
  3483. exprObj.includePath(fn);
  3484. } else {
  3485. if (!(ctx.isTopLevel && fn == Document.ID_PROPERTY_NAME)) throw new Error("The top-level " + Document.ID_PROPERTY_NAME + " field is the only field currently supported for exclusion; code 16406");
  3486. exprObj.excludeId = true;
  3487. }
  3488. break;
  3489. default:
  3490. throw new Error("disallowed field type " + (fv ? fv.constructor.name + ":" : "") + typeof(fv) + " in object expression (at '" + fn + "')");
  3491. }
  3492. }
  3493. }
  3494. return expr;
  3495. };
  3496. /**
  3497. * Parse a BSONElement Object which has already been determined to be functional expression.
  3498. *
  3499. * @static
  3500. * @method parseExpression
  3501. * @param opName the name of the (prefix) operator
  3502. * @param obj the BSONElement to parse
  3503. * @returns the parsed Expression
  3504. **/
  3505. klass.parseExpression = function parseExpression(opName, obj) {
  3506. // look for the specified operator
  3507. if (opName === "$const") return new ConstantExpression(obj); //TODO: createFromBsonElement was here, not needed since this isn't BSON?
  3508. var op = klass.opMap[opName];
  3509. if (!(op instanceof OpDesc)) throw new Error("invalid operator " + opName + "; code 15999");
  3510. // make the expression node
  3511. var IExpression = op.factory, //TODO: should this get renamed from `factory` to `ctor` or something?
  3512. expr = new IExpression();
  3513. // add the operands to the expression node
  3514. if (op.flags & OpDesc.FIXED_COUNT && op.argCount > 1 && !(obj instanceof Array)) throw new Error("the " + op.name + " operator requires an array of " + op.argCount + " operands; code 16019");
  3515. var operand; // used below
  3516. if (obj.constructor === Object) { // the operator must be unary and accept an object argument
  3517. if (!(op.flags & OpDesc.OBJECT_ARG)) throw new Error("the " + op.name + " operator does not accept an object as an operand");
  3518. operand = Expression.parseObject(obj, new ObjectCtx({isDocumentOk: 1}));
  3519. expr.addOperand(operand);
  3520. } else if (obj instanceof Array) { // multiple operands - an n-ary operator
  3521. if (op.flags & OpDesc.FIXED_COUNT && op.argCount !== obj.length) throw new Error("the " + op.name + " operator requires " + op.argCount + " operand(s); code 16020");
  3522. for (var i = 0, n = obj.length; i < n; ++i) {
  3523. operand = Expression.parseOperand(obj[i]);
  3524. expr.addOperand(operand);
  3525. }
  3526. } else { //assume it's an atomic operand
  3527. if (op.flags & OpDesc.FIXED_COUNT && op.argCount != 1) throw new Error("the " + op.name + " operator requires an array of " + op.argCount + " operands; code 16022");
  3528. operand = Expression.parseOperand(obj);
  3529. expr.addOperand(operand);
  3530. }
  3531. return expr;
  3532. };
  3533. /**
  3534. * Parse a BSONElement which is an operand in an Expression.
  3535. *
  3536. * @static
  3537. * @param pBsonElement the expected operand's BSONElement
  3538. * @returns the parsed operand, as an Expression
  3539. **/
  3540. klass.parseOperand = function parseOperand(obj){
  3541. var t = typeof(obj);
  3542. if (t === "string" && obj[0] == "$") { //if we got here, this is a field path expression
  3543. var path = Expression.removeFieldPrefix(obj);
  3544. return new FieldPathExpression(path);
  3545. }
  3546. else if (t === "object" && obj && obj.constructor === Object) return Expression.parseObject(obj, new ObjectCtx({isDocumentOk: true}));
  3547. else return new ConstantExpression(obj);
  3548. };
  3549. /**
  3550. * Produce a field path string with the field prefix removed.
  3551. * Throws an error if the field prefix is not present.
  3552. *
  3553. * @static
  3554. * @param prefixedField the prefixed field
  3555. * @returns the field path with the prefix removed
  3556. **/
  3557. klass.removeFieldPrefix = function removeFieldPrefix(prefixedField) {
  3558. if (prefixedField.indexOf("\0") != -1) throw new Error("field path must not contain embedded null characters; code 16419");
  3559. if (prefixedField[0] !== "$") throw new Error("field path references must be prefixed with a '$' ('" + prefixedField + "'); code 15982");
  3560. return prefixedField.substr(1);
  3561. };
  3562. /**
  3563. * returns the signe of a number
  3564. *
  3565. * @static
  3566. * @method signum
  3567. * @returns the sign of a number; -1, 1, or 0
  3568. **/
  3569. klass.signum = function signum(i) {
  3570. if (i < 0) return -1;
  3571. if (i > 0) return 1;
  3572. return 0;
  3573. };
  3574. // PROTOTYPE MEMBERS
  3575. /**
  3576. * Evaluate the Expression using the given document as input.
  3577. *
  3578. * @method evaluate
  3579. * @returns the computed value
  3580. **/
  3581. proto.evaluate = function evaluate(obj) {
  3582. throw new Error("WAS NOT IMPLEMENTED BY INHERITOR!");
  3583. };
  3584. /**
  3585. * Optimize the Expression.
  3586. *
  3587. * This provides an opportunity to do constant folding, or to collapse nested
  3588. * operators that have the same precedence, such as $add, $and, or $or.
  3589. *
  3590. * The Expression should be replaced with the return value, which may or may
  3591. * not be the same object. In the case of constant folding, a computed
  3592. * expression may be replaced by a constant.
  3593. *
  3594. * @method optimize
  3595. * @returns the optimized Expression
  3596. **/
  3597. proto.optimize = function optimize() {
  3598. throw new Error("WAS NOT IMPLEMENTED BY INHERITOR!");
  3599. };
  3600. /**
  3601. * Add this expression's field dependencies to the set Expressions are trees, so this is often recursive.
  3602. *
  3603. * Top-level ExpressionObject gets pointer to empty vector.
  3604. * If any other Expression is an ancestor, or in other cases where {a:1} inclusion objects aren't allowed, they get NULL.
  3605. *
  3606. * @method addDependencies
  3607. * @param deps output parameter
  3608. * @param path path to self if all ancestors are ExpressionObjects.
  3609. **/
  3610. proto.addDependencies = function addDependencies(deps, path) {
  3611. throw new Error("WAS NOT IMPLEMENTED BY INHERITOR!");
  3612. };
  3613. /**
  3614. * simple expressions are just inclusion exclusion as supported by ExpressionObject
  3615. * @method getIsSimple
  3616. **/
  3617. proto.getIsSimple = function getIsSimple() {
  3618. return false;
  3619. };
  3620. proto.toMatcherBson = function toMatcherBson(){
  3621. throw new Error("WAS NOT IMPLEMENTED BY INHERITOR!"); //verify(false && "Expression::toMatcherBson()");
  3622. };
  3623. },{"../Document":3,"./AddExpression":29,"./AndExpression":30,"./CompareExpression":32,"./ConcatExpression":33,"./CondExpression":34,"./ConstantExpression":35,"./DayOfMonthExpression":36,"./DayOfWeekExpression":37,"./DayOfYearExpression":38,"./DivideExpression":39,"./FieldPathExpression":41,"./HourExpression":43,"./IfNullExpression":44,"./MinuteExpression":45,"./ModExpression":46,"./MonthExpression":47,"./MultiplyExpression":48,"./NotExpression":50,"./ObjectExpression":51,"./OrExpression":52,"./SecondExpression":53,"./StrcasecmpExpression":54,"./SubstrExpression":55,"./SubtractExpression":56,"./ToLowerExpression":57,"./ToUpperExpression":58,"./WeekExpression":59,"./YearExpression":60}],41:[function(require,module,exports){
  3624. "use strict";
  3625. /**
  3626. * Create a field path expression. Evaluation will extract the value associated with the given field path from the source document.
  3627. * @class FieldPathExpression
  3628. * @namespace mungedb-aggregate.pipeline.expressions
  3629. * @module mungedb-aggregate
  3630. * @extends mungedb-aggregate.pipeline.expressions.Expression
  3631. * @constructor
  3632. * @param {String} fieldPath the field path string, without any leading document indicator
  3633. **/
  3634. var FieldPathExpression = module.exports = function FieldPathExpression(path){
  3635. if (arguments.length !== 1) throw new Error("args expected: path");
  3636. this.path = new FieldPath(path);
  3637. }, klass = FieldPathExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3638. // DEPENDENCIES
  3639. var FieldPath = require("../FieldPath");
  3640. // PROTOTYPE MEMBERS
  3641. proto.evaluate = function evaluate(obj){
  3642. return this._evaluatePath(obj, 0, this.path.fields.length);
  3643. };
  3644. /**
  3645. * Internal implementation of evaluate(), used recursively.
  3646. *
  3647. * The internal implementation doesn't just use a loop because of the
  3648. * possibility that we need to skip over an array. If the path is "a.b.c",
  3649. * and a is an array, then we fan out from there, and traverse "b.c" for each
  3650. * element of a:[...]. This requires that a be an array of objects in order
  3651. * to navigate more deeply.
  3652. *
  3653. * @param index current path field index to extract
  3654. * @param pathLength maximum number of fields on field path
  3655. * @param pDocument current document traversed to (not the top-level one)
  3656. * @returns the field found; could be an array
  3657. **/
  3658. proto._evaluatePath = function _evaluatePath(obj, i, len){
  3659. var fieldName = this.path.fields[i],
  3660. field = obj[fieldName]; // It is possible we won't have an obj (document) and we need to not fail if that is the case
  3661. // if the field doesn't exist, quit with an undefined value
  3662. if (field === undefined) return undefined;
  3663. // if we've hit the end of the path, stop
  3664. if (++i >= len) return field;
  3665. // We're diving deeper. If the value was null, return null
  3666. if(field === null) return undefined;
  3667. if (field.constructor === Object) {
  3668. return this._evaluatePath(field, i, len);
  3669. } else if (Array.isArray(field)) {
  3670. var results = [];
  3671. for (var i2 = 0, l2 = field.length; i2 < l2; i2++) {
  3672. var subObj = field[i2],
  3673. subObjType = typeof(subObj);
  3674. if (subObjType === "undefined" || subObj === null) {
  3675. results.push(subObj);
  3676. } else if (subObj.constructor === Object) {
  3677. results.push(this._evaluatePath(subObj, i, len));
  3678. } else {
  3679. throw new Error("the element '" + fieldName + "' along the dotted path '" + this.path.getPath() + "' is not an object, and cannot be navigated.; code 16014");
  3680. }
  3681. }
  3682. return results;
  3683. }
  3684. return undefined;
  3685. };
  3686. proto.optimize = function(){
  3687. return this;
  3688. };
  3689. proto.addDependencies = function addDependencies(deps){
  3690. deps[this.path.getPath()] = 1;
  3691. return deps;
  3692. };
  3693. // renamed write to get because there are no streams
  3694. proto.getFieldPath = function getFieldPath(usePrefix){
  3695. return this.path.getPath(usePrefix);
  3696. };
  3697. proto.toJSON = function toJSON(){
  3698. return this.path.getPath(true);
  3699. };
  3700. //TODO: proto.addToBsonObj = ...?
  3701. //TODO: proto.addToBsonArray = ...?
  3702. //proto.writeFieldPath = ...? use #getFieldPath instead
  3703. },{"../FieldPath":4,"./Expression":40}],42:[function(require,module,exports){
  3704. "use strict";
  3705. /**
  3706. * Create a field range expression.
  3707. *
  3708. * Field ranges are meant to match up with classic Matcher semantics, and therefore are conjunctions.
  3709. *
  3710. * For example, these appear in mongo shell predicates in one of these forms:
  3711. * { a : C } -> (a == C) // degenerate "point" range
  3712. * { a : { $lt : C } } -> (a < C) // open range
  3713. * { a : { $gt : C1, $lte : C2 } } -> ((a > C1) && (a <= C2)) // closed
  3714. *
  3715. * When initially created, a field range only includes one end of the range. Additional points may be added via intersect().
  3716. *
  3717. * Note that NE and CMP are not supported.
  3718. *
  3719. * @class FieldRangeExpression
  3720. * @namespace mungedb-aggregate.pipeline.expressions
  3721. * @module mungedb-aggregate
  3722. * @extends mungedb-aggregate.pipeline.expressions.Expression
  3723. * @constructor
  3724. * @param pathExpr the field path for extracting the field value
  3725. * @param cmpOp the comparison operator
  3726. * @param value the value to compare against
  3727. * @returns the newly created field range expression
  3728. **/
  3729. var FieldRangeExpression = module.exports = function FieldRangeExpression(pathExpr, cmpOp, value){
  3730. if (arguments.length !== 3) throw new Error("args expected: pathExpr, cmpOp, and value");
  3731. this.pathExpr = pathExpr;
  3732. this.range = new Range({cmpOp:cmpOp, value:value});
  3733. }, klass = FieldRangeExpression, Expression = require("./Expression"), base = Expression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3734. // DEPENDENCIES
  3735. var Value = require("../Value"),
  3736. ConstantExpression = require("./ConstantExpression");
  3737. // NESTED CLASSES
  3738. var Range = (function(){
  3739. /**
  3740. * create a new Range; opts is either {cmpOp:..., value:...} or {bottom:..., isBottomOpen:..., top:..., isTopOpen:...}
  3741. * @private
  3742. **/
  3743. var klass = function Range(opts){
  3744. this.isBottomOpen = this.isTopOpen = false;
  3745. this.bottom = this.top = undefined;
  3746. if(opts.hasOwnProperty("cmpOp") && opts.hasOwnProperty("value")){
  3747. switch (opts.cmpOp) {
  3748. case Expression.CmpOp.EQ:
  3749. this.bottom = this.top = opts.value;
  3750. break;
  3751. case Expression.CmpOp.GT:
  3752. this.isBottomOpen = true;
  3753. /* falls through */
  3754. case Expression.CmpOp.GTE:
  3755. this.isTopOpen = true;
  3756. this.bottom = opts.value;
  3757. break;
  3758. case Expression.CmpOp.LT:
  3759. this.isTopOpen = true;
  3760. /* falls through */
  3761. case Expression.CmpOp.LTE:
  3762. this.isBottomOpen = true;
  3763. this.top = opts.value;
  3764. break;
  3765. case Expression.CmpOp.NE:
  3766. case Expression.CmpOp.CMP:
  3767. throw new Error("CmpOp not allowed: " + opts.cmpOp);
  3768. default:
  3769. throw new Error("Unexpected CmpOp: " + opts.cmpOp);
  3770. }
  3771. }else{
  3772. this.bottom = opts.bottom;
  3773. this.isBottomOpen = opts.isBottomOpen;
  3774. this.top = opts.top;
  3775. this.isTopOpen = opts.isTopOpen;
  3776. }
  3777. }, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3778. // PROTOTYPE MEMBERS
  3779. proto.intersect = function intersect(range){
  3780. // Find the max of the bottom end of ranges
  3781. var maxBottom = range.bottom,
  3782. maxBottomOpen = range.isBottomOpen;
  3783. if(this.bottom !== undefined){
  3784. if(range.bottom === undefined){
  3785. maxBottom = this.bottom;
  3786. maxBottomOpen = this.isBottomOpen;
  3787. }else{
  3788. if(Value.compare(this.bottom, range.bottom) === 0){
  3789. maxBottomOpen = this.isBottomOpen || range.isBottomOpen;
  3790. }else{
  3791. maxBottom = this.bottom;
  3792. maxBottomOpen = this.isBottomOpen;
  3793. }
  3794. }
  3795. }
  3796. // Find the min of the tops of the ranges
  3797. var minTop = range.top,
  3798. minTopOpen = range.isTopOpen;
  3799. if(this.top !== undefined){
  3800. if(range.top === undefined){
  3801. minTop = this.top;
  3802. minTopOpen = this.isTopOpen;
  3803. }else{
  3804. if(Value.compare(this.top, range.top) === 0){
  3805. minTopOpen = this.isTopOpen || range.isTopOpen;
  3806. }else{
  3807. minTop = this.top;
  3808. minTopOpen = this.isTopOpen;
  3809. }
  3810. }
  3811. }
  3812. if(Value.compare(maxBottom, minTop) <= 0)
  3813. return new Range({bottom:maxBottom, isBottomOpen:maxBottomOpen, top:minTop, isTopOpen:minTopOpen});
  3814. return null; // empty intersection
  3815. };
  3816. proto.contains = function contains(value){
  3817. var cmp;
  3818. if(this.bottom !== undefined){
  3819. cmp = Value.compare(value, this.bottom);
  3820. if(cmp < 0) return false;
  3821. if(this.isBottomOpen && cmp === 0) return false;
  3822. }
  3823. if(this.top !== undefined){
  3824. cmp = Value.compare(value, this.top);
  3825. if(cmp > 0) return false;
  3826. if(this.isTopOpen && cmp === 0) return false;
  3827. }
  3828. return true;
  3829. };
  3830. return klass;
  3831. })();
  3832. // PROTOTYPE MEMBERS
  3833. proto.evaluate = function evaluate(obj){
  3834. if(this.range === undefined) return false;
  3835. var value = this.pathExpr.evaluate(obj);
  3836. return this.range.contains(value);
  3837. };
  3838. proto.optimize = function optimize(){
  3839. if(this.range === undefined) return new ConstantExpression(false);
  3840. if(this.range.bottom === undefined && this.range.top === undefined) return new ConstantExpression(true);
  3841. return this;
  3842. };
  3843. proto.addDependencies = function(deps){
  3844. return this.pathExpr.addDependencies(deps);
  3845. };
  3846. /**
  3847. * Add an intersecting range.
  3848. *
  3849. * This can be done any number of times after creation. The range is
  3850. * internally optimized for each new addition. If the new intersection
  3851. * extends or reduces the values within the range, the internal
  3852. * representation is adjusted to reflect that.
  3853. *
  3854. * Note that NE and CMP are not supported.
  3855. *
  3856. * @method intersect
  3857. * @param cmpOp the comparison operator
  3858. * @param pValue the value to compare against
  3859. **/
  3860. proto.intersect = function intersect(cmpOp, value){
  3861. this.range = this.range.intersect(new Range({cmpOp:cmpOp, value:value}));
  3862. };
  3863. proto.toJSON = function toJSON(){
  3864. if (this.range === undefined) return false; //nothing will satisfy this predicate
  3865. if (this.range.top === undefined && this.range.bottom === undefined) return true; // any value will satisfy this predicate
  3866. // FIXME Append constant values using the $const operator. SERVER-6769
  3867. var json = {};
  3868. if (this.range.top === this.range.bottom) {
  3869. json[Expression.CmpOp.EQ] = [this.pathExpr.toJSON(), this.range.top];
  3870. }else{
  3871. var leftOp = {};
  3872. if (this.range.bottom !== undefined) {
  3873. leftOp[this.range.isBottomOpen ? Expression.CmpOp.GT : Expression.CmpOp.GTE] = [this.pathExpr.toJSON(), this.range.bottom];
  3874. if (this.range.top === undefined) return leftOp;
  3875. }
  3876. var rightOp = {};
  3877. if(this.range.top !== undefined){
  3878. rightOp[this.range.isTopOpen ? Expression.CmpOp.LT : Expression.CmpOp.LTE] = [this.pathExpr.toJSON(), this.range.top];
  3879. if (this.range.bottom === undefined) return rightOp;
  3880. }
  3881. json.$and = [leftOp, rightOp];
  3882. }
  3883. return json;
  3884. };
  3885. //TODO: proto.addToBson = ...?
  3886. //TODO: proto.addToBsonObj = ...?
  3887. //TODO: proto.addToBsonArray = ...?
  3888. //TODO: proto.toMatcherBson = ...? WILL PROBABLY NEED THESE...
  3889. },{"../Value":7,"./ConstantExpression":35,"./Expression":40}],43:[function(require,module,exports){
  3890. "use strict";
  3891. /**
  3892. * An $hour pipeline expression.
  3893. * @see evaluate
  3894. * @class HourExpression
  3895. * @namespace mungedb-aggregate.pipeline.expressions
  3896. * @module mungedb-aggregate
  3897. * @constructor
  3898. **/
  3899. var HourExpression = module.exports = function HourExpression(){
  3900. if (arguments.length !== 0) throw new Error("zero args expected");
  3901. base.call(this);
  3902. }, klass = HourExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3903. // PROTOTYPE MEMBERS
  3904. proto.getOpName = function getOpName(){
  3905. return "$hour";
  3906. };
  3907. proto.addOperand = function addOperand(expr) {
  3908. this.checkArgLimit(1);
  3909. base.prototype.addOperand.call(this, expr);
  3910. };
  3911. /**
  3912. * Takes a date and returns the hour between 0 and 23.
  3913. * @method evaluate
  3914. **/
  3915. proto.evaluate = function evaluate(doc){
  3916. this.checkArgCount(1);
  3917. var date = this.operands[0].evaluate(doc);
  3918. return date.getUTCHours();
  3919. };
  3920. },{"./NaryExpression":49}],44:[function(require,module,exports){
  3921. "use strict";
  3922. /**
  3923. * An $ifNull pipeline expression.
  3924. * @see evaluate
  3925. * @class IfNullExpression
  3926. * @namespace mungedb-aggregate.pipeline.expressions
  3927. * @module mungedb-aggregate
  3928. * @constructor
  3929. **/
  3930. var IfNullExpression = module.exports = function IfNullExpression(){
  3931. if (arguments.length !== 0) throw new Error("zero args expected");
  3932. base.call(this);
  3933. }, klass = IfNullExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3934. // PROTOTYPE MEMBERS
  3935. proto.getOpName = function getOpName(){
  3936. return "$ifNull";
  3937. };
  3938. proto.addOperand = function addOperand(expr) {
  3939. this.checkArgLimit(2);
  3940. base.prototype.addOperand.call(this, expr);
  3941. };
  3942. /**
  3943. * Use the $ifNull operator with the following syntax: { $ifNull: [ <expression>, <replacement-if-null> ] }
  3944. * @method evaluate
  3945. **/
  3946. proto.evaluate = function evaluate(doc){
  3947. this.checkArgCount(2);
  3948. var left = this.operands[0].evaluate(doc);
  3949. if(left !== undefined && left !== null) return left;
  3950. var right = this.operands[1].evaluate(doc);
  3951. return right;
  3952. };
  3953. },{"./NaryExpression":49}],45:[function(require,module,exports){
  3954. "use strict";
  3955. /**
  3956. * An $minute pipeline expression.
  3957. * @see evaluate
  3958. * @class MinuteExpression
  3959. * @namespace mungedb-aggregate.pipeline.expressions
  3960. * @module mungedb-aggregate
  3961. * @constructor
  3962. **/
  3963. var MinuteExpression = module.exports = function MinuteExpression(){
  3964. if (arguments.length !== 0) throw new Error("zero args expected");
  3965. base.call(this);
  3966. }, klass = MinuteExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3967. // PROTOTYPE MEMBERS
  3968. proto.getOpName = function getOpName(){
  3969. return "$minute";
  3970. };
  3971. proto.addOperand = function addOperand(expr) {
  3972. this.checkArgLimit(1);
  3973. base.prototype.addOperand.call(this, expr);
  3974. };
  3975. /**
  3976. * Takes a date and returns the minute between 0 and 59.
  3977. * @method evaluate
  3978. **/
  3979. proto.evaluate = function evaluate(doc){
  3980. this.checkArgCount(1);
  3981. var date = this.operands[0].evaluate(doc);
  3982. return date.getUTCMinutes();
  3983. };
  3984. },{"./NaryExpression":49}],46:[function(require,module,exports){
  3985. "use strict";
  3986. /**
  3987. * An $mod pipeline expression.
  3988. * @see evaluate
  3989. * @class ModExpression
  3990. * @namespace mungedb-aggregate.pipeline.expressions
  3991. * @module mungedb-aggregate
  3992. * @constructor
  3993. **/
  3994. var ModExpression = module.exports = function ModExpression(){
  3995. if (arguments.length !== 0) throw new Error("zero args expected");
  3996. base.call(this);
  3997. }, klass = ModExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  3998. // DEPENDENCIES
  3999. var Value = require("../Value");
  4000. // PROTOTYPE MEMBERS
  4001. proto.getOpName = function getOpName(){
  4002. return "$mod";
  4003. };
  4004. proto.addOperand = function addOperand(expr) {
  4005. this.checkArgLimit(2);
  4006. base.prototype.addOperand.call(this, expr);
  4007. };
  4008. /**
  4009. * Takes an array that contains a pair of numbers and returns the remainder of the first number divided by the second number.
  4010. * @method evaluate
  4011. **/
  4012. proto.evaluate = function evaluate(doc){
  4013. this.checkArgCount(2);
  4014. var left = this.operands[0].evaluate(doc),
  4015. right = this.operands[1].evaluate(doc);
  4016. if(left instanceof Date || right instanceof Date) throw new Error("$mod does not support dates; code 16374");
  4017. // pass along jstNULLs and Undefineds
  4018. if(left === undefined || left === null) return left;
  4019. if(right === undefined || right === null) return right;
  4020. // ensure we aren't modding by 0
  4021. right = Value.coerceToDouble(right);
  4022. if(right === 0) return undefined;
  4023. left = Value.coerceToDouble(left);
  4024. return left % right;
  4025. };
  4026. },{"../Value":7,"./NaryExpression":49}],47:[function(require,module,exports){
  4027. "use strict";
  4028. /**
  4029. * A $month pipeline expression.
  4030. * @see evaluate
  4031. * @class MonthExpression
  4032. * @namespace mungedb-aggregate.pipeline.expressions
  4033. * @module mungedb-aggregate
  4034. * @constructor
  4035. **/
  4036. var MonthExpression = module.exports = function MonthExpression(){
  4037. if (arguments.length !== 0) throw new Error("zero args expected");
  4038. base.call(this);
  4039. }, klass = MonthExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4040. // PROTOTYPE MEMBERS
  4041. proto.getOpName = function getOpName(){
  4042. return "$month";
  4043. };
  4044. proto.addOperand = function addOperand(expr) {
  4045. this.checkArgLimit(1);
  4046. base.prototype.addOperand.call(this, expr);
  4047. };
  4048. /**
  4049. * Takes a date and returns the month as a number between 1 and 12.
  4050. * @method evaluate
  4051. **/
  4052. proto.evaluate = function evaluate(doc){
  4053. this.checkArgCount(1);
  4054. var date = this.operands[0].evaluate(doc);
  4055. return date.getUTCMonth() + 1;
  4056. };
  4057. },{"./NaryExpression":49}],48:[function(require,module,exports){
  4058. "use strict";
  4059. /**
  4060. * A $multiply pipeline expression.
  4061. * @see evaluate
  4062. * @class MultiplyExpression
  4063. * @namespace mungedb-aggregate.pipeline.expressions
  4064. * @module mungedb-aggregate
  4065. * @constructor
  4066. **/
  4067. var MultiplyExpression = module.exports = function MultiplyExpression(){
  4068. if (arguments.length !== 0) throw new Error("zero args expected");
  4069. base.call(this);
  4070. }, klass = MultiplyExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4071. // DEPENDENCIES
  4072. var Value = require("../Value");
  4073. // PROTOTYPE MEMBERS
  4074. proto.getOpName = function getOpName(){
  4075. return "$multiply";
  4076. };
  4077. /**
  4078. * Takes an array of one or more numbers and multiples them, returning the resulting product.
  4079. * @method evaluate
  4080. **/
  4081. proto.evaluate = function evaluate(doc){
  4082. var product = 1;
  4083. for(var i = 0, n = this.operands.length; i < n; ++i){
  4084. var value = this.operands[i].evaluate(doc);
  4085. if(value instanceof Date) throw new Error("$multiply does not support dates; code 16375");
  4086. product *= Value.coerceToDouble(value);
  4087. }
  4088. if(typeof(product) != "number") throw new Error("$multiply resulted in a non-numeric type; code 16418");
  4089. return product;
  4090. };
  4091. proto.getFactory = function getFactory(){
  4092. return klass; // using the ctor rather than a separate .create() method
  4093. };
  4094. },{"../Value":7,"./NaryExpression":49}],49:[function(require,module,exports){
  4095. "use strict";
  4096. /**
  4097. * The base class for all n-ary `Expression`s
  4098. * @class NaryExpression
  4099. * @namespace mungedb-aggregate.pipeline.expressions
  4100. * @module mungedb-aggregate
  4101. * @extends mungedb-aggregate.pipeline.expressions.Expression
  4102. * @constructor
  4103. **/
  4104. var NaryExpression = module.exports = function NaryExpression(){
  4105. if (arguments.length !== 0) throw new Error("zero args expected");
  4106. this.operands = [];
  4107. base.call(this);
  4108. }, klass = NaryExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4109. // DEPENDENCIES
  4110. var ConstantExpression = require("./ConstantExpression");
  4111. // PROTOTYPE MEMBERS
  4112. proto.evaluate = undefined; // evaluate(doc){ ... defined by inheritor ... }
  4113. proto.getOpName = function getOpName(doc){
  4114. throw new Error("NOT IMPLEMENTED BY INHERITOR");
  4115. };
  4116. proto.optimize = function optimize(){
  4117. var constsFound = 0,
  4118. stringsFound = 0;
  4119. for (var i = 0, l = this.operands.length; i < l; i++) {
  4120. var optimizedExpr = this.operands[i].optimize();
  4121. if (optimizedExpr instanceof ConstantExpression) {
  4122. constsFound++;
  4123. if (typeof(optimizedExpr.value) == "string") stringsFound++;
  4124. }
  4125. this.operands[i] = optimizedExpr;
  4126. }
  4127. // If all the operands are constant, we can replace this expression with a constant. We can find the value by evaluating this expression over a NULL Document because evaluating the ExpressionConstant never refers to the argument Document.
  4128. if (constsFound === l) return new ConstantExpression(this.evaluate());
  4129. // If there are any strings, we can't re-arrange anything, so stop now. LATER: we could concatenate adjacent strings as a special case.
  4130. if (stringsFound) return this;
  4131. // If there's no more than one constant, then we can't do any constant folding, so don't bother going any further.
  4132. if (constsFound <= 1) return this;
  4133. // If the operator isn't commutative or associative, there's nothing more we can do. We test that by seeing if we can get a factory; if we can, we can use it to construct a temporary expression which we'll evaluate to collapse as many constants as we can down to a single one.
  4134. var IExpression = this.getFactory();
  4135. if (!(IExpression instanceof Function)) return this;
  4136. // Create a new Expression that will be the replacement for this one. We actually create two: one to hold constant expressions, and one to hold non-constants.
  4137. // Once we've got these, we evaluate the constant expression to produce a single value, as above. We then add this operand to the end of the non-constant expression, and return that.
  4138. var expr = new IExpression(),
  4139. constExpr = new IExpression();
  4140. for (i = 0; i < l; ++i) {
  4141. var operandExpr = this.operands[i];
  4142. if (operandExpr instanceof ConstantExpression) {
  4143. constExpr.addOperand(operandExpr);
  4144. } else {
  4145. // If the child operand is the same type as this, then we can extract its operands and inline them here because we already know this is commutative and associative because it has a factory. We can detect sameness of the child operator by checking for equality of the factory
  4146. // Note we don't have to do this recursively, because we called optimize() on all the children first thing in this call to optimize().
  4147. if (!(operandExpr instanceof NaryExpression)) {
  4148. expr.addOperand(operandExpr);
  4149. } else {
  4150. if (operandExpr.getFactory() !== IExpression) {
  4151. expr.addOperand(operandExpr);
  4152. } else { // same factory, so flatten
  4153. for (var i2 = 0, n2 = operandExpr.operands.length; i2 < n2; ++i2) {
  4154. var childOperandExpr = operandExpr.operands[i2];
  4155. if (childOperandExpr instanceof ConstantExpression) {
  4156. constExpr.addOperand(childOperandExpr);
  4157. } else {
  4158. expr.addOperand(childOperandExpr);
  4159. }
  4160. }
  4161. }
  4162. }
  4163. }
  4164. }
  4165. if (constExpr.operands.length === 1) { // If there was only one constant, add it to the end of the expression operand vector.
  4166. expr.addOperand(constExpr.operands[0]);
  4167. } else if (constExpr.operands.length > 1) { // If there was more than one constant, collapse all the constants together before adding the result to the end of the expression operand vector.
  4168. var pResult = constExpr.evaluate();
  4169. expr.addOperand(new ConstantExpression(pResult));
  4170. }
  4171. return expr;
  4172. };
  4173. proto.addDependencies = function addDependencies(deps){
  4174. for(var i = 0, l = this.operands.length; i < l; ++i)
  4175. this.operands[i].addDependencies(deps);
  4176. return deps;
  4177. };
  4178. /**
  4179. * Add an operand to the n-ary expression.
  4180. * @method addOperand
  4181. * @param pExpression the expression to add
  4182. **/
  4183. proto.addOperand = function addOperand(expr) {
  4184. this.operands.push(expr);
  4185. };
  4186. proto.getFactory = function getFactory() {
  4187. return undefined;
  4188. };
  4189. proto.toJSON = function toJSON() {
  4190. var o = {};
  4191. o[this.getOpName()] = this.operands.map(function(operand){
  4192. return operand.toJSON();
  4193. });
  4194. return o;
  4195. };
  4196. //TODO: proto.toBson ? DONE NOW???
  4197. //TODO: proto.addToBsonObj ?
  4198. //TODO: proto.addToBsonArray ?
  4199. /**
  4200. * Checks the current size of vpOperand; if the size equal to or greater than maxArgs, fires a user assertion indicating that this operator cannot have this many arguments.
  4201. * The equal is there because this is intended to be used in addOperand() to check for the limit *before* adding the requested argument.
  4202. *
  4203. * @method checkArgLimit
  4204. * @param maxArgs the maximum number of arguments the operator accepts
  4205. **/
  4206. proto.checkArgLimit = function checkArgLimit(maxArgs) {
  4207. if (this.operands.length >= maxArgs) throw new Error(this.getOpName() + " only takes " + maxArgs + " operand" + (maxArgs == 1 ? "" : "s") + "; code 15993");
  4208. };
  4209. /**
  4210. * Checks the current size of vpOperand; if the size is not equal to reqArgs, fires a user assertion indicating that this must have exactly reqArgs arguments.
  4211. * This is meant to be used in evaluate(), *before* the evaluation takes place.
  4212. *
  4213. * @method checkArgCount
  4214. * @param reqArgs the number of arguments this operator requires
  4215. **/
  4216. proto.checkArgCount = function checkArgCount(reqArgs) {
  4217. if (this.operands.length !== reqArgs) throw new Error(this.getOpName() + ": insufficient operands; " + reqArgs + " required, only got " + this.operands.length + "; code 15997");
  4218. };
  4219. },{"./ConstantExpression":35,"./Expression":40}],50:[function(require,module,exports){
  4220. "use strict";
  4221. /**
  4222. * A $not pipeline expression.
  4223. * @see evaluate
  4224. * @class NotExpression
  4225. * @namespace mungedb-aggregate.pipeline.expressions
  4226. * @module mungedb-aggregate
  4227. * @constructor
  4228. **/
  4229. var NotExpression = module.exports = function NotExpression(){
  4230. if (arguments.length !== 0) throw new Error("zero args expected");
  4231. base.call(this);
  4232. }, klass = NotExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4233. // DEPENDENCIES
  4234. var Value = require("../Value");
  4235. // PROTOTYPE MEMBERS
  4236. proto.getOpName = function getOpName(){
  4237. return "$not";
  4238. };
  4239. proto.addOperand = function addOperand(expr) {
  4240. this.checkArgLimit(1);
  4241. base.prototype.addOperand.call(this, expr);
  4242. };
  4243. /**
  4244. * Returns the boolean opposite value passed to it. When passed a true value, $not returns false; when passed a false value, $not returns true.
  4245. * @method evaluate
  4246. **/
  4247. proto.evaluate = function evaluate(doc){
  4248. this.checkArgCount(1);
  4249. var op = this.operands[0].evaluate(doc);
  4250. return !Value.coerceToBool(op);
  4251. };
  4252. },{"../Value":7,"./NaryExpression":49}],51:[function(require,module,exports){
  4253. "use strict";
  4254. /**
  4255. * Create an empty expression. Until fields are added, this will evaluate to an empty document (object).
  4256. * @class ObjectExpression
  4257. * @namespace mungedb-aggregate.pipeline.expressions
  4258. * @module mungedb-aggregate
  4259. * @extends mungedb-aggregate.pipeline.expressions.Expression
  4260. * @constructor
  4261. **/
  4262. var ObjectExpression = module.exports = function ObjectExpression(){
  4263. if (arguments.length !== 0) throw new Error("zero args expected");
  4264. this.excludeId = false; /// <Boolean> for if _id is to be excluded
  4265. this._expressions = {}; /// <Object<Expression>> mapping from fieldname to Expression to generate the value NULL expression means include from source document
  4266. this._order = []; /// <Array<String>> this is used to maintain order for generated fields not in the source document
  4267. }, klass = ObjectExpression, Expression = require("./Expression"), base = Expression, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4268. // DEPENDENCIES
  4269. var Document = require("../Document"),
  4270. FieldPath = require("../FieldPath");
  4271. // INSTANCE VARIABLES
  4272. /**
  4273. * <Boolean> for if _id is to be excluded
  4274. * @property excludeId
  4275. **/
  4276. proto.excludeId = undefined;
  4277. /**
  4278. * <Object<Expression>> mapping from fieldname to Expression to generate the value NULL expression means include from source document
  4279. **/
  4280. proto._expressions = undefined;
  4281. //TODO: might be able to completely ditch _order everywhere in here since `Object`s are mostly ordered anyhow but need to come back and revisit that later
  4282. /**
  4283. * <Array<String>> this is used to maintain order for generated fields not in the source document
  4284. **/
  4285. proto._order = [];
  4286. // PROTOTYPE MEMBERS
  4287. /**
  4288. * evaluate(), but return a Document instead of a Value-wrapped Document.
  4289. * @method evaluateDocument
  4290. * @param pDocument the input Document
  4291. * @returns the result document
  4292. **/
  4293. proto.evaluateDocument = function evaluateDocument(doc) {
  4294. // create and populate the result
  4295. var pResult = {};
  4296. this.addToDocument(pResult, pResult, doc); // No inclusion field matching.
  4297. return pResult;
  4298. };
  4299. proto.evaluate = function evaluate(doc) { //TODO: collapse with #evaluateDocument()?
  4300. return this.evaluateDocument(doc);
  4301. };
  4302. proto.optimize = function optimize(){
  4303. for (var key in this._expressions) {
  4304. var expr = this._expressions[key];
  4305. if (expr !== undefined && expr !== null) this._expressions[key] = expr.optimize();
  4306. }
  4307. return this;
  4308. };
  4309. proto.getIsSimple = function getIsSimple(){
  4310. for (var key in this._expressions) {
  4311. var expr = this._expressions[key];
  4312. if (expr !== undefined && expr !== null && !expr.getIsSimple()) return false;
  4313. }
  4314. return true;
  4315. };
  4316. proto.addDependencies = function addDependencies(deps, path){
  4317. var depsSet = {};
  4318. var pathStr = "";
  4319. if (path instanceof Array) {
  4320. if (path.length === 0) {
  4321. // we are in the top level of a projection so _id is implicit
  4322. if (!this.excludeId) depsSet[Document.ID_PROPERTY_NAME] = 1;
  4323. } else {
  4324. pathStr = new FieldPath(path).getPath() + ".";
  4325. }
  4326. } else {
  4327. if (this.excludeId) throw new Error("excludeId is true!");
  4328. }
  4329. for (var key in this._expressions) {
  4330. var expr = this._expressions[key];
  4331. if (expr !== undefined && expr !== null) {
  4332. if (path instanceof Array) path.push(key);
  4333. expr.addDependencies(deps, path);
  4334. if (path instanceof Array) path.pop();
  4335. } else { // inclusion
  4336. if (path === undefined || path === null) throw new Error("inclusion not supported in objects nested in $expressions; uassert code 16407");
  4337. depsSet[pathStr + key] = 1;
  4338. }
  4339. }
  4340. //Array.prototype.push.apply(deps, Object.getOwnPropertyNames(depsSet));
  4341. for(key in depsSet) {
  4342. deps[key] = 1;
  4343. }
  4344. return deps; // NOTE: added to munge as a convenience
  4345. };
  4346. /**
  4347. * evaluate(), but add the evaluated fields to a given document instead of creating a new one.
  4348. * @method addToDocument
  4349. * @param pResult the Document to add the evaluated expressions to
  4350. * @param pDocument the input Document for this level
  4351. * @param rootDoc the root of the whole input document
  4352. **/
  4353. proto.addToDocument = function addToDocument(pResult, pDocument, rootDoc){
  4354. var atRoot = (pDocument === rootDoc);
  4355. var doneFields = {}; // This is used to mark fields we've done so that we can add the ones we haven't
  4356. for(var fieldName in pDocument){
  4357. if (!pDocument.hasOwnProperty(fieldName)) continue;
  4358. var fieldValue = pDocument[fieldName];
  4359. // This field is not supposed to be in the output (unless it is _id)
  4360. if (!this._expressions.hasOwnProperty(fieldName)) {
  4361. if (!this.excludeId && atRoot && fieldName == Document.ID_PROPERTY_NAME) {
  4362. // _id from the root doc is always included (until exclusion is supported)
  4363. // not updating doneFields since "_id" isn't in _expressions
  4364. pResult[fieldName] = fieldValue;
  4365. }
  4366. continue;
  4367. }
  4368. // make sure we don't add this field again
  4369. doneFields[fieldName] = true;
  4370. // This means pull the matching field from the input document
  4371. var expr = this._expressions[fieldName];
  4372. if (!(expr instanceof Expression)) {
  4373. pResult[fieldName] = fieldValue;
  4374. continue;
  4375. }
  4376. // Check if this expression replaces the whole field
  4377. if (!(fieldValue instanceof Object) || (fieldValue.constructor !== Object && fieldValue.constructor !== Array) || !(expr instanceof ObjectExpression)) {
  4378. var pValue = expr.evaluate(rootDoc);
  4379. // don't add field if nothing was found in the subobject
  4380. if (expr instanceof ObjectExpression && pValue instanceof Object && Object.getOwnPropertyNames(pValue).length === 0) continue;
  4381. // Don't add non-existent values (note: different from NULL); this is consistent with existing selection syntax which doesn't force the appearnance of non-existent fields.
  4382. // TODO make missing distinct from Undefined
  4383. if (pValue !== undefined) pResult[fieldName] = pValue;
  4384. continue;
  4385. }
  4386. // Check on the type of the input value. If it's an object, just walk down into that recursively, and add it to the result.
  4387. if (fieldValue instanceof Object && fieldValue.constructor === Object) {
  4388. pResult[fieldName] = expr.addToDocument({}, fieldValue, rootDoc); //TODO: pretty sure this is broken;
  4389. } else if (fieldValue instanceof Object && fieldValue.constructor === Array) {
  4390. // If it's an array, we have to do the same thing, but to each array element. Then, add the array of results to the current document.
  4391. var result = [];
  4392. for(var fvi = 0, fvl = fieldValue.length; fvi < fvl; fvi++){
  4393. var subValue = fieldValue[fvi];
  4394. if (subValue.constructor !== Object) continue; // can't look for a subfield in a non-object value.
  4395. result.push(expr.addToDocument({}, subValue, rootDoc));
  4396. }
  4397. pResult[fieldName] = result;
  4398. } else {
  4399. throw new Error("should never happen"); //verify( false );
  4400. }
  4401. }
  4402. if (Object.getOwnPropertyNames(doneFields).length == Object.getOwnPropertyNames(this._expressions).length) return pResult; //NOTE: munge returns result as a convenience
  4403. // add any remaining fields we haven't already taken care of
  4404. for(var i = 0, l = this._order.length; i < l; i++){
  4405. var fieldName2 = this._order[i];
  4406. var expr2 = this._expressions[fieldName2];
  4407. // if we've already dealt with this field, above, do nothing
  4408. if (doneFields.hasOwnProperty(fieldName2)) continue;
  4409. // this is a missing inclusion field
  4410. if (!expr2) continue;
  4411. var value = expr2.evaluate(rootDoc);
  4412. // Don't add non-existent values (note: different from NULL); this is consistent with existing selection syntax which doesn't force the appearnance of non-existent fields.
  4413. if (value === undefined) continue;
  4414. // don't add field if nothing was found in the subobject
  4415. if (expr2 instanceof ObjectExpression && value && value instanceof Object && Object.getOwnPropertyNames(value).length === 0) continue;
  4416. pResult[fieldName2] = value;
  4417. }
  4418. return pResult; //NOTE: munge returns result as a convenience
  4419. };
  4420. /**
  4421. * estimated number of fields that will be output
  4422. * @method getSizeHint
  4423. **/
  4424. proto.getSizeHint = function getSizeHint(){
  4425. // Note: this can overestimate, but that is better than underestimating
  4426. return Object.getOwnPropertyNames(this._expressions).length + (this.excludeId ? 0 : 1);
  4427. };
  4428. /**
  4429. * Add a field to the document expression.
  4430. * @method addField
  4431. * @param fieldPath the path the evaluated expression will have in the result Document
  4432. * @param pExpression the expression to evaluate obtain this field's Value in the result Document
  4433. **/
  4434. proto.addField = function addField(fieldPath, pExpression){
  4435. if(!(fieldPath instanceof FieldPath)) fieldPath = new FieldPath(fieldPath);
  4436. var fieldPart = fieldPath.fields[0],
  4437. haveExpr = this._expressions.hasOwnProperty(fieldPart),
  4438. subObj = this._expressions[fieldPart]; // inserts if !haveExpr //NOTE: not in munge & JS it doesn't, handled manually below
  4439. if (!haveExpr) {
  4440. this._order.push(fieldPart);
  4441. } else { // we already have an expression or inclusion for this field
  4442. if (fieldPath.getPathLength() == 1) { // This expression is for right here
  4443. if (!(subObj instanceof ObjectExpression && typeof pExpression == "object" && pExpression instanceof ObjectExpression)){
  4444. throw new Error("can't add an expression for field `" + fieldPart + "` because there is already an expression for that field or one of its sub-fields; uassert code 16400"); // we can merge them
  4445. }
  4446. // Copy everything from the newSubObj to the existing subObj
  4447. // This is for cases like { $project:{ 'b.c':1, b:{ a:1 } } }
  4448. for (var key in pExpression._expressions) {
  4449. if (pExpression._expressions.hasOwnProperty(key)) {
  4450. subObj.addField(key, pExpression._expressions[key]); // asserts if any fields are dupes
  4451. }
  4452. }
  4453. return;
  4454. } else { // This expression is for a subfield
  4455. if(!subObj) throw new Error("can't add an expression for a subfield of `" + fieldPart + "` because there is already an expression that applies to the whole field; uassert code 16401");
  4456. }
  4457. }
  4458. if (fieldPath.getPathLength() == 1) {
  4459. if(haveExpr) throw new Error("Internal error."); // haveExpr case handled above.
  4460. this._expressions[fieldPart] = pExpression;
  4461. return;
  4462. }
  4463. if (!haveExpr) subObj = this._expressions[fieldPart] = new ObjectExpression();
  4464. subObj.addField(fieldPath.tail(), pExpression);
  4465. };
  4466. /**
  4467. * Add a field path to the set of those to be included.
  4468. *
  4469. * Note that including a nested field implies including everything on the path leading down to it.
  4470. *
  4471. * @method includePath
  4472. * @param fieldPath the name of the field to be included
  4473. **/
  4474. proto.includePath = function includePath(path){
  4475. this.addField(path, undefined);
  4476. };
  4477. /**
  4478. * Get a count of the added fields.
  4479. * @method getFieldCount
  4480. * @returns how many fields have been added
  4481. **/
  4482. proto.getFieldCount = function getFieldCount(){
  4483. return Object.getOwnPropertyNames(this._expressions).length;
  4484. };
  4485. ///**
  4486. //* Specialized BSON conversion that allows for writing out a $project specification.
  4487. //* This creates a standalone object, which must be added to a containing object with a name
  4488. //*
  4489. //* @param pBuilder where to write the object to
  4490. //* @param requireExpression see Expression::addToBsonObj
  4491. //**/
  4492. //TODO: proto.documentToBson = ...?
  4493. //TODO: proto.addToBsonObj = ...?
  4494. //TODO: proto.addToBsonArray = ...?
  4495. //NOTE: in `munge` we're not passing the `Object`s in and allowing `toJSON` (was `documentToBson`) to modify it directly and are instead building and returning a new `Object` since that's the way it's actually used
  4496. proto.toJSON = function toJSON(requireExpression){
  4497. var o = {};
  4498. if (this.excludeId) o[Document.ID_PROPERTY_NAME] = false;
  4499. for (var i = 0, l = this._order.length; i < l; i++) {
  4500. var fieldName = this._order[i];
  4501. if (!this._expressions.hasOwnProperty(fieldName)) throw new Error("internal error: fieldName from _ordered list not found in _expressions");
  4502. var fieldValue = this._expressions[fieldName];
  4503. if (fieldValue === undefined) {
  4504. o[fieldName] = true; // this is inclusion, not an expression
  4505. } else {
  4506. o[fieldName] = fieldValue.toJSON(requireExpression);
  4507. }
  4508. }
  4509. return o;
  4510. };
  4511. },{"../Document":3,"../FieldPath":4,"./Expression":40}],52:[function(require,module,exports){
  4512. "use strict";
  4513. /**
  4514. * An $or pipeline expression.
  4515. * @see evaluate
  4516. * @class OrExpression
  4517. * @namespace mungedb-aggregate.pipeline.expressions
  4518. * @module mungedb-aggregate
  4519. * @constructor
  4520. **/
  4521. var OrExpression = module.exports = function OrExpression(){
  4522. if (arguments.length !== 0) throw new Error("zero args expected");
  4523. base.call(this);
  4524. }, klass = OrExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4525. // DEPENDENCIES
  4526. var Value = require("../Value"),
  4527. ConstantExpression = require("./ConstantExpression"),
  4528. CoerceToBoolExpression = require("./CoerceToBoolExpression");
  4529. // PROTOTYPE MEMBERS
  4530. proto.getOpName = function getOpName(){
  4531. return "$or";
  4532. };
  4533. /**
  4534. * Takes an array of one or more values and returns true if any of the values in the array are true. Otherwise $or returns false.
  4535. * @method evaluate
  4536. **/
  4537. proto.evaluate = function evaluate(doc){
  4538. for(var i = 0, n = this.operands.length; i < n; ++i){
  4539. var value = this.operands[i].evaluate(doc);
  4540. if (Value.coerceToBool(value)) return true;
  4541. }
  4542. return false;
  4543. };
  4544. proto.optimize = function optimize() {
  4545. var pE = base.prototype.optimize.call(this); // optimize the disjunction as much as possible
  4546. if (!(pE instanceof OrExpression)) return pE; // if the result isn't a disjunction, we can't do anything
  4547. var pOr = pE;
  4548. // Check the last argument on the result; if it's not const (as promised
  4549. // by ExpressionNary::optimize(),) then there's nothing we can do.
  4550. var n = pOr.operands.length;
  4551. // ExpressionNary::optimize() generates an ExpressionConstant for {$or:[]}.
  4552. if (!n) throw new Error("OrExpression must have operands!");
  4553. var pLast = pOr.operands[n - 1];
  4554. if (!(pLast instanceof ConstantExpression)) return pE;
  4555. // Evaluate and coerce the last argument to a boolean. If it's true, then we can replace this entire expression.
  4556. var last = Value.coerceToBool(pLast.evaluate());
  4557. if (last) return new ConstantExpression(true);
  4558. // If we got here, the final operand was false, so we don't need it anymore.
  4559. // If there was only one other operand, we don't need the conjunction either. Note we still need to keep the promise that the result will be a boolean.
  4560. if (n == 2) return new CoerceToBoolExpression(pOr.operands[0]);
  4561. // Remove the final "false" value, and return the new expression.
  4562. pOr.operands.length = n - 1;
  4563. return pE;
  4564. };
  4565. proto.getFactory = function getFactory(){
  4566. return klass; // using the ctor rather than a separate .create() method
  4567. };
  4568. },{"../Value":7,"./CoerceToBoolExpression":31,"./ConstantExpression":35,"./NaryExpression":49}],53:[function(require,module,exports){
  4569. "use strict";
  4570. /**
  4571. * An $second pipeline expression.
  4572. * @see evaluate
  4573. * @class SecondExpression
  4574. * @namespace mungedb-aggregate.pipeline.expressions
  4575. * @module mungedb-aggregate
  4576. * @constructor
  4577. **/
  4578. var SecondExpression = module.exports = function SecondExpression(){
  4579. if (arguments.length !== 0) throw new Error("zero args expected");
  4580. base.call(this);
  4581. }, klass = SecondExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4582. // PROTOTYPE MEMBERS
  4583. proto.getOpName = function getOpName(){
  4584. return "$second";
  4585. };
  4586. proto.addOperand = function addOperand(expr) {
  4587. this.checkArgLimit(1);
  4588. base.prototype.addOperand.call(this, expr);
  4589. };
  4590. /**
  4591. * Takes a date and returns the second between 0 and 59, but can be 60 to account for leap seconds.
  4592. * @method evaluate
  4593. **/
  4594. proto.evaluate = function evaluate(doc){
  4595. this.checkArgCount(1);
  4596. var date = this.operands[0].evaluate(doc);
  4597. return date.getUTCSeconds(); //TODO: incorrect for last second of leap year, need to fix...
  4598. // currently leap seconds are unsupported in v8
  4599. // http://code.google.com/p/v8/issues/detail?id=1944
  4600. };
  4601. },{"./NaryExpression":49}],54:[function(require,module,exports){
  4602. "use strict";
  4603. /**
  4604. * A $strcasecmp pipeline expression.
  4605. * @see evaluate
  4606. * @class StrcasecmpExpression
  4607. * @namespace mungedb-aggregate.pipeline.expressions
  4608. * @module mungedb-aggregate
  4609. * @constructor
  4610. **/
  4611. var StrcasecmpExpression = module.exports = function StrcasecmpExpression(){
  4612. if (arguments.length !== 0) throw new Error("zero args expected");
  4613. base.call(this);
  4614. }, klass = StrcasecmpExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4615. // DEPENDENCIES
  4616. var Value = require("../Value"),
  4617. NaryExpression = require("./NaryExpression");
  4618. // PROTOTYPE MEMBERS
  4619. proto.getOpName = function getOpName(){
  4620. return "$strcasecmp";
  4621. };
  4622. proto.addOperand = function addOperand(expr) {
  4623. this.checkArgLimit(2);
  4624. base.prototype.addOperand.call(this, expr);
  4625. };
  4626. /**
  4627. * Takes in two strings. Returns a number. $strcasecmp is positive if the first string is “greater than” the second and negative if the first string is “less than” the second. $strcasecmp returns 0 if the strings are identical.
  4628. * @method evaluate
  4629. **/
  4630. proto.evaluate = function evaluate(doc){
  4631. this.checkArgCount(2);
  4632. var val1 = this.operands[0].evaluate(doc),
  4633. val2 = this.operands[1].evaluate(doc),
  4634. str1 = Value.coerceToString(val1).toUpperCase(),
  4635. str2 = Value.coerceToString(val2).toUpperCase(),
  4636. cmp = Value.compare(str1, str2);
  4637. return cmp;
  4638. };
  4639. },{"../Value":7,"./NaryExpression":49}],55:[function(require,module,exports){
  4640. "use strict";
  4641. /**
  4642. * A $substr pipeline expression.
  4643. * @see evaluate
  4644. * @class SubstrExpression
  4645. * @namespace mungedb-aggregate.pipeline.expressions
  4646. * @module mungedb-aggregate
  4647. * @constructor
  4648. **/
  4649. var SubstrExpression = module.exports = function SubstrExpression(){
  4650. if (arguments.length !== 0) throw new Error("zero args expected");
  4651. base.call(this);
  4652. }, klass = SubstrExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4653. // DEPENDENCIES
  4654. var Value = require("../Value");
  4655. // PROTOTYPE MEMBERS
  4656. proto.getOpName = function getOpName(){
  4657. return "$substr";
  4658. };
  4659. proto.addOperand = function addOperand(expr) {
  4660. this.checkArgLimit(3);
  4661. base.prototype.addOperand.call(this, expr);
  4662. };
  4663. /**
  4664. * Takes a string and two numbers. The first number represents the number of bytes in the string to skip, and the second number specifies the number of bytes to return from the string.
  4665. * @method evaluate
  4666. **/
  4667. proto.evaluate = function evaluate(doc) {
  4668. this.checkArgCount(3);
  4669. var val = this.operands[0].evaluate(doc),
  4670. idx = this.operands[1].evaluate(doc),
  4671. len = this.operands[2].evaluate(doc),
  4672. str = Value.coerceToString(val);
  4673. if (typeof(idx) != "number") throw new Error(this.getOpName() + ": starting index must be a numeric type; code 16034");
  4674. if (typeof(len) != "number") throw new Error(this.getOpName() + ": length must be a numeric type; code 16035");
  4675. if (idx >= str.length) return "";
  4676. //TODO: Need to handle -1
  4677. len = (len === -1 ? undefined : len);
  4678. return str.substr(idx, len);
  4679. };
  4680. },{"../Value":7,"./NaryExpression":49}],56:[function(require,module,exports){
  4681. "use strict";
  4682. /**
  4683. * A $subtract pipeline expression.
  4684. * @see evaluate
  4685. * @class SubtractExpression
  4686. * @namespace mungedb-aggregate.pipeline.expressions
  4687. * @module mungedb-aggregate
  4688. * @constructor
  4689. **/
  4690. var SubtractExpression = module.exports = function SubtractExpression(){
  4691. if (arguments.length !== 0) throw new Error("zero args expected");
  4692. base.call(this);
  4693. }, klass = SubtractExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4694. // DEPENDENCIES
  4695. var Value = require("../Value");
  4696. // PROTOTYPE MEMBERS
  4697. proto.getOpName = function getOpName(){
  4698. return "$subtract";
  4699. };
  4700. proto.addOperand = function addOperand(expr) {
  4701. this.checkArgLimit(2);
  4702. base.prototype.addOperand.call(this, expr);
  4703. };
  4704. /**
  4705. * Takes an array that contains a pair of numbers and subtracts the second from the first, returning their difference.
  4706. **/
  4707. proto.evaluate = function evaluate(doc) {
  4708. this.checkArgCount(2);
  4709. var left = this.operands[0].evaluate(doc),
  4710. right = this.operands[1].evaluate(doc);
  4711. return left - right;
  4712. };
  4713. },{"../Value":7,"./NaryExpression":49}],57:[function(require,module,exports){
  4714. "use strict";
  4715. /**
  4716. * A $toLower pipeline expression.
  4717. * @see evaluate
  4718. * @class ToLowerExpression
  4719. * @namespace mungedb-aggregate.pipeline.expressions
  4720. * @module mungedb-aggregate
  4721. * @constructor
  4722. **/
  4723. var ToLowerExpression = module.exports = function ToLowerExpression(){
  4724. if (arguments.length !== 0) throw new Error("zero args expected");
  4725. base.call(this);
  4726. }, klass = ToLowerExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4727. // DEPENDENCIES
  4728. var Value = require("../Value");
  4729. // PROTOTYPE MEMBERS
  4730. proto.getOpName = function getOpName(){
  4731. return "$toLower";
  4732. };
  4733. proto.addOperand = function addOperand(expr) {
  4734. this.checkArgLimit(1);
  4735. base.prototype.addOperand.call(this, expr);
  4736. };
  4737. /**
  4738. * Takes a single string and converts that string to lowercase, returning the result. All uppercase letters become lowercase.
  4739. **/
  4740. proto.evaluate = function evaluate(doc) {
  4741. this.checkArgCount(1);
  4742. var val = this.operands[0].evaluate(doc),
  4743. str = Value.coerceToString(val);
  4744. return str.toLowerCase();
  4745. };
  4746. },{"../Value":7,"./NaryExpression":49}],58:[function(require,module,exports){
  4747. "use strict";
  4748. /**
  4749. * A $toUpper pipeline expression.
  4750. * @see evaluate
  4751. * @class ToUpperExpression
  4752. * @namespace mungedb-aggregate.pipeline.expressions
  4753. * @module mungedb-aggregate
  4754. * @constructor
  4755. **/
  4756. var ToUpperExpression = module.exports = function ToUpperExpression(){
  4757. if (arguments.length !== 0) throw new Error("zero args expected");
  4758. base.call(this);
  4759. }, klass = ToUpperExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4760. // DEPENDENCIES
  4761. var Value = require("../Value");
  4762. // PROTOTYPE MEMBERS
  4763. proto.getOpName = function getOpName(){
  4764. return "$toUpper";
  4765. };
  4766. proto.addOperand = function addOperand(expr) {
  4767. this.checkArgLimit(1);
  4768. base.prototype.addOperand.call(this, expr);
  4769. };
  4770. /**
  4771. * Takes a single string and converts that string to lowercase, returning the result. All uppercase letters become lowercase.
  4772. **/
  4773. proto.evaluate = function evaluate(doc) {
  4774. this.checkArgCount(1);
  4775. var val = this.operands[0].evaluate(doc),
  4776. str = Value.coerceToString(val);
  4777. return str.toUpperCase();
  4778. };
  4779. },{"../Value":7,"./NaryExpression":49}],59:[function(require,module,exports){
  4780. "use strict";
  4781. /**
  4782. * A $week pipeline expression.
  4783. * @see evaluate
  4784. * @class WeekExpression
  4785. * @namespace mungedb-aggregate.pipeline.expressions
  4786. * @module mungedb-aggregate
  4787. * @constructor
  4788. **/
  4789. var WeekExpression = module.exports = function WeekExpression(){
  4790. if (arguments.length !== 0) throw new Error("zero args expected");
  4791. base.call(this);
  4792. }, klass = WeekExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4793. // DEPENDENCIES
  4794. var Value = require("../Value"),
  4795. DayOfYearExpression = require("./DayOfYearExpression");
  4796. // PROTOTYPE MEMBERS
  4797. proto.getOpName = function getOpName(){
  4798. return "$week";
  4799. };
  4800. proto.addOperand = function addOperand(expr) {
  4801. this.checkArgLimit(1);
  4802. base.prototype.addOperand.call(this, expr);
  4803. };
  4804. /**
  4805. * Takes a date and returns the week of the year as a number between 0 and 53.
  4806. * Weeks begin on Sundays, and week 1 begins with the first Sunday of the year.
  4807. * Days preceding the first Sunday of the year are in week 0.
  4808. * This behavior is the same as the “%U” operator to the strftime standard library function.
  4809. * @method evaluate
  4810. **/
  4811. proto.evaluate = function evaluate(doc) {
  4812. this.checkArgCount(1);
  4813. var date = this.operands[0].evaluate(doc),
  4814. dayOfWeek = date.getUTCDay(),
  4815. dayOfYear = DayOfYearExpression.getDateDayOfYear(date),
  4816. prevSundayDayOfYear = dayOfYear - dayOfWeek, // may be negative
  4817. nextSundayDayOfYear = prevSundayDayOfYear + 7; // must be positive
  4818. // Return the zero based index of the week of the next sunday, equal to the one based index of the week of the previous sunday, which is to be returned.
  4819. return (nextSundayDayOfYear / 7) | 0; // also, the `| 0` here truncates this so that we return an integer
  4820. };
  4821. },{"../Value":7,"./DayOfYearExpression":38,"./NaryExpression":49}],60:[function(require,module,exports){
  4822. "use strict";
  4823. /**
  4824. * A $year pipeline expression.
  4825. * @see evaluate
  4826. * @class YearExpression
  4827. * @namespace mungedb-aggregate.pipeline.expressions
  4828. * @module mungedb-aggregate
  4829. * @constructor
  4830. **/
  4831. var YearExpression = module.exports = function YearExpression(){
  4832. if (arguments.length !== 0) throw new Error("zero args expected");
  4833. base.call(this);
  4834. }, klass = YearExpression, base = require("./NaryExpression"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  4835. // DEPENDENCIES
  4836. var Value = require("../Value"),
  4837. DayOfYearExpression = require("./DayOfYearExpression");
  4838. // PROTOTYPE MEMBERS
  4839. proto.getOpName = function getOpName(){
  4840. return "$year";
  4841. };
  4842. proto.addOperand = function addOperand(expr) {
  4843. this.checkArgLimit(1);
  4844. base.prototype.addOperand.call(this, expr);
  4845. };
  4846. /**
  4847. * Takes a date and returns the full year.
  4848. * @method evaluate
  4849. **/
  4850. proto.evaluate = function evaluate(doc) {
  4851. this.checkArgCount(1);
  4852. var date = this.operands[0].evaluate(doc);
  4853. return date.getUTCFullYear();
  4854. };
  4855. },{"../Value":7,"./DayOfYearExpression":38,"./NaryExpression":49}],61:[function(require,module,exports){
  4856. "use strict";
  4857. module.exports = {
  4858. AddExpression: require("./AddExpression.js"),
  4859. AndExpression: require("./AndExpression.js"),
  4860. CoerceToBoolExpression: require("./CoerceToBoolExpression.js"),
  4861. CompareExpression: require("./CompareExpression.js"),
  4862. CondExpression: require("./CondExpression.js"),
  4863. ConstantExpression: require("./ConstantExpression.js"),
  4864. DayOfMonthExpression: require("./DayOfMonthExpression.js"),
  4865. DayOfWeekExpression: require("./DayOfWeekExpression.js"),
  4866. DayOfYearExpression: require("./DayOfYearExpression.js"),
  4867. DivideExpression: require("./DivideExpression.js"),
  4868. Expression: require("./Expression.js"),
  4869. FieldPathExpression: require("./FieldPathExpression.js"),
  4870. FieldRangeExpression: require("./FieldRangeExpression.js"),
  4871. HourExpression: require("./HourExpression.js"),
  4872. IfNullExpression: require("./IfNullExpression.js"),
  4873. MinuteExpression: require("./MinuteExpression.js"),
  4874. ModExpression: require("./ModExpression.js"),
  4875. MonthExpression: require("./MonthExpression.js"),
  4876. MultiplyExpression: require("./MultiplyExpression.js"),
  4877. NaryExpression: require("./NaryExpression.js"),
  4878. NotExpression: require("./NotExpression.js"),
  4879. ObjectExpression: require("./ObjectExpression.js"),
  4880. OrExpression: require("./OrExpression.js"),
  4881. SecondExpression: require("./SecondExpression.js"),
  4882. StrcasecmpExpression: require("./StrcasecmpExpression.js"),
  4883. SubstrExpression: require("./SubstrExpression.js"),
  4884. SubtractExpression: require("./SubtractExpression.js"),
  4885. ToLowerExpression: require("./ToLowerExpression.js"),
  4886. ToUpperExpression: require("./ToUpperExpression.js"),
  4887. WeekExpression: require("./WeekExpression.js"),
  4888. YearExpression: require("./YearExpression.js")
  4889. };
  4890. },{"./AddExpression.js":29,"./AndExpression.js":30,"./CoerceToBoolExpression.js":31,"./CompareExpression.js":32,"./CondExpression.js":34,"./ConstantExpression.js":35,"./DayOfMonthExpression.js":36,"./DayOfWeekExpression.js":37,"./DayOfYearExpression.js":38,"./DivideExpression.js":39,"./Expression.js":40,"./FieldPathExpression.js":41,"./FieldRangeExpression.js":42,"./HourExpression.js":43,"./IfNullExpression.js":44,"./MinuteExpression.js":45,"./ModExpression.js":46,"./MonthExpression.js":47,"./MultiplyExpression.js":48,"./NaryExpression.js":49,"./NotExpression.js":50,"./ObjectExpression.js":51,"./OrExpression.js":52,"./SecondExpression.js":53,"./StrcasecmpExpression.js":54,"./SubstrExpression.js":55,"./SubtractExpression.js":56,"./ToLowerExpression.js":57,"./ToUpperExpression.js":58,"./WeekExpression.js":59,"./YearExpression.js":60}],62:[function(require,module,exports){
  4891. "use strict";
  4892. module.exports = {
  4893. Pipeline: require("./Pipeline"),
  4894. PipelineD: require("./PipelineD"),
  4895. FieldPath: require("./FieldPath"),
  4896. Document: require("./Document"),
  4897. Value: require("./Value"),
  4898. accumulators: require("./accumulators/"),
  4899. documentSources: require("./documentSources/"),
  4900. expressions: require("./expressions/")
  4901. };
  4902. },{"./Document":3,"./FieldPath":4,"./Pipeline":5,"./PipelineD":6,"./Value":7,"./accumulators/":17,"./documentSources/":28,"./expressions/":61}],63:[function(require,module,exports){
  4903. (function (process){
  4904. /*!
  4905. * async
  4906. * https://github.com/caolan/async
  4907. *
  4908. * Copyright 2010-2014 Caolan McMahon
  4909. * Released under the MIT license
  4910. */
  4911. /*jshint onevar: false, indent:4 */
  4912. /*global setImmediate: false, setTimeout: false, console: false */
  4913. (function () {
  4914. var async = {};
  4915. // global on the server, window in the browser
  4916. var root, previous_async;
  4917. root = this;
  4918. if (root != null) {
  4919. previous_async = root.async;
  4920. }
  4921. async.noConflict = function () {
  4922. root.async = previous_async;
  4923. return async;
  4924. };
  4925. function only_once(fn) {
  4926. var called = false;
  4927. return function() {
  4928. if (called) throw new Error("Callback was already called.");
  4929. called = true;
  4930. fn.apply(root, arguments);
  4931. }
  4932. }
  4933. //// cross-browser compatiblity functions ////
  4934. var _toString = Object.prototype.toString;
  4935. var _isArray = Array.isArray || function (obj) {
  4936. return _toString.call(obj) === '[object Array]';
  4937. };
  4938. var _each = function (arr, iterator) {
  4939. if (arr.forEach) {
  4940. return arr.forEach(iterator);
  4941. }
  4942. for (var i = 0; i < arr.length; i += 1) {
  4943. iterator(arr[i], i, arr);
  4944. }
  4945. };
  4946. var _map = function (arr, iterator) {
  4947. if (arr.map) {
  4948. return arr.map(iterator);
  4949. }
  4950. var results = [];
  4951. _each(arr, function (x, i, a) {
  4952. results.push(iterator(x, i, a));
  4953. });
  4954. return results;
  4955. };
  4956. var _reduce = function (arr, iterator, memo) {
  4957. if (arr.reduce) {
  4958. return arr.reduce(iterator, memo);
  4959. }
  4960. _each(arr, function (x, i, a) {
  4961. memo = iterator(memo, x, i, a);
  4962. });
  4963. return memo;
  4964. };
  4965. var _keys = function (obj) {
  4966. if (Object.keys) {
  4967. return Object.keys(obj);
  4968. }
  4969. var keys = [];
  4970. for (var k in obj) {
  4971. if (obj.hasOwnProperty(k)) {
  4972. keys.push(k);
  4973. }
  4974. }
  4975. return keys;
  4976. };
  4977. //// exported async module functions ////
  4978. //// nextTick implementation with browser-compatible fallback ////
  4979. if (typeof process === 'undefined' || !(process.nextTick)) {
  4980. if (typeof setImmediate === 'function') {
  4981. async.nextTick = function (fn) {
  4982. // not a direct alias for IE10 compatibility
  4983. setImmediate(fn);
  4984. };
  4985. async.setImmediate = async.nextTick;
  4986. }
  4987. else {
  4988. async.nextTick = function (fn) {
  4989. setTimeout(fn, 0);
  4990. };
  4991. async.setImmediate = async.nextTick;
  4992. }
  4993. }
  4994. else {
  4995. async.nextTick = process.nextTick;
  4996. if (typeof setImmediate !== 'undefined') {
  4997. async.setImmediate = function (fn) {
  4998. // not a direct alias for IE10 compatibility
  4999. setImmediate(fn);
  5000. };
  5001. }
  5002. else {
  5003. async.setImmediate = async.nextTick;
  5004. }
  5005. }
  5006. async.each = function (arr, iterator, callback) {
  5007. callback = callback || function () {};
  5008. if (!arr.length) {
  5009. return callback();
  5010. }
  5011. var completed = 0;
  5012. _each(arr, function (x) {
  5013. iterator(x, only_once(done) );
  5014. });
  5015. function done(err) {
  5016. if (err) {
  5017. callback(err);
  5018. callback = function () {};
  5019. }
  5020. else {
  5021. completed += 1;
  5022. if (completed >= arr.length) {
  5023. callback();
  5024. }
  5025. }
  5026. }
  5027. };
  5028. async.forEach = async.each;
  5029. async.eachSeries = function (arr, iterator, callback) {
  5030. callback = callback || function () {};
  5031. if (!arr.length) {
  5032. return callback();
  5033. }
  5034. var completed = 0;
  5035. var iterate = function () {
  5036. iterator(arr[completed], function (err) {
  5037. if (err) {
  5038. callback(err);
  5039. callback = function () {};
  5040. }
  5041. else {
  5042. completed += 1;
  5043. if (completed >= arr.length) {
  5044. callback();
  5045. }
  5046. else {
  5047. iterate();
  5048. }
  5049. }
  5050. });
  5051. };
  5052. iterate();
  5053. };
  5054. async.forEachSeries = async.eachSeries;
  5055. async.eachLimit = function (arr, limit, iterator, callback) {
  5056. var fn = _eachLimit(limit);
  5057. fn.apply(null, [arr, iterator, callback]);
  5058. };
  5059. async.forEachLimit = async.eachLimit;
  5060. var _eachLimit = function (limit) {
  5061. return function (arr, iterator, callback) {
  5062. callback = callback || function () {};
  5063. if (!arr.length || limit <= 0) {
  5064. return callback();
  5065. }
  5066. var completed = 0;
  5067. var started = 0;
  5068. var running = 0;
  5069. (function replenish () {
  5070. if (completed >= arr.length) {
  5071. return callback();
  5072. }
  5073. while (running < limit && started < arr.length) {
  5074. started += 1;
  5075. running += 1;
  5076. iterator(arr[started - 1], function (err) {
  5077. if (err) {
  5078. callback(err);
  5079. callback = function () {};
  5080. }
  5081. else {
  5082. completed += 1;
  5083. running -= 1;
  5084. if (completed >= arr.length) {
  5085. callback();
  5086. }
  5087. else {
  5088. replenish();
  5089. }
  5090. }
  5091. });
  5092. }
  5093. })();
  5094. };
  5095. };
  5096. var doParallel = function (fn) {
  5097. return function () {
  5098. var args = Array.prototype.slice.call(arguments);
  5099. return fn.apply(null, [async.each].concat(args));
  5100. };
  5101. };
  5102. var doParallelLimit = function(limit, fn) {
  5103. return function () {
  5104. var args = Array.prototype.slice.call(arguments);
  5105. return fn.apply(null, [_eachLimit(limit)].concat(args));
  5106. };
  5107. };
  5108. var doSeries = function (fn) {
  5109. return function () {
  5110. var args = Array.prototype.slice.call(arguments);
  5111. return fn.apply(null, [async.eachSeries].concat(args));
  5112. };
  5113. };
  5114. var _asyncMap = function (eachfn, arr, iterator, callback) {
  5115. arr = _map(arr, function (x, i) {
  5116. return {index: i, value: x};
  5117. });
  5118. if (!callback) {
  5119. eachfn(arr, function (x, callback) {
  5120. iterator(x.value, function (err) {
  5121. callback(err);
  5122. });
  5123. });
  5124. } else {
  5125. var results = [];
  5126. eachfn(arr, function (x, callback) {
  5127. iterator(x.value, function (err, v) {
  5128. results[x.index] = v;
  5129. callback(err);
  5130. });
  5131. }, function (err) {
  5132. callback(err, results);
  5133. });
  5134. }
  5135. };
  5136. async.map = doParallel(_asyncMap);
  5137. async.mapSeries = doSeries(_asyncMap);
  5138. async.mapLimit = function (arr, limit, iterator, callback) {
  5139. return _mapLimit(limit)(arr, iterator, callback);
  5140. };
  5141. var _mapLimit = function(limit) {
  5142. return doParallelLimit(limit, _asyncMap);
  5143. };
  5144. // reduce only has a series version, as doing reduce in parallel won't
  5145. // work in many situations.
  5146. async.reduce = function (arr, memo, iterator, callback) {
  5147. async.eachSeries(arr, function (x, callback) {
  5148. iterator(memo, x, function (err, v) {
  5149. memo = v;
  5150. callback(err);
  5151. });
  5152. }, function (err) {
  5153. callback(err, memo);
  5154. });
  5155. };
  5156. // inject alias
  5157. async.inject = async.reduce;
  5158. // foldl alias
  5159. async.foldl = async.reduce;
  5160. async.reduceRight = function (arr, memo, iterator, callback) {
  5161. var reversed = _map(arr, function (x) {
  5162. return x;
  5163. }).reverse();
  5164. async.reduce(reversed, memo, iterator, callback);
  5165. };
  5166. // foldr alias
  5167. async.foldr = async.reduceRight;
  5168. var _filter = function (eachfn, arr, iterator, callback) {
  5169. var results = [];
  5170. arr = _map(arr, function (x, i) {
  5171. return {index: i, value: x};
  5172. });
  5173. eachfn(arr, function (x, callback) {
  5174. iterator(x.value, function (v) {
  5175. if (v) {
  5176. results.push(x);
  5177. }
  5178. callback();
  5179. });
  5180. }, function (err) {
  5181. callback(_map(results.sort(function (a, b) {
  5182. return a.index - b.index;
  5183. }), function (x) {
  5184. return x.value;
  5185. }));
  5186. });
  5187. };
  5188. async.filter = doParallel(_filter);
  5189. async.filterSeries = doSeries(_filter);
  5190. // select alias
  5191. async.select = async.filter;
  5192. async.selectSeries = async.filterSeries;
  5193. var _reject = function (eachfn, arr, iterator, callback) {
  5194. var results = [];
  5195. arr = _map(arr, function (x, i) {
  5196. return {index: i, value: x};
  5197. });
  5198. eachfn(arr, function (x, callback) {
  5199. iterator(x.value, function (v) {
  5200. if (!v) {
  5201. results.push(x);
  5202. }
  5203. callback();
  5204. });
  5205. }, function (err) {
  5206. callback(_map(results.sort(function (a, b) {
  5207. return a.index - b.index;
  5208. }), function (x) {
  5209. return x.value;
  5210. }));
  5211. });
  5212. };
  5213. async.reject = doParallel(_reject);
  5214. async.rejectSeries = doSeries(_reject);
  5215. var _detect = function (eachfn, arr, iterator, main_callback) {
  5216. eachfn(arr, function (x, callback) {
  5217. iterator(x, function (result) {
  5218. if (result) {
  5219. main_callback(x);
  5220. main_callback = function () {};
  5221. }
  5222. else {
  5223. callback();
  5224. }
  5225. });
  5226. }, function (err) {
  5227. main_callback();
  5228. });
  5229. };
  5230. async.detect = doParallel(_detect);
  5231. async.detectSeries = doSeries(_detect);
  5232. async.some = function (arr, iterator, main_callback) {
  5233. async.each(arr, function (x, callback) {
  5234. iterator(x, function (v) {
  5235. if (v) {
  5236. main_callback(true);
  5237. main_callback = function () {};
  5238. }
  5239. callback();
  5240. });
  5241. }, function (err) {
  5242. main_callback(false);
  5243. });
  5244. };
  5245. // any alias
  5246. async.any = async.some;
  5247. async.every = function (arr, iterator, main_callback) {
  5248. async.each(arr, function (x, callback) {
  5249. iterator(x, function (v) {
  5250. if (!v) {
  5251. main_callback(false);
  5252. main_callback = function () {};
  5253. }
  5254. callback();
  5255. });
  5256. }, function (err) {
  5257. main_callback(true);
  5258. });
  5259. };
  5260. // all alias
  5261. async.all = async.every;
  5262. async.sortBy = function (arr, iterator, callback) {
  5263. async.map(arr, function (x, callback) {
  5264. iterator(x, function (err, criteria) {
  5265. if (err) {
  5266. callback(err);
  5267. }
  5268. else {
  5269. callback(null, {value: x, criteria: criteria});
  5270. }
  5271. });
  5272. }, function (err, results) {
  5273. if (err) {
  5274. return callback(err);
  5275. }
  5276. else {
  5277. var fn = function (left, right) {
  5278. var a = left.criteria, b = right.criteria;
  5279. return a < b ? -1 : a > b ? 1 : 0;
  5280. };
  5281. callback(null, _map(results.sort(fn), function (x) {
  5282. return x.value;
  5283. }));
  5284. }
  5285. });
  5286. };
  5287. async.auto = function (tasks, callback) {
  5288. callback = callback || function () {};
  5289. var keys = _keys(tasks);
  5290. var remainingTasks = keys.length
  5291. if (!remainingTasks) {
  5292. return callback();
  5293. }
  5294. var results = {};
  5295. var listeners = [];
  5296. var addListener = function (fn) {
  5297. listeners.unshift(fn);
  5298. };
  5299. var removeListener = function (fn) {
  5300. for (var i = 0; i < listeners.length; i += 1) {
  5301. if (listeners[i] === fn) {
  5302. listeners.splice(i, 1);
  5303. return;
  5304. }
  5305. }
  5306. };
  5307. var taskComplete = function () {
  5308. remainingTasks--
  5309. _each(listeners.slice(0), function (fn) {
  5310. fn();
  5311. });
  5312. };
  5313. addListener(function () {
  5314. if (!remainingTasks) {
  5315. var theCallback = callback;
  5316. // prevent final callback from calling itself if it errors
  5317. callback = function () {};
  5318. theCallback(null, results);
  5319. }
  5320. });
  5321. _each(keys, function (k) {
  5322. var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
  5323. var taskCallback = function (err) {
  5324. var args = Array.prototype.slice.call(arguments, 1);
  5325. if (args.length <= 1) {
  5326. args = args[0];
  5327. }
  5328. if (err) {
  5329. var safeResults = {};
  5330. _each(_keys(results), function(rkey) {
  5331. safeResults[rkey] = results[rkey];
  5332. });
  5333. safeResults[k] = args;
  5334. callback(err, safeResults);
  5335. // stop subsequent errors hitting callback multiple times
  5336. callback = function () {};
  5337. }
  5338. else {
  5339. results[k] = args;
  5340. async.setImmediate(taskComplete);
  5341. }
  5342. };
  5343. var requires = task.slice(0, Math.abs(task.length - 1)) || [];
  5344. var ready = function () {
  5345. return _reduce(requires, function (a, x) {
  5346. return (a && results.hasOwnProperty(x));
  5347. }, true) && !results.hasOwnProperty(k);
  5348. };
  5349. if (ready()) {
  5350. task[task.length - 1](taskCallback, results);
  5351. }
  5352. else {
  5353. var listener = function () {
  5354. if (ready()) {
  5355. removeListener(listener);
  5356. task[task.length - 1](taskCallback, results);
  5357. }
  5358. };
  5359. addListener(listener);
  5360. }
  5361. });
  5362. };
  5363. async.retry = function(times, task, callback) {
  5364. var DEFAULT_TIMES = 5;
  5365. var attempts = [];
  5366. // Use defaults if times not passed
  5367. if (typeof times === 'function') {
  5368. callback = task;
  5369. task = times;
  5370. times = DEFAULT_TIMES;
  5371. }
  5372. // Make sure times is a number
  5373. times = parseInt(times, 10) || DEFAULT_TIMES;
  5374. var wrappedTask = function(wrappedCallback, wrappedResults) {
  5375. var retryAttempt = function(task, finalAttempt) {
  5376. return function(seriesCallback) {
  5377. task(function(err, result){
  5378. seriesCallback(!err || finalAttempt, {err: err, result: result});
  5379. }, wrappedResults);
  5380. };
  5381. };
  5382. while (times) {
  5383. attempts.push(retryAttempt(task, !(times-=1)));
  5384. }
  5385. async.series(attempts, function(done, data){
  5386. data = data[data.length - 1];
  5387. (wrappedCallback || callback)(data.err, data.result);
  5388. });
  5389. }
  5390. // If a callback is passed, run this as a controll flow
  5391. return callback ? wrappedTask() : wrappedTask
  5392. };
  5393. async.waterfall = function (tasks, callback) {
  5394. callback = callback || function () {};
  5395. if (!_isArray(tasks)) {
  5396. var err = new Error('First argument to waterfall must be an array of functions');
  5397. return callback(err);
  5398. }
  5399. if (!tasks.length) {
  5400. return callback();
  5401. }
  5402. var wrapIterator = function (iterator) {
  5403. return function (err) {
  5404. if (err) {
  5405. callback.apply(null, arguments);
  5406. callback = function () {};
  5407. }
  5408. else {
  5409. var args = Array.prototype.slice.call(arguments, 1);
  5410. var next = iterator.next();
  5411. if (next) {
  5412. args.push(wrapIterator(next));
  5413. }
  5414. else {
  5415. args.push(callback);
  5416. }
  5417. async.setImmediate(function () {
  5418. iterator.apply(null, args);
  5419. });
  5420. }
  5421. };
  5422. };
  5423. wrapIterator(async.iterator(tasks))();
  5424. };
  5425. var _parallel = function(eachfn, tasks, callback) {
  5426. callback = callback || function () {};
  5427. if (_isArray(tasks)) {
  5428. eachfn.map(tasks, function (fn, callback) {
  5429. if (fn) {
  5430. fn(function (err) {
  5431. var args = Array.prototype.slice.call(arguments, 1);
  5432. if (args.length <= 1) {
  5433. args = args[0];
  5434. }
  5435. callback.call(null, err, args);
  5436. });
  5437. }
  5438. }, callback);
  5439. }
  5440. else {
  5441. var results = {};
  5442. eachfn.each(_keys(tasks), function (k, callback) {
  5443. tasks[k](function (err) {
  5444. var args = Array.prototype.slice.call(arguments, 1);
  5445. if (args.length <= 1) {
  5446. args = args[0];
  5447. }
  5448. results[k] = args;
  5449. callback(err);
  5450. });
  5451. }, function (err) {
  5452. callback(err, results);
  5453. });
  5454. }
  5455. };
  5456. async.parallel = function (tasks, callback) {
  5457. _parallel({ map: async.map, each: async.each }, tasks, callback);
  5458. };
  5459. async.parallelLimit = function(tasks, limit, callback) {
  5460. _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
  5461. };
  5462. async.series = function (tasks, callback) {
  5463. callback = callback || function () {};
  5464. if (_isArray(tasks)) {
  5465. async.mapSeries(tasks, function (fn, callback) {
  5466. if (fn) {
  5467. fn(function (err) {
  5468. var args = Array.prototype.slice.call(arguments, 1);
  5469. if (args.length <= 1) {
  5470. args = args[0];
  5471. }
  5472. callback.call(null, err, args);
  5473. });
  5474. }
  5475. }, callback);
  5476. }
  5477. else {
  5478. var results = {};
  5479. async.eachSeries(_keys(tasks), function (k, callback) {
  5480. tasks[k](function (err) {
  5481. var args = Array.prototype.slice.call(arguments, 1);
  5482. if (args.length <= 1) {
  5483. args = args[0];
  5484. }
  5485. results[k] = args;
  5486. callback(err);
  5487. });
  5488. }, function (err) {
  5489. callback(err, results);
  5490. });
  5491. }
  5492. };
  5493. async.iterator = function (tasks) {
  5494. var makeCallback = function (index) {
  5495. var fn = function () {
  5496. if (tasks.length) {
  5497. tasks[index].apply(null, arguments);
  5498. }
  5499. return fn.next();
  5500. };
  5501. fn.next = function () {
  5502. return (index < tasks.length - 1) ? makeCallback(index + 1): null;
  5503. };
  5504. return fn;
  5505. };
  5506. return makeCallback(0);
  5507. };
  5508. async.apply = function (fn) {
  5509. var args = Array.prototype.slice.call(arguments, 1);
  5510. return function () {
  5511. return fn.apply(
  5512. null, args.concat(Array.prototype.slice.call(arguments))
  5513. );
  5514. };
  5515. };
  5516. var _concat = function (eachfn, arr, fn, callback) {
  5517. var r = [];
  5518. eachfn(arr, function (x, cb) {
  5519. fn(x, function (err, y) {
  5520. r = r.concat(y || []);
  5521. cb(err);
  5522. });
  5523. }, function (err) {
  5524. callback(err, r);
  5525. });
  5526. };
  5527. async.concat = doParallel(_concat);
  5528. async.concatSeries = doSeries(_concat);
  5529. async.whilst = function (test, iterator, callback) {
  5530. if (test()) {
  5531. iterator(function (err) {
  5532. if (err) {
  5533. return callback(err);
  5534. }
  5535. async.whilst(test, iterator, callback);
  5536. });
  5537. }
  5538. else {
  5539. callback();
  5540. }
  5541. };
  5542. async.doWhilst = function (iterator, test, callback) {
  5543. iterator(function (err) {
  5544. if (err) {
  5545. return callback(err);
  5546. }
  5547. var args = Array.prototype.slice.call(arguments, 1);
  5548. if (test.apply(null, args)) {
  5549. async.doWhilst(iterator, test, callback);
  5550. }
  5551. else {
  5552. callback();
  5553. }
  5554. });
  5555. };
  5556. async.until = function (test, iterator, callback) {
  5557. if (!test()) {
  5558. iterator(function (err) {
  5559. if (err) {
  5560. return callback(err);
  5561. }
  5562. async.until(test, iterator, callback);
  5563. });
  5564. }
  5565. else {
  5566. callback();
  5567. }
  5568. };
  5569. async.doUntil = function (iterator, test, callback) {
  5570. iterator(function (err) {
  5571. if (err) {
  5572. return callback(err);
  5573. }
  5574. var args = Array.prototype.slice.call(arguments, 1);
  5575. if (!test.apply(null, args)) {
  5576. async.doUntil(iterator, test, callback);
  5577. }
  5578. else {
  5579. callback();
  5580. }
  5581. });
  5582. };
  5583. async.queue = function (worker, concurrency) {
  5584. if (concurrency === undefined) {
  5585. concurrency = 1;
  5586. }
  5587. function _insert(q, data, pos, callback) {
  5588. if (!q.started){
  5589. q.started = true;
  5590. }
  5591. if (!_isArray(data)) {
  5592. data = [data];
  5593. }
  5594. if(data.length == 0) {
  5595. // call drain immediately if there are no tasks
  5596. return async.setImmediate(function() {
  5597. if (q.drain) {
  5598. q.drain();
  5599. }
  5600. });
  5601. }
  5602. _each(data, function(task) {
  5603. var item = {
  5604. data: task,
  5605. callback: typeof callback === 'function' ? callback : null
  5606. };
  5607. if (pos) {
  5608. q.tasks.unshift(item);
  5609. } else {
  5610. q.tasks.push(item);
  5611. }
  5612. if (q.saturated && q.tasks.length === q.concurrency) {
  5613. q.saturated();
  5614. }
  5615. async.setImmediate(q.process);
  5616. });
  5617. }
  5618. var workers = 0;
  5619. var q = {
  5620. tasks: [],
  5621. concurrency: concurrency,
  5622. saturated: null,
  5623. empty: null,
  5624. drain: null,
  5625. started: false,
  5626. paused: false,
  5627. push: function (data, callback) {
  5628. _insert(q, data, false, callback);
  5629. },
  5630. kill: function () {
  5631. q.drain = null;
  5632. q.tasks = [];
  5633. },
  5634. unshift: function (data, callback) {
  5635. _insert(q, data, true, callback);
  5636. },
  5637. process: function () {
  5638. if (!q.paused && workers < q.concurrency && q.tasks.length) {
  5639. var task = q.tasks.shift();
  5640. if (q.empty && q.tasks.length === 0) {
  5641. q.empty();
  5642. }
  5643. workers += 1;
  5644. var next = function () {
  5645. workers -= 1;
  5646. if (task.callback) {
  5647. task.callback.apply(task, arguments);
  5648. }
  5649. if (q.drain && q.tasks.length + workers === 0) {
  5650. q.drain();
  5651. }
  5652. q.process();
  5653. };
  5654. var cb = only_once(next);
  5655. worker(task.data, cb);
  5656. }
  5657. },
  5658. length: function () {
  5659. return q.tasks.length;
  5660. },
  5661. running: function () {
  5662. return workers;
  5663. },
  5664. idle: function() {
  5665. return q.tasks.length + workers === 0;
  5666. },
  5667. pause: function () {
  5668. if (q.paused === true) { return; }
  5669. q.paused = true;
  5670. q.process();
  5671. },
  5672. resume: function () {
  5673. if (q.paused === false) { return; }
  5674. q.paused = false;
  5675. q.process();
  5676. }
  5677. };
  5678. return q;
  5679. };
  5680. async.priorityQueue = function (worker, concurrency) {
  5681. function _compareTasks(a, b){
  5682. return a.priority - b.priority;
  5683. };
  5684. function _binarySearch(sequence, item, compare) {
  5685. var beg = -1,
  5686. end = sequence.length - 1;
  5687. while (beg < end) {
  5688. var mid = beg + ((end - beg + 1) >>> 1);
  5689. if (compare(item, sequence[mid]) >= 0) {
  5690. beg = mid;
  5691. } else {
  5692. end = mid - 1;
  5693. }
  5694. }
  5695. return beg;
  5696. }
  5697. function _insert(q, data, priority, callback) {
  5698. if (!q.started){
  5699. q.started = true;
  5700. }
  5701. if (!_isArray(data)) {
  5702. data = [data];
  5703. }
  5704. if(data.length == 0) {
  5705. // call drain immediately if there are no tasks
  5706. return async.setImmediate(function() {
  5707. if (q.drain) {
  5708. q.drain();
  5709. }
  5710. });
  5711. }
  5712. _each(data, function(task) {
  5713. var item = {
  5714. data: task,
  5715. priority: priority,
  5716. callback: typeof callback === 'function' ? callback : null
  5717. };
  5718. q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
  5719. if (q.saturated && q.tasks.length === q.concurrency) {
  5720. q.saturated();
  5721. }
  5722. async.setImmediate(q.process);
  5723. });
  5724. }
  5725. // Start with a normal queue
  5726. var q = async.queue(worker, concurrency);
  5727. // Override push to accept second parameter representing priority
  5728. q.push = function (data, priority, callback) {
  5729. _insert(q, data, priority, callback);
  5730. };
  5731. // Remove unshift function
  5732. delete q.unshift;
  5733. return q;
  5734. };
  5735. async.cargo = function (worker, payload) {
  5736. var working = false,
  5737. tasks = [];
  5738. var cargo = {
  5739. tasks: tasks,
  5740. payload: payload,
  5741. saturated: null,
  5742. empty: null,
  5743. drain: null,
  5744. drained: true,
  5745. push: function (data, callback) {
  5746. if (!_isArray(data)) {
  5747. data = [data];
  5748. }
  5749. _each(data, function(task) {
  5750. tasks.push({
  5751. data: task,
  5752. callback: typeof callback === 'function' ? callback : null
  5753. });
  5754. cargo.drained = false;
  5755. if (cargo.saturated && tasks.length === payload) {
  5756. cargo.saturated();
  5757. }
  5758. });
  5759. async.setImmediate(cargo.process);
  5760. },
  5761. process: function process() {
  5762. if (working) return;
  5763. if (tasks.length === 0) {
  5764. if(cargo.drain && !cargo.drained) cargo.drain();
  5765. cargo.drained = true;
  5766. return;
  5767. }
  5768. var ts = typeof payload === 'number'
  5769. ? tasks.splice(0, payload)
  5770. : tasks.splice(0, tasks.length);
  5771. var ds = _map(ts, function (task) {
  5772. return task.data;
  5773. });
  5774. if(cargo.empty) cargo.empty();
  5775. working = true;
  5776. worker(ds, function () {
  5777. working = false;
  5778. var args = arguments;
  5779. _each(ts, function (data) {
  5780. if (data.callback) {
  5781. data.callback.apply(null, args);
  5782. }
  5783. });
  5784. process();
  5785. });
  5786. },
  5787. length: function () {
  5788. return tasks.length;
  5789. },
  5790. running: function () {
  5791. return working;
  5792. }
  5793. };
  5794. return cargo;
  5795. };
  5796. var _console_fn = function (name) {
  5797. return function (fn) {
  5798. var args = Array.prototype.slice.call(arguments, 1);
  5799. fn.apply(null, args.concat([function (err) {
  5800. var args = Array.prototype.slice.call(arguments, 1);
  5801. if (typeof console !== 'undefined') {
  5802. if (err) {
  5803. if (console.error) {
  5804. console.error(err);
  5805. }
  5806. }
  5807. else if (console[name]) {
  5808. _each(args, function (x) {
  5809. console[name](x);
  5810. });
  5811. }
  5812. }
  5813. }]));
  5814. };
  5815. };
  5816. async.log = _console_fn('log');
  5817. async.dir = _console_fn('dir');
  5818. /*async.info = _console_fn('info');
  5819. async.warn = _console_fn('warn');
  5820. async.error = _console_fn('error');*/
  5821. async.memoize = function (fn, hasher) {
  5822. var memo = {};
  5823. var queues = {};
  5824. hasher = hasher || function (x) {
  5825. return x;
  5826. };
  5827. var memoized = function () {
  5828. var args = Array.prototype.slice.call(arguments);
  5829. var callback = args.pop();
  5830. var key = hasher.apply(null, args);
  5831. if (key in memo) {
  5832. async.nextTick(function () {
  5833. callback.apply(null, memo[key]);
  5834. });
  5835. }
  5836. else if (key in queues) {
  5837. queues[key].push(callback);
  5838. }
  5839. else {
  5840. queues[key] = [callback];
  5841. fn.apply(null, args.concat([function () {
  5842. memo[key] = arguments;
  5843. var q = queues[key];
  5844. delete queues[key];
  5845. for (var i = 0, l = q.length; i < l; i++) {
  5846. q[i].apply(null, arguments);
  5847. }
  5848. }]));
  5849. }
  5850. };
  5851. memoized.memo = memo;
  5852. memoized.unmemoized = fn;
  5853. return memoized;
  5854. };
  5855. async.unmemoize = function (fn) {
  5856. return function () {
  5857. return (fn.unmemoized || fn).apply(null, arguments);
  5858. };
  5859. };
  5860. async.times = function (count, iterator, callback) {
  5861. var counter = [];
  5862. for (var i = 0; i < count; i++) {
  5863. counter.push(i);
  5864. }
  5865. return async.map(counter, iterator, callback);
  5866. };
  5867. async.timesSeries = function (count, iterator, callback) {
  5868. var counter = [];
  5869. for (var i = 0; i < count; i++) {
  5870. counter.push(i);
  5871. }
  5872. return async.mapSeries(counter, iterator, callback);
  5873. };
  5874. async.seq = function (/* functions... */) {
  5875. var fns = arguments;
  5876. return function () {
  5877. var that = this;
  5878. var args = Array.prototype.slice.call(arguments);
  5879. var callback = args.pop();
  5880. async.reduce(fns, args, function (newargs, fn, cb) {
  5881. fn.apply(that, newargs.concat([function () {
  5882. var err = arguments[0];
  5883. var nextargs = Array.prototype.slice.call(arguments, 1);
  5884. cb(err, nextargs);
  5885. }]))
  5886. },
  5887. function (err, results) {
  5888. callback.apply(that, [err].concat(results));
  5889. });
  5890. };
  5891. };
  5892. async.compose = function (/* functions... */) {
  5893. return async.seq.apply(null, Array.prototype.reverse.call(arguments));
  5894. };
  5895. var _applyEach = function (eachfn, fns /*args...*/) {
  5896. var go = function () {
  5897. var that = this;
  5898. var args = Array.prototype.slice.call(arguments);
  5899. var callback = args.pop();
  5900. return eachfn(fns, function (fn, cb) {
  5901. fn.apply(that, args.concat([cb]));
  5902. },
  5903. callback);
  5904. };
  5905. if (arguments.length > 2) {
  5906. var args = Array.prototype.slice.call(arguments, 2);
  5907. return go.apply(this, args);
  5908. }
  5909. else {
  5910. return go;
  5911. }
  5912. };
  5913. async.applyEach = doParallel(_applyEach);
  5914. async.applyEachSeries = doSeries(_applyEach);
  5915. async.forever = function (fn, callback) {
  5916. function next(err) {
  5917. if (err) {
  5918. if (callback) {
  5919. return callback(err);
  5920. }
  5921. throw err;
  5922. }
  5923. fn(next);
  5924. }
  5925. next();
  5926. };
  5927. // Node.js
  5928. if (typeof module !== 'undefined' && module.exports) {
  5929. module.exports = async;
  5930. }
  5931. // AMD / RequireJS
  5932. else if (typeof define !== 'undefined' && define.amd) {
  5933. define([], function () {
  5934. return async;
  5935. });
  5936. }
  5937. // included directly via <script> tag
  5938. else {
  5939. root.async = async;
  5940. }
  5941. }());
  5942. }).call(this,require('_process'))
  5943. },{"_process":65}],64:[function(require,module,exports){
  5944. /*
  5945. * Sift
  5946. *
  5947. * Copryright 2011, Craig Condon
  5948. * Licensed under MIT
  5949. *
  5950. * Inspired by mongodb's query language
  5951. */
  5952. (function() {
  5953. /**
  5954. */
  5955. var _convertDotToSubObject = function(keyParts, value) {
  5956. var subObject = {},
  5957. currentValue = subObject;
  5958. for(var i = 0, n = keyParts.length - 1; i < n; i++) {
  5959. currentValue = currentValue[keyParts[i]] = {};
  5960. }
  5961. currentValue[keyParts[i]] = value;
  5962. return subObject;
  5963. }
  5964. /**
  5965. */
  5966. var _queryParser = new (function() {
  5967. /**
  5968. * tests against data
  5969. */
  5970. var priority = this.priority = function(statement, data) {
  5971. var exprs = statement.exprs,
  5972. priority = 0;
  5973. //generally, expressions are ordered from least efficient, to most efficient.
  5974. for(var i = 0, n = exprs.length; i < n; i++) {
  5975. var expr = exprs[i],
  5976. p;
  5977. if(!~(p = expr.e(expr.v, _comparable(data), data))) return -1;
  5978. priority += p;
  5979. }
  5980. return priority;
  5981. }
  5982. /**
  5983. * parses a statement into something evaluable
  5984. */
  5985. var parse = this.parse = function(statement, key) {
  5986. //fixes sift(null, []) issue
  5987. if(!statement) statement = { $eq: statement };
  5988. var testers = [];
  5989. //if the statement is an object, then we're looking at something like: { key: match }
  5990. if(Object.prototype.toString.call(statement) === "[object Object]") {
  5991. for(var k in statement) {
  5992. //find the apropriate operator. If one doesn't exist and the key does not start
  5993. //with a $ character, then it's a property, which means we create a new statement
  5994. //(traversing)
  5995. var operator;
  5996. if (!!_testers[k]) {
  5997. operator = k;
  5998. } else if (k.substr(0, 1) !== '$') {
  5999. operator = '$trav';
  6000. } else {
  6001. throw new Error('Unknown operator.');
  6002. }
  6003. //value of given statement (the match)
  6004. var value = statement[k];
  6005. //default = match
  6006. var exprValue = value;
  6007. //if we're working with a traversable operator, then set the expr value
  6008. if(TRAV_OP[operator]) {
  6009. //using dot notation? convert into a sub-object
  6010. if(~k.indexOf(".")) {
  6011. var keyParts = k.split(".");
  6012. k = keyParts.shift(); //we're using the first key, so remove it
  6013. exprValue = value = _convertDotToSubObject(keyParts, value);
  6014. }
  6015. //*if* the value is an array, then we're dealing with something like: $or, $and
  6016. if(value instanceof Array) {
  6017. exprValue = [];
  6018. for(var i = value.length; i--;) {
  6019. exprValue.push(parse(value[i]));
  6020. }
  6021. //otherwise we're dealing with $trav
  6022. } else {
  6023. exprValue = parse(value, k);
  6024. }
  6025. }
  6026. testers.push(_getExpr(operator, k, exprValue));
  6027. }
  6028. //otherwise we're comparing a particular value, so set to eq
  6029. } else {
  6030. testers.push(_getExpr('$eq', k, statement));
  6031. }
  6032. var stmt = {
  6033. exprs: testers,
  6034. k: key,
  6035. test: function(value) {
  6036. return !!~stmt.priority(value);
  6037. },
  6038. priority: function(value) {
  6039. return priority(stmt, value);
  6040. }
  6041. };
  6042. return stmt;
  6043. }
  6044. //traversable statements
  6045. var TRAV_OP = this.traversable = {
  6046. $and: true,
  6047. $or: true,
  6048. $nor: true,
  6049. $trav: true,
  6050. $not: true
  6051. };
  6052. function _comparable(value) {
  6053. if(value instanceof Date) {
  6054. return value.getTime();
  6055. } else {
  6056. return value;
  6057. }
  6058. }
  6059. function btop(value) {
  6060. return value ? 0 : -1;
  6061. }
  6062. var _testers = this.testers = {
  6063. /**
  6064. */
  6065. $eq: function(a, b) {
  6066. return btop(a.test(b));
  6067. },
  6068. /**
  6069. */
  6070. $ne: function(a, b) {
  6071. return btop(!a.test(b));
  6072. },
  6073. /**
  6074. */
  6075. $lt: function(a, b) {
  6076. return btop(a > b);
  6077. },
  6078. /**
  6079. */
  6080. $gt: function(a, b) {
  6081. return btop(a < b);
  6082. },
  6083. /**
  6084. */
  6085. $lte: function(a, b) {
  6086. return btop(a >= b);
  6087. },
  6088. /**
  6089. */
  6090. $gte: function(a, b) {
  6091. return btop(a <= b);
  6092. },
  6093. /**
  6094. */
  6095. $exists: function(a, b) {
  6096. return btop(a === (b != null))
  6097. },
  6098. /**
  6099. */
  6100. $in: function(a, b) {
  6101. //intersecting an array
  6102. if(b instanceof Array) {
  6103. for(var i = b.length; i--;) {
  6104. if(~a.indexOf(b[i])) return i;
  6105. }
  6106. } else {
  6107. return btop(~a.indexOf(b));
  6108. }
  6109. return -1;
  6110. },
  6111. /**
  6112. */
  6113. $not: function(a, b) {
  6114. if(!a.test) throw new Error("$not test should include an expression, not a value. Use $ne instead.");
  6115. return btop(!a.test(b));
  6116. },
  6117. /**
  6118. */
  6119. $type: function(a, b, org) {
  6120. //instanceof doesn't work for strings / boolean. instanceof works with inheritance
  6121. return org ? btop(org instanceof a || org.constructor == a) : -1;
  6122. },
  6123. /**
  6124. */
  6125. $nin: function(a, b) {
  6126. return ~_testers.$in(a, b) ? -1 : 0;
  6127. },
  6128. /**
  6129. */
  6130. $mod: function(a, b) {
  6131. return b % a[0] == a[1] ? 0 : -1;
  6132. },
  6133. /**
  6134. */
  6135. $all: function(a, b) {
  6136. if (!b) b = [];
  6137. for(var i = a.length; i--;) {
  6138. var a1 = a[i];
  6139. var indexInB = ~b.indexOf(a1);
  6140. if(!indexInB) return -1;
  6141. }
  6142. return 0;
  6143. },
  6144. /**
  6145. */
  6146. $size: function(a, b) {
  6147. return b ? btop(a == b.length) : -1;
  6148. },
  6149. /**
  6150. */
  6151. $or: function(a, b) {
  6152. var i = a.length, p, n = i;
  6153. for(; i--;) {
  6154. if(~priority(a[i], b)) {
  6155. return i;
  6156. }
  6157. }
  6158. return btop(n == 0);
  6159. },
  6160. /**
  6161. */
  6162. $nor: function(a, b) {
  6163. var i = a.length, n = i;
  6164. for(; i--;) {
  6165. if(~priority(a[i], b)) {
  6166. return -1;
  6167. }
  6168. }
  6169. return 0;
  6170. },
  6171. /**
  6172. */
  6173. $and: function(a, b) {
  6174. for(var i = a.length; i--;) {
  6175. if(!~priority(a[i], b)) {
  6176. return -1;
  6177. }
  6178. }
  6179. return 0;
  6180. },
  6181. /**
  6182. */
  6183. $trav: function(a, b) {
  6184. if(b instanceof Array) {
  6185. for(var i = b.length; i--;) {
  6186. var subb = b[i];
  6187. if(subb[a.k] && ~priority(a, subb[a.k])) return i;
  6188. }
  6189. return -1;
  6190. }
  6191. //continue to traverse even if there isn't a value - this is needed for
  6192. //something like name:{$exists:false}
  6193. return priority(a, b ? b[a.k] : void 0);
  6194. },
  6195. /**
  6196. */
  6197. $regex: function(a, b) {
  6198. var aRE = new RegExp(a);
  6199. return aRE.test(b) ? 0 : -1;
  6200. }
  6201. }
  6202. var _prepare = {
  6203. /**
  6204. */
  6205. $eq: function(a) {
  6206. var fn;
  6207. if(a instanceof RegExp) {
  6208. return a;
  6209. } else if (a instanceof Function) {
  6210. fn = a;
  6211. } else {
  6212. fn = function(b) {
  6213. if(b instanceof Array) {
  6214. return ~b.indexOf(a);
  6215. } else {
  6216. return a == b;
  6217. }
  6218. }
  6219. }
  6220. return {
  6221. test: fn
  6222. }
  6223. },
  6224. /**
  6225. */
  6226. $ne: function(a) {
  6227. return _prepare.$eq(a);
  6228. }
  6229. };
  6230. var _getExpr = function(type, key, value) {
  6231. var v = _comparable(value);
  6232. return {
  6233. //k key
  6234. k: key,
  6235. //v value
  6236. v: _prepare[type] ? _prepare[type](v) : v,
  6237. //e eval
  6238. e: _testers[type]
  6239. };
  6240. }
  6241. })();
  6242. var getSelector = function(selector) {
  6243. if(!selector) {
  6244. return function(value) {
  6245. return value;
  6246. };
  6247. } else
  6248. if(typeof selector == 'function') {
  6249. return selector;
  6250. }
  6251. throw new Error("Unknown sift selector " + selector);
  6252. }
  6253. var sifter = function(query, selector) {
  6254. //build the filter for the sifter
  6255. var filter = _queryParser.parse(query);
  6256. //the function used to sift through the given array
  6257. var self = function(target) {
  6258. var sifted = [], results = [], testValue, value, priority;
  6259. //I'll typically start from the end, but in this case we need to keep the order
  6260. //of the array the same.
  6261. for(var i = 0, n = target.length; i < n; i++) {
  6262. value = target[i];
  6263. testValue = selector(value);
  6264. //priority = -1? it's not something we can use.
  6265. if(!~(priority = filter.priority(testValue))) continue;
  6266. sifted.push(value);
  6267. }
  6268. return sifted;
  6269. }
  6270. //set the test function incase the sifter isn't needed
  6271. self.test = filter.test;
  6272. self.score = filter.priority;
  6273. self.query = query;
  6274. return self;
  6275. }
  6276. /**
  6277. * sifts the given function
  6278. * @param query the mongodb query
  6279. * @param target the target array
  6280. * @param rawSelector the selector for plucking data from the given target
  6281. */
  6282. var sift = function(query, target, rawSelector) {
  6283. //must be an array
  6284. if(typeof target != "object") {
  6285. rawSelector = target;
  6286. target = void 0;
  6287. }
  6288. var sft = sifter(query, getSelector(rawSelector));
  6289. //target given? sift through it and return the filtered result
  6290. if(target) return sft(target);
  6291. //otherwise return the sifter func
  6292. return sft;
  6293. }
  6294. sift.use = function(options) {
  6295. if(options.operators) sift.useOperators(options.operators);
  6296. if (typeof options === "function") options(sift);
  6297. }
  6298. sift.useOperators = function(operators) {
  6299. for(var key in operators) {
  6300. sift.useOperator(key, operators[key]);
  6301. }
  6302. }
  6303. sift.useOperator = function(operator, optionsOrFn) {
  6304. var options = {};
  6305. if(typeof optionsOrFn == "object") {
  6306. options = optionsOrFn;
  6307. } else {
  6308. options = { test: optionsOrFn };
  6309. }
  6310. var key = "$" + operator;
  6311. _queryParser.testers[key] = options.test;
  6312. if(options.traversable || options.traverse) {
  6313. _queryParser.traversable[key] = true;
  6314. }
  6315. }
  6316. //node.js?
  6317. if((typeof module != 'undefined') && (typeof module.exports != 'undefined')) {
  6318. module.exports = sift;
  6319. } else
  6320. //browser?
  6321. if(typeof window != 'undefined') {
  6322. window.sift = sift;
  6323. }
  6324. })();
  6325. },{}],65:[function(require,module,exports){
  6326. // shim for using process in browser
  6327. var process = module.exports = {};
  6328. process.nextTick = (function () {
  6329. var canSetImmediate = typeof window !== 'undefined'
  6330. && window.setImmediate;
  6331. var canMutationObserver = typeof window !== 'undefined'
  6332. && window.MutationObserver;
  6333. var canPost = typeof window !== 'undefined'
  6334. && window.postMessage && window.addEventListener
  6335. ;
  6336. if (canSetImmediate) {
  6337. return function (f) { return window.setImmediate(f) };
  6338. }
  6339. var queue = [];
  6340. if (canMutationObserver) {
  6341. var hiddenDiv = document.createElement("div");
  6342. var observer = new MutationObserver(function () {
  6343. var queueList = queue.slice();
  6344. queue.length = 0;
  6345. queueList.forEach(function (fn) {
  6346. fn();
  6347. });
  6348. });
  6349. observer.observe(hiddenDiv, { attributes: true });
  6350. return function nextTick(fn) {
  6351. if (!queue.length) {
  6352. hiddenDiv.setAttribute('yes', 'no');
  6353. }
  6354. queue.push(fn);
  6355. };
  6356. }
  6357. if (canPost) {
  6358. window.addEventListener('message', function (ev) {
  6359. var source = ev.source;
  6360. if ((source === window || source === null) && ev.data === 'process-tick') {
  6361. ev.stopPropagation();
  6362. if (queue.length > 0) {
  6363. var fn = queue.shift();
  6364. fn();
  6365. }
  6366. }
  6367. }, true);
  6368. return function nextTick(fn) {
  6369. queue.push(fn);
  6370. window.postMessage('process-tick', '*');
  6371. };
  6372. }
  6373. return function nextTick(fn) {
  6374. setTimeout(fn, 0);
  6375. };
  6376. })();
  6377. process.title = 'browser';
  6378. process.browser = true;
  6379. process.env = {};
  6380. process.argv = [];
  6381. function noop() {}
  6382. process.on = noop;
  6383. process.addListener = noop;
  6384. process.once = noop;
  6385. process.off = noop;
  6386. process.removeListener = noop;
  6387. process.removeAllListeners = noop;
  6388. process.emit = noop;
  6389. process.binding = function (name) {
  6390. throw new Error('process.binding is not supported');
  6391. };
  6392. // TODO(shtylman)
  6393. process.cwd = function () { return '/' };
  6394. process.chdir = function (dir) {
  6395. throw new Error('process.chdir is not supported');
  6396. };
  6397. },{}]},{},[2])(2)
  6398. });