-
-
Notifications
You must be signed in to change notification settings - Fork 43
Description
Environment
- Operating System:
Linux - Node Version:
v18.12.1
Reproduction
See #1619
This is the schema:
import { Model } from "pinia-orm";
export class User extends Model {
static entity = "user" as const;
static fields() {
return {
id: this.uid(),
name: this.string(""),
episodes: this.hasMany(UserSavedEpisode, "user_id").onDelete("cascade"),
};
}
declare id: number;
declare name: string;
declare episodes: UserSavedEpisode;
}
export class UserSavedEpisode extends Model {
static entity = "savedEpisode";
static primaryKey = ["user_id", "episode_id"];
// static primaryKey = "episode_id" // change the primary key to a non-composite and delete user works
static fields() {
return {
user_id: this.uid(),
episode_id: this.uid(),
human: this.belongsTo(User, "user_id"),
};
}
declare user_id: string;
declare episode_id: string;
}Here is vue code to reproduce the error:
<script setup lang="ts">
import { computed } from "vue";
import { useRepo } from "pinia-orm";
import { User, UserSavedEpisode } from "/src/bugreport";
const user = useRepo(User);
const usersavedepisode = useRepo(UserSavedEpisode);
function clear() {
user.flush();
usersavedepisode.flush();
}
function save_user() {
user.save({
id: "userid",
name: "tintin10q",
});
}
function insert_episode() {
usersavedepisode.save({
user_id: "userid",
episode_id: "episode_id",
});
}
function delete_user() {
user.destroy("userid");
}
const theuser = computed(() => user.query().whereId("userid").with("episodes").first());
const all_episodes = computed(() => usersavedepisode.all());
</script>
<template>
<div style="display: flex; flex-direction: column; gap:.25rem">
<button @click="save_user()">Create user</button>
<button @click="insert_episode()">Give user episode</button>
<button @click="delete_user()">Delete User</button>
<button @click="clear()">Clear</button>
</div>
<h2>User</h2>
<span> User: {{ theuser }} </span>
<h2>Episodes</h2>
<div v-for="i in all_episodes">{{ i }}</div>
</template>- Click create user
- Click give user episode
- Click delete episode and observe the error
- Make the primary key of saved episode a single primary key. (uncomment line 22 and comment out line 21)
- Observe that you don't get an error now
Describe the bug
You can not use .onDelete("cascade") if you have a model with a composite primary key.
I get this error:
Uncaught (in promise) Error: [Pinia ORM] Please provide the local key for the relationship. The model with the composite key can't infer its local key.
Additional context
With a composite primary key it makes sense that when you are cascading a delete you don't have all the values for the other parts of the primary key. This means that indeed, you can not cascade the delete based on deleting with the primary key. So if you delete a user and want to cascade the delete you do not know all the episode ids required to delete all the usersavedepisode by primary key.
But you could still simply perform the delete by doing the equivalent of usersavedepisode.query().where('user_id','user_id').delete(). This way you can still cascade the delete anyway.
Another way could be to first query all the usersavedepisode with the specific user_id which we are trying to delete and then delete based on primary key with the user_id and the obtained primary keys. But to me that just sounds like double the amount of work and more complicated than the first solution.
Logs
Uncaught Error: [Pinia ORM] Please provide the local key for the relationship. The model with the composite key can't infer its local key.
throwError pinia-orm.1cd11660.mjs:99
assert pinia-orm.1cd11660.mjs:103
$getLocalKey index.mjs:2791
relationIds index.mjs:1198
checkAndDeleteRelations index.mjs:1197
dispatchDeleteHooks index.mjs:1236
dispatchDeleteHooks index.mjs:1229
destroyOne index.mjs:1153
destroy index.mjs:1147
destroy index.mjs:1598
delete_user Test.vue:30