staudenmeir/eloquent-json-relations

String values fail for belongsToJson and HasManyJson

madsem opened this issue · 4 comments

Hey @staudenmeir,

thanks a lot for this package, I have been using it for a while and it was working great.
Today I updated and made some changes to an existing app, so I can't say if the update caused this, or if I am simply doing something wrong...

But in any case, I am using this in conjunction with FilamentPhp table & form builder, which saves JSON values as string...
Before it was working with string values, but now it's not any longer:

use Staudenmeir\EloquentJsonRelations\Relations\HasManyJson;

class LanderOfferSet  extends Model
{

use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;

protected $casts = [
        'offers' => 'json',
];

public function landers(): HasManyJson
    {
        return $this->hasManyJson(Lander::class, 'lander_offer_sets[]->lander_offer_set_id');
    }
}
use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson;

class Lander extends Model
{
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
    use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;

public function landerOfferSets(): BelongsToJson
    {
        return $this->belongsToJson(LanderOfferSet::class, 'lander_offer_sets[]->lander_offer_set_id');
    }

LanderFactory:

'lander_offer_sets' => [
                0 => [
                    'lander_offer_set_id' => (string) LanderOfferSet::factory()->create()->id,
                    'lander_element_id' => fake()->uuid(),
                ],
                1 => [
                    'lander_offer_set_id' => (string) LanderOfferSet::factory()->create()->id,
                    'lander_element_id' => fake()->uuid(),
                ],
            ],

LanderOfferSetFactory:

'offers' => [
                0 => [
                    'offer_id' => (string) Offer::factory()->create()->id,
                    'redirect_weight' => '40',
                    'is_active' => false,
                ],
                1 => [
                    'offer_id' =>  (string) Offer::factory()->create()->id,
                    'redirect_weight' => '100',
                    'is_active' => true,
                ],
            ],

landers table, lander_offer_sets:

[{"lander_element_id": "88338d96-6c37-3874-a1ca-bf89a216dc2d", "lander_offer_set_id": "1"}, {"lander_element_id": "5b4b897e-62c3-359a-8d75-a53caa612655", "lander_offer_set_id": "2"}]

All relationship queries fail since I set up my factories with (string) casts, if I remove it everything works.

Now I know that HasManyJson uses whereJsonContains and that it only works with INT, but BelongsToJson also fails, all relationship counts in my Livewire components show 0:

TextColumn::make('lander_offer_sets_count')
                ->counts('landerOfferSets')
                ->label('# of Offer Sets')
                ->url(fn (Model $record) => route('lander-offer-sets', ['tableFilters' => ['landers' => ['value' => $record->id]]])),

When I change the values back to "lander_offer_set_id": 2, both relationships work flawlessly.

What can I do here to make this work reliably throughout my application?

Is there any way to override something and cast all values to int?

Hi @madsem,

Before it was working with string values, but now it's not any longer:

lander_offer_set_id values have always been strings and that worked with both BelongsToJson and HasManyJson relationships?

madsem commented

Hi @madsem,

Before it was working with string values, but now it's not any longer:

lander_offer_set_id values have always been strings and that worked with both BelongsToJson and HasManyJson relationships?

Hey 👋

So, not quite. There used to be just an "offer" relationship, I am rewriting this atm.

But it used to be the exact same type of relationship, like i said: When I change the Factories to integer model FKs, everything starts working.

Currently Im thinking the only way to make it future proof, would be to hook into thr Models booted method and cast values to int.

But it would be great if this could be solved differently? :)

Ps: Before I was using only the BelongsToJson, which was working. But now, it's not

I haven't tested any solutions so I can't recommend anything. You could also look into custom casts.

madsem commented

Thanks 🙏

Wanted to make sure i'm using it right ;)
The custom casts could work well too! Good idea