Skip to content
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

LegendState w Supabase is only getting one of my tasks from my tasks table #467

Open
ac3kb opened this issue Feb 14, 2025 · 3 comments
Open

Comments

@ac3kb
Copy link

ac3kb commented Feb 14, 2025

I am attempting to try out LegendState with my Supabase database in React Native Expo. I already have many Tasks on my tasks table prior to integrating LegendState and have not created any using the LegendState interface. However, when I console log my tasks$.get(), it only shows one of my tasks from the table, and if I use the For component to try to render them all, only one task is shown. I've referenced both the LegendState docs and Supabase's blog for setup. Maybe I'm not understanding and this is the intended output?

This is my setup:

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: {
    storage: AsyncStorage,
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false,
  },
});

AppState.addEventListener("change", (state) => {
  if (state === "active") {
    supabase.auth.startAutoRefresh();
  } else {
    supabase.auth.stopAutoRefresh();
  }
});

const generateId = () => uuidv4();

export const isAuthed$ = observable(false);

// Create a configured sync function
const customSynced = configureSynced(syncedSupabase, {
  persist: {
    plugin: observablePersistAsyncStorage({
      AsyncStorage,
    }),
  },
  generateId,
  supabase,
  changesSince: "all", 
  fieldCreatedAt: "created_at",
  fieldUpdatedAt: "updated_at",
  // Optionally enable soft deletes
  fieldDeleted: "deleted",
  waitFor: isAuthed$,
});

export const tasks$ = observable(
  customSynced({
    supabase,
    collection: "tasks",
    select: (from) => from.select("*"),
    actions: ["read"],
    //realtime: true,
    // Persist data and pending changes locally
    persist: {
      name: "tasks",
      retrySync: true, // Persist pending changes and retry
    },
    retry: {
      infinite: true, // Retry changes with exponential backoff
    },
  })
);

Here i try to see the contents:

const SomeComponent = () => {
  const tasks = tasks$.get();
  console.log("Tasks:", tasks);
  return (
    <For
      each={tasks$}
      item={({ item$ }) => <Text>{item$?.task.toString()}</Text>}
    />
  );
};

The console.log response:

Tasks: {
  undefined: {
    completed: true,
    created_at: "2025-02-14T03:41:31.758327+00:00",
    deleted: false,
    priority: 2,
    task: "Task name",
    task_id: "a0917051-d44e-40d7-b180-87f99987ff4b",
    updated_at: "2025-02-14T03:41:31.758327+00:00",
    user_id: "513e05a9-6f75-4831-8322-f22c37cb0e9e",
  },
}
@jmeistrich
Copy link
Contributor

It's because you used a custom id field name (it defaults to "id"), so it's seeing every task as having an id of undefined. So you just need to add a fieldId prop:

export const tasks$ = observable(
  customSynced({
    // ...,
    fieldId: "task_id"
  })
);

We should probably be catching this with a warning. I'll leave this open as a note to do that.

@ac3kb
Copy link
Author

ac3kb commented Feb 18, 2025

It's because you used a custom id field name (it defaults to "id"), so it's seeing every task as having an id of undefined. So you just need to add a fieldId prop:

export const tasks$ = observable(
customSynced({
// ...,
fieldId: "task_id"
})
);
We should probably be catching this with a warning. I'll leave this open as a note to do that.

Awsome, that fixed the issue. Is this also affecting update and delete methods? when the primary key of the table is something other than 'id' I can list and create a new table entry with this syntax

tasks$[id].set({
      task_id: id,
      task: task,
 });

however when i try to update with this

export const toggleCompleted = (taskId: string) => {
  tasks$[taskId].set((prev) => ({ ...prev, completed: !prev?.completed }));
};

export const deleteTask = (taskId: string) => {
  tasks$[taskId].delete();
};

tasks on my client will be updated and deleted but there are no changes on my Supabase table. From the onError: (error) => console.log(error) on my customSynced object, I'm getting [Error: column tasks.id does not exist], even though i have fieldId: "task_id".

I've cleared async storage and that doesn't seem to be the issue.

@Herklos
Copy link

Herklos commented Feb 24, 2025

It's because you used a custom id field name (it defaults to "id"), so it's seeing every task as having an id of undefined. So you just need to add a fieldId prop:
export const tasks$ = observable(
customSynced({
// ...,
fieldId: "task_id"
})
);
We should probably be catching this with a warning. I'll leave this open as a note to do that.

Awsome, that fixed the issue. Is this also affecting update and delete methods? when the primary key of the table is something other than 'id' I can list and create a new table entry with this syntax

tasks$[id].set({
      task_id: id,
      task: task,
 });

however when i try to update with this

export const toggleCompleted = (taskId: string) => {
  tasks$[taskId].set((prev) => ({ ...prev, completed: !prev?.completed }));
};

export const deleteTask = (taskId: string) => {
  tasks$[taskId].delete();
};

tasks on my client will be updated and deleted but there are no changes on my Supabase table. From the onError: (error) => console.log(error) on my customSynced object, I'm getting [Error: column tasks.id does not exist], even though i have fieldId: "task_id".

I've cleared async storage and that doesn't seem to be the issue.

I've the same issue, fieldId works well with select and filter but it doesn't seem to work with update and delete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants