Skip to content

Commit e00796b

Browse files
committed
Refactor BelongsToArrayColumn: streamline JSON contains constraints and enhance eager loading logic
1 parent 474bc97 commit e00796b

File tree

1 file changed

+81
-14
lines changed

1 file changed

+81
-14
lines changed

src/Relations/BelongsToArrayColumn.php

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ public function addConstraints(): void
2929
}
3030
$query = $this->getBaseQuery();
3131

32-
$query->when($this->isString, function ($q) {
33-
$q->whereJsonContains($this->ownerKey, (string) $this->getParentKey());
34-
}, function ($q) {
35-
$q->whereJsonContains($this->ownerKey, $this->getParentKey());
36-
});
32+
$parentKey = $this->getParentKey();
33+
if ($parentKey !== null) {
34+
$searchValue = $this->isString ? (string) $parentKey : $parentKey;
35+
$this->addJsonContainsConstraint($query, $this->ownerKey, $searchValue);
36+
}
3737

3838
$query->whereNotNull($this->ownerKey);
3939
}
@@ -44,15 +44,37 @@ public function addConstraints(): void
4444
public function addEagerConstraints(array $models): void
4545
{
4646
$ids = $this->getEagerModelKeys($models);
47-
$this->query->where(function ($q) use ($ids) {
48-
foreach ($ids as $id) {
49-
$q->when($this->isString, function ($q) use ($id) {
50-
$q->orWhereJsonContains($this->ownerKey, (string) $id);
51-
}, function ($q) use ($id) {
52-
$q->orWhereJsonContains($this->ownerKey, $id);
53-
});
54-
}
55-
});
47+
48+
if ($this->isString) {
49+
// For strings, simple OR with quoted values
50+
$this->query->where(function ($q) use ($ids) {
51+
foreach ($ids as $id) {
52+
$q->orWhere($this->ownerKey, 'LIKE', '%"' . $id . '"%');
53+
}
54+
});
55+
} else {
56+
// For integers, use pattern matching with OR logic
57+
$this->query->where(function ($q) use ($ids) {
58+
foreach ($ids as $id) {
59+
$q->orWhere(function ($subQuery) use ($id) {
60+
$patterns = [
61+
'%[' . $id . ',%',
62+
'%,' . $id . ',%',
63+
'%,' . $id . ']%',
64+
'%[' . $id . ']%'
65+
];
66+
67+
foreach ($patterns as $i => $pattern) {
68+
if ($i === 0) {
69+
$subQuery->where($this->ownerKey, 'LIKE', $pattern);
70+
} else {
71+
$subQuery->orWhere($this->ownerKey, 'LIKE', $pattern);
72+
}
73+
}
74+
});
75+
}
76+
});
77+
}
5678
}
5779

5880
/**
@@ -85,4 +107,49 @@ public function getResults(): mixed
85107
{
86108
return $this->query->get();
87109
}
110+
111+
/**
112+
* Add JSON contains constraint in a database-agnostic way.
113+
* Uses pattern matching that works across all database engines and Laravel versions.
114+
*/
115+
protected function addJsonContainsConstraint($query, string $column, $value, string $boolean = 'and'): void
116+
{
117+
// Use pattern matching for all databases to ensure compatibility
118+
// with prefer-lowest dependency resolution in CI environments
119+
if ($this->isString) {
120+
// For strings, search for quoted value: "value"
121+
$method = $boolean === 'or' ? 'orWhere' : 'where';
122+
$query->$method($column, 'LIKE', '%"' . $value . '"%');
123+
} else {
124+
// For integers, use precise pattern matching for unquoted numbers
125+
$patterns = [
126+
'%[' . $value . ',%', // [1,
127+
'%,' . $value . ',%', // ,1,
128+
'%,' . $value . ']%', // ,1]
129+
'%[' . $value . ']%' // [1]
130+
];
131+
132+
if ($boolean === 'or') {
133+
$query->orWhere(function ($subQuery) use ($column, $patterns) {
134+
foreach ($patterns as $i => $pattern) {
135+
if ($i === 0) {
136+
$subQuery->where($column, 'LIKE', $pattern);
137+
} else {
138+
$subQuery->orWhere($column, 'LIKE', $pattern);
139+
}
140+
}
141+
});
142+
} else {
143+
$query->where(function ($subQuery) use ($column, $patterns) {
144+
foreach ($patterns as $i => $pattern) {
145+
if ($i === 0) {
146+
$subQuery->where($column, 'LIKE', $pattern);
147+
} else {
148+
$subQuery->orWhere($column, 'LIKE', $pattern);
149+
}
150+
}
151+
});
152+
}
153+
}
154+
}
88155
}

0 commit comments

Comments
 (0)