-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Maybe bug?] Empty array does not show up in nested write #81
Comments
Hey @steventhan yes this is by design. We want to default the relationship to We do have other ways to delete/disassociate relationships though https://www.graphiti.dev/guides/concepts/resources#sideposting In theory we could support something like this with a special flag or something, but I tend to think it's not worth the effort as a less-common use case (with a big possible downside). If you have this scenario, consider a one-off separate resource for the special case, or maybe a magic attribute flag (ie |
I had the same problem and made a generic solution. Company
.includes(['employees'])
.find(123)
.then(data => data.data.detachWhenEmpty(['employees'])) All you have to do is to extend your Base class with this class: @Model()
export default class BaseModel extends SpraypaintBaseDetachRelationsWhenEmpty {
static baseUrl = process.env.API_URL
static apiNamespace = '/v1'
// ...
} import { isArray, isEmpty } from 'lodash';
import { Attr, SpraypaintBase } from 'spraypaint';
import { SaveOptions } from 'spraypaint/lib-esm/model';
export default class SpraypaintBaseDetachRelationsWhenEmpty extends SpraypaintBase {
/**
* hack to allow detaching all relations since spraypaint does not send an empty array
* @see CommonRessourceRequest.php -> after()
* https://github.com/graphiti-api/spraypaint.js/issues/81
*/
@Attr() private detachRelationsByName: string[] = []
detachRelationsWhenEmptyByName: string[] = []
detachWhenEmpty(names: string|string[]): this {
if(isArray(names)) {
for(const name of names) {
this.detachRelationsWhenEmptyByName.push(name)
}
} else {
this.detachRelationsWhenEmptyByName.push(names)
}
return this
}
private checkDetachRelationsWhenEmpty() {
for(const relationName of this.detachRelationsWhenEmptyByName) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const relation = this[relationName]
if(isEmpty(relation)) {
if(this.detachRelationsByName === null) {
this.detachRelationsByName = []
}
this.detachRelationsByName.push(relationName)
}
}
}
save<I extends SpraypaintBase>(options?: SaveOptions<I>): Promise<boolean> {
this.checkDetachRelationsWhenEmpty()
return super.save(options);
}
} If you are using Laravel JSON:API in your backend, you can check the field dynamically, too: CompanySchema.php class CompanySchema extends CommonSchema {
public function fields(): array
{
return self::withDefaults([
// fields for company
]);
}
} CommonSchema.php abstract class CommonSchema extends Schema {
public static function withDefaults(array $fields): array {
return array_merge($fields, [
ArrayList::make('detachRelationsByName') // @see CommonRessourceRequest::after()
]);
}
} CompanyRequest.php class CompanyRequest extends CommonRessourceRequest {
// ...
} CommonRessourceRequest.php use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Validation\Validator;
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
abstract class CommonRessourceRequest extends ResourceRequest {
/**
* https://laravel.com/docs/10.x/validation#performing-additional-validation-on-form-requests
*
* @return array
*/
public function after(): array {
return [
/**
* hack to allow detaching all relations since spraypaint does not send an empty array
* @see SpraypaintBaseDetachRelationsWhenEmpty.ts
* https://github.com/graphiti-api/spraypaint.js/issues/81
*/
function (Validator $validator) {
$detachRelationsByName = request()?->input('data.attributes.detachRelationsByName');
$model = $this->model();
if(isset($detachRelationsByName, $model)) {
foreach ($detachRelationsByName as $relationName) {
if($model->isRelation($relationName)) {
$relation = $model->{$relationName}();
$data = $validator->getData();
unset($data[$relationName]); // prevent existing values being merged
$validator->setData($data);
if($relation instanceof BelongsToMany) {
$relation->detach();
}
elseif($relation instanceof BelongsTo) {
$relation->disassociate();
}
// add other relation types if needed
}
}
}
}
];
}
} |
E.g. a
Company
that has manyEmployee
This is the payload which doesn't include the
relationships
field:It seems to be because of this line explicitly setting it to
null
https://github.com/graphiti-api/spraypaint.js/blob/master/src/util/write-payload.ts#L115
I just wonder this is intended? (JSON:API spec allows replacement of the entire array: https://jsonapi.org/format/#crud-updating-resource-relationships)
The text was updated successfully, but these errors were encountered: