<?php
declare(strict_types=1);
require __DIR__.'/ProjectionContract.php';
require __DIR__.'/GiftContract.php';
$n=0;
function sameP($e,$a): void {global $n;++$n;if($e!==$a){throw new RuntimeException('projection assertion '.$n);}}
function rejectP(callable $f): void {$bad=false;try{$f();}catch(InvalidArgumentException $e){$bad=true;}sameP(true,$bad);}
$schema=virtualSchema();$base=['table'=>'cdx_shadow_single','alias'=>['cdx_shadow_single'=>'s'],'field'=>['s.wide_id'=>'order_id','s.amount'=>'money','s.id'],'operation'=>'select'];
$p=ProjectionContract::compile($base,$schema,false);
sameP(['order_id','money','id','cdx_shadow_0','cdx_shadow_1'],$p['names']);sameP([0,1,2],$p['visible']);sameP(2,count($p['restore']));sameP('unsigned_integer',$p['restore'][0]['rule']['kind']);sameP(18,$p['restore'][1]['rule']['scale']);
sameP(['source'=>'s.wide_id','alias'=>'order_id'],$p['columns'][0]);
$one=$base;$one['field']=['wide_id'];sameP(['wide_id','cdx_shadow_0'],ProjectionContract::compile($one,$schema,false)['names']);
$plain=$base;$plain['field']=['id','ratio'];sameP(null,ProjectionContract::compile($plain,$schema,false));
$star=$base;$star['field']=['*'];rejectP(function()use($star,$schema){ProjectionContract::compile($star,$schema,false);});
sameP(['id','wide_id','amount','ratio','label','n','cdx_shadow_0','cdx_shadow_1','cdx_shadow_2'],ProjectionContract::compile($star,$schema,true)['names']);
$qualified=$star;$qualified['field']=['s.*'];sameP(ProjectionContract::compile($star,$schema,true),ProjectionContract::compile($qualified,$schema,true));
foreach([
    ['join'=>[['other']]],['union'=>['x']],['group'=>'id'],['having'=>'id>0'],['distinct'=>true],['lock'=>true],['procedure'=>true],['operation'=>'selectInsert'],
    ['field'=>['missing']],['field'=>['wide_id AS x']],['field'=>['o.wide_id']],['field'=>['wide_id'=>'7']],['field'=>['wide_id'=>'dup','amount'=>'dup']],
    ['field'=>['wide_id'=>'cdx_shadow_0']],['table'=>'other'],['field'=>[new stdClass()]],['order'=>['RAND()']],['field'=>['s.*','wide_id']],
] as $change){rejectP(function()use($base,$schema,$change){ProjectionContract::compile(array_replace($base,$change),$schema,false);});}
$incomplete=$schema;unset($incomplete['columns'][2]['rule']['scale']);rejectP(function()use($base,$incomplete){ProjectionContract::compile($base,$incomplete,false);});
$duplicate=$schema;$duplicate['columns'][1]['name']='id';rejectP(function()use($base,$duplicate){ProjectionContract::compile($base,$duplicate,false);});
$gift=giftContract();$real=['table'=>'yoshop_user_gift_log','alias'=>['yoshop_user_gift_log'=>'g'],'field'=>['g.biz_order_id'=>'order_id','g.money'],'operation'=>'select'];
sameP(['order_id','money','cdx_shadow_0','cdx_shadow_1'],ProjectionContract::compile($real,$gift,false)['names']);
sameP(10,ProjectionContract::compile($real,$gift,false)['restore'][1]['rule']['precision']);
$real['field']=['*'];rejectP(function()use($real,$gift){ProjectionContract::compile($real,$gift,true);});
$real['field']=['is_delete'];rejectP(function()use($real,$gift){ProjectionContract::compile($real,$gift,false);});
$real['field']=['log_id'];sameP(null,ProjectionContract::compile($real,$gift,false));
echo json_encode(['status'=>'pass','assertions'=>$n,'database_queries'=>0]).PHP_EOL;
