Skip to content
256 changes: 132 additions & 124 deletions src/CacheKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,66 @@ public function make(
return $key;
}

protected function getBindingsSlug() : string
{
if (! method_exists($this->model, 'query')) {
return '';
}

return Arr::query($this->model->query()->getBindings());
}

protected function getColumnClauses(array $where) : string
{
if ($where["type"] !== "Column") {
return "";
}

return "-{$where["boolean"]}_{$where["first"]}_{$where["operator"]}_{$where["second"]}";
}

protected function getCurrentBinding(string $type, $bindingFallback = null)
{
return data_get($this->query->bindings, "{$type}.{$this->currentBinding}", $bindingFallback);
}

protected function getIdColumn(string $idColumn) : string
{
return $idColumn ? "_{$idColumn}" : "";
}

protected function getInAndNotInClauses(array $where) : string
{
if (! in_array($where["type"], ["In", "NotIn", "InRaw"])) {
return "";
}

$type = strtolower($where["type"]);
$subquery = $this->getValuesFromWhere($where);
$values = collect($this->getCurrentBinding('where', []));

if (Str::startsWith($subquery, $values->first())) {
$this->currentBinding += count($where["values"]);
}

if (! is_numeric($subquery) && ! is_numeric(str_replace("_", "", $subquery))) {
try {
$subquery = Uuid::fromBytes($subquery);
$values = $this->recursiveImplode([$subquery], "_");

return "-{$where["column"]}_{$type}{$values}";
} catch (Exception $exception) {
// do nothing
}
}

$subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);
$subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
$values = $this->recursiveImplode($subquery->toArray(), "_");

return "-{$where["column"]}_{$type}{$values}";
}

protected function getLimitClause() : string
{
if (! property_exists($this->query, "limit")
Expand All @@ -67,15 +122,18 @@ protected function getLimitClause() : string
return "-limit_{$this->query->limit}";
}

protected function getTableSlug() : string
protected function getModelSlug() : string
{
return (new Str)->slug($this->query->from)
. ":";
return (new Str)->slug(get_class($this->model));
}

protected function getModelSlug() : string
protected function getNestedClauses(array $where) : string
{
return (new Str)->slug(get_class($this->model));
if (! in_array($where["type"], ["Exists", "Nested", "NotExists"])) {
return "";
}

return "-" . strtolower($where["type"]) . $this->getWhereClauses($where["query"]->wheres);
}

protected function getOffsetClause() : string
Expand Down Expand Up @@ -110,6 +168,18 @@ protected function getOrderByClauses() : string
?: "";
}

protected function getOtherClauses(array $where) : string
{
if (in_array($where["type"], ["Exists", "Nested", "NotExists", "Column", "raw", "In", "NotIn", "InRaw"])) {
return "";
}

$value = $this->getTypeClause($where);
$value .= $this->getValuesClause($where);

return "-{$where["column"]}_{$value}";
}

protected function getQueryColumns(array $columns) : string
{
if (($columns === ["*"]
Expand All @@ -129,6 +199,36 @@ protected function getQueryColumns(array $columns) : string
return "_" . implode("_", $columns);
}

protected function getRawClauses(array $where) : string
{
if (! in_array($where["type"], ["raw"])) {
return "";
}

$queryParts = explode("?", $where["sql"]);
$clause = "_{$where["boolean"]}";

while (count($queryParts) > 1) {
$clause .= "_" . array_shift($queryParts);
$clause .= $this->getCurrentBinding("where");
$this->currentBinding++;
}

$lastPart = array_shift($queryParts);

if ($lastPart) {
$clause .= "_" . $lastPart;
}

return "-" . str_replace(" ", "_", $clause);
}

protected function getTableSlug() : string
{
return (new Str)->slug($this->query->from)
. ":";
}

protected function getTypeClause($where) : string
{
$type = in_array($where["type"], ["InRaw", "In", "NotIn", "Null", "NotNull", "between", "NotInSub", "InSub", "JsonContains"])
Expand Down Expand Up @@ -174,12 +274,15 @@ protected function getValuesFromWhere(array $where) : string

protected function getValuesFromBindings(array $where, string $values) : string
{
if (($this->query->bindings["where"][$this->currentBinding] ?? false) !== false) {
$values = $this->query->bindings["where"][$this->currentBinding];
$bindingFallback = __CLASS__ . ':UNKNOWN_BINDING';
$currentBinding = $this->getCurrentBinding("where", $bindingFallback);

if ($currentBinding !== $bindingFallback) {
$values = $currentBinding;
$this->currentBinding++;

if ($where["type"] === "between") {
$values .= "_" . $this->query->bindings["where"][$this->currentBinding];
$values .= "_" . $this->getCurrentBinding("where");
$this->currentBinding++;
}
}
Expand Down Expand Up @@ -207,57 +310,41 @@ protected function getWhereClauses(array $wheres = []) : string
return $value;
});
}

protected function getNestedClauses(array $where) : string
protected function getWheres(array $wheres) : Collection
{
if (! in_array($where["type"], ["Exists", "Nested", "NotExists"])) {
return "";
}

return "-" . strtolower($where["type"]) . $this->getWhereClauses($where["query"]->wheres);
}
$wheres = collect($wheres);

protected function getColumnClauses(array $where) : string
{
if ($where["type"] !== "Column") {
return "";
if ($wheres->isEmpty()
&& property_exists($this->query, "wheres")
) {
$wheres = collect($this->query->wheres);
}

return "-{$where["boolean"]}_{$where["first"]}_{$where["operator"]}_{$where["second"]}";
return $wheres;
}

protected function getInAndNotInClauses(array $where) : string
protected function getWithModels() : string
{
if (! in_array($where["type"], ["In", "NotIn", "InRaw"])) {
return "";
}

$type = strtolower($where["type"]);
$subquery = $this->getValuesFromWhere($where);
$values = collect($this->query->bindings["where"][$this->currentBinding] ?? []);
$eagerLoads = collect($this->eagerLoad);

if (Str::startsWith($subquery, $values->first())) {
$this->currentBinding += count($where["values"]);
if ($eagerLoads->isEmpty()) {
return "";
}

if (! is_numeric($subquery) && ! is_numeric(str_replace("_", "", $subquery))) {
try {
$subquery = Uuid::fromBytes($subquery);
$values = $this->recursiveImplode([$subquery], "_");

return "-{$where["column"]}_{$type}{$values}";
} catch (Exception $exception) {
// do nothing
return $eagerLoads->keys()->reduce(function ($carry, $related) {
if (! method_exists($this->model, $related)) {
return "{$carry}-{$related}";
}
}

$subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);
$subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
$values = $this->recursiveImplode($subquery->toArray(), "_");
$relatedModel = $this->model->$related()->getRelated();
$relatedConnection = $relatedModel->getConnection()->getName();
$relatedDatabase = $relatedModel->getConnection()->getDatabaseName();

return "-{$where["column"]}_{$type}{$values}";
return "{$carry}-{$relatedConnection}:{$relatedDatabase}:{$related}";
});
}

protected function recursiveImplode(array $items, string $glue = ",") : string
{
$result = "";
Expand All @@ -283,83 +370,4 @@ protected function recursiveImplode(array $items, string $glue = ",") : string

return $result;
}

protected function getRawClauses(array $where) : string
{
if (! in_array($where["type"], ["raw"])) {
return "";
}

$queryParts = explode("?", $where["sql"]);
$clause = "_{$where["boolean"]}";

while (count($queryParts) > 1) {
$clause .= "_" . array_shift($queryParts);
$clause .= $this->query->bindings["where"][$this->currentBinding];
$this->currentBinding++;
}

$lastPart = array_shift($queryParts);

if ($lastPart) {
$clause .= "_" . $lastPart;
}

return "-" . str_replace(" ", "_", $clause);
}

protected function getOtherClauses(array $where) : string
{
if (in_array($where["type"], ["Exists", "Nested", "NotExists", "Column", "raw", "In", "NotIn", "InRaw"])) {
return "";
}

$value = $this->getTypeClause($where);
$value .= $this->getValuesClause($where);

return "-{$where["column"]}_{$value}";
}

protected function getWheres(array $wheres) : Collection
{
$wheres = collect($wheres);

if ($wheres->isEmpty()
&& property_exists($this->query, "wheres")
) {
$wheres = collect($this->query->wheres);
}

return $wheres;
}

protected function getWithModels() : string
{
$eagerLoads = collect($this->eagerLoad);

if ($eagerLoads->isEmpty()) {
return "";
}

return $eagerLoads->keys()->reduce(function ($carry, $related) {
if (! method_exists($this->model, $related)) {
return "{$carry}-{$related}";
}

$relatedModel = $this->model->$related()->getRelated();
$relatedConnection = $relatedModel->getConnection()->getName();
$relatedDatabase = $relatedModel->getConnection()->getDatabaseName();

return "{$carry}-{$relatedConnection}:{$relatedDatabase}:{$related}";
});
}

protected function getBindingsSlug() : string
{
if (! method_exists($this->model, 'query')) {
return '';
}

return Arr::query($this->model->query()->getBindings());
}
}
Loading