(Experimental) Export a DBSearch as an array/JSON structure.

This commit is contained in:
Denis Flaven
2019-11-13 18:03:37 +01:00
parent 30430bb7dc
commit 36584092e5
4 changed files with 279 additions and 2 deletions

View File

@@ -1524,6 +1524,80 @@ class DBObjectSearch extends DBSearch
}
}
/**
* {@inheritDoc}
* @see DBSearch::ToJSON()
*/
public function ToJSON()
{
$aRet = array('selects' => array(), 'joins' => array(), 'where' => array());
$aParams = array_merge($this->m_aParams);
$aParams = MetaModel::PrepareQueryArguments($aParams);
foreach ($this->m_aSelectedClasses as $sAlias => $sClass)
{
$aRet['selects'][] = array('class' => $sClass, 'alias' => $sAlias);
}
$this->JoinsToJSON($aRet);
$aRet['condition'] = $this->m_oSearchCondition->ToJSON($aParams, true);
return $aRet;
}
/**
* Export the JOIN operations to a structure (array of arrays) suitable for JSON export
*
* @internal
*
* @param mixed[string] $aRet
* @return void
*/
protected function JoinsToJSON(&$aRet)
{
foreach($this->m_aPointingTo as $sExtKey => $aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
$sOperator = $this->OperatorCodeToOQL($iOperatorCode);
foreach($aFilter as $oFilter)
{
$aRet['joins'][] = array(
'src' => $this->GetFirstJoinedClass(),
'src_alias' => $this->GetFirstJoinedClassAlias(),
'target' => $oFilter->GetFirstJoinedClass(),
'target_alias' => $oFilter->GetFirstJoinedClassAlias(),
'foreign_key' => $sExtKey,
'operator' => $sOperator,
);
$oFilter->JoinsToJSON($aRet);
}
}
}
foreach($this->m_aReferencedBy as $aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator)
{
foreach ($aFiltersByOperator as $iOperatorCode => $aFilters)
{
$sOperator = $this->OperatorCodeToOQL($iOperatorCode);
foreach ($aFilters as $oForeignFilter)
{
$aRet['joins'][] = array(
'src' => $oForeignFilter->GetFirstJoinedClass(),
'src_alias' => $oForeignFilter->GetFirstJoinedClassAlias(),
'target' => $this->GetFirstJoinedClass(),
'target_alias' => $this->GetFirstJoinedClassAlias(),
'foreign_key' => $sForeignExtKeyAttCode,
'operator' => $sOperator,
);
$oForeignFilter->JoinsToJSON($aRet);
}
}
}
}
}
public function InitFromOqlQuery(OqlQuery $oOqlQuery, $sQuery)
{
$oModelReflection = new ModelReflectionRuntime();

View File

@@ -699,6 +699,15 @@ abstract class DBSearch
*/
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
/**
* Export the DBSearch as a structure (array of arrays...) suitable for a conversion to JSON
*
* @internal
*
* @return mixed[string]
*/
abstract public function ToJSON();
static protected $m_aOQLQueries = array();
/**
@@ -734,12 +743,13 @@ abstract class DBSearch
*
* @param string $sQuery The OQL to convert to a DBSearch
* @param mixed[string] $aParams array of <mixed> params index by <string> name
* @param ModelReflection|null $oMetaModel The MetaModel to use when checking the consistency of the OQL
*
* @return DBObjectSearch|DBUnionSearch
*
* @throws OQLException
*/
static public function FromOQL($sQuery, $aParams = null)
static public function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel=null)
{
if (empty($sQuery))
{
@@ -781,7 +791,10 @@ abstract class DBSearch
$oOql = new OqlInterpreter($sQuery);
$oOqlQuery = $oOql->ParseQuery();
$oMetaModel = new ModelReflectionRuntime();
if ($oMetaModel === null)
{
$oMetaModel = new ModelReflectionRuntime();
}
$oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue
$oResultFilter = $oOqlQuery->ToDBSearch($sQuery);

View File

@@ -463,6 +463,20 @@ class DBUnionSearch extends DBSearch
return $sRet;
}
/**
* {@inheritDoc}
* @see DBSearch::ToJSON()
*/
public function ToJSON()
{
$sRet = array('unions' => array());
foreach ($this->aSearches as $oSearch)
{
$sRet['unions'][] = $oSearch->ToJSON();
}
return $sRet;
}
/**
* Returns a new DBUnionSearch object where duplicates queries have been removed based on their OQLs
*

View File

@@ -27,6 +27,17 @@ class MissingQueryArgument extends CoreException
*/
abstract class Expression
{
public const OPERATOR_BINARY = 'binary';
public const OPERATOR_BOOLEAN = 'boolean_binary';
public const OPERATOR_FIELD = 'field';
public const OPERATOR_FUNCTION = 'function';
public const OPERATOR_INTERVAL = 'interval';
public const OPERATOR_LIST = 'list';
public const OPERATOR_SCALAR = 'scalar';
public const OPERATOR_UNARY = 'unary';
public const OPERATOR_VARIABLE = 'variable';
/**
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
**/
@@ -98,6 +109,15 @@ abstract class Expression
*/
abstract public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false);
/**
* Recursively renders the expression as a structure (array) suitable for a JSON export
*
* @param mixed[string] $aArgs
* @param boolean $bRetrofitParams
* @return mixed[string]
*/
abstract public function ToJSON(&$aArgs = null, $bRetrofitParams = false);
/**
* @param DBObjectSearch $oSearch
* @param array $aArgs
@@ -277,6 +297,12 @@ class SQLExpression extends Expression
return $this->m_sSQL;
}
// recursive rendering
public function toJSON(&$aArgs = null, $bRetrofitParams = false)
{
return null; // TODO should we throw an Exception ??
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -413,6 +439,31 @@ class BinaryExpression extends Expression
return "($sLeft $sOperator $sRight)";
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
if (($this->GetOperator() == 'AND') || ($this->GetOperator() == 'OR'))
{
return array(
'type' => static::OPERATOR_BOOLEAN,
'operator' => $this->GetOperator(),
'left' => $this->GetLeftExpr()->ToJSON($aArgs, $bRetrofitParams),
'right' => $this->GetRightExpr()->ToJSON($aArgs, $bRetrofitParams),
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
return array(
'type' => static::OPERATOR_BINARY,
'operator' => $this->GetOperator(),
'left' => $this->GetLeftExpr()->ToJSON($aArgs, $bRetrofitParams),
'right' => $this->GetRightExpr()->ToJSON($aArgs, $bRetrofitParams),
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -789,6 +840,19 @@ class UnaryExpression extends Expression
return CMDBSource::Quote($this->m_value);
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
return array(
'type' => static::OPERATOR_UNARY,
'value' => $this->m_value,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -909,6 +973,19 @@ class ScalarExpression extends UnaryExpression
return $sRet;
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
return array(
'type' => static::OPERATOR_SCALAR,
'value' => $this->m_value,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function GetAsScalar($aArgs)
{
return clone $this;
@@ -1157,6 +1234,21 @@ class FieldExpression extends UnaryExpression
return "`{$this->m_sParent}`.`{$this->m_sName}`";
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
return array(
'type' => static::OPERATOR_FIELD,
'value' => $this->m_value,
'alias' => $this->m_sParent,
'field' => $this->m_sName,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function GetAttDef($aClasses = array())
{
if (!empty($this->m_sParent))
@@ -1546,6 +1638,19 @@ class VariableExpression extends UnaryExpression
}
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
return array(
'type' => static::OPERATOR_VARIABLE,
'value' => $this->m_value,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function RenameParam($sOldName, $sNewName)
{
if ($this->m_sName == $sOldName)
@@ -1645,6 +1750,24 @@ class ListExpression extends Expression
return '('.implode(', ', $aRes).')';
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
$aFields = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aFields[] = $oExpr->ToJSON($aArgs, $bRetrofitParams);
}
return array(
'type' => static::OPERATOR_LIST,
'fields' => $aFields,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -1798,6 +1921,26 @@ class FunctionExpression extends Expression
return $this->m_sVerb.'('.implode(', ', $aRes).')';
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
$aFields = array();
foreach ($this->m_aArgs as $oExpr)
{
$aFields[] = $oExpr->ToJSON($aArgs, $bRetrofitParams);
}
return array(
'type' => static::OPERATOR_FUNCTION,
'operator' => $this->m_sVerb,
'fields' => $aFields,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -2093,6 +2236,20 @@ class IntervalExpression extends Expression
return 'INTERVAL '.$this->m_oValue->RenderExpression($bForSQL, $aArgs, $bRetrofitParams).' '.$this->m_sUnit;
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
return array(
'type' => static::OPERATOR_INTERVAL,
'unit' => $this->m_sUnit,
'expression' => $this->m_oValue->ToJSON($aArgs, $bRetrofitParams),
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
);
}
public function Browse(Closure $callback)
{
$callback($this);
@@ -2192,6 +2349,25 @@ class CharConcatExpression extends Expression
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
}
/**
* {@inheritDoc}
* @see Expression::ToJSON()
*/
public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
{
$aFields = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aFields[] = $oExpr->RenderExpression($aArgs, $bRetrofitParams);
}
return array(
'type' => static::OPERATOR_FUNCTION,
'operator' => 'concat',
'fields' => $aFields,
);
}
public function Browse(Closure $callback)
{
$callback($this);