-
Notifications
You must be signed in to change notification settings - Fork 143
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
fix(electric): Sync rows that were in the table prior to electrification #1108
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably works for the case you're testing, but I hit a related problem in my permissions e2e test.
In this test if I swap the order of the inserts and electrification I get an error later in the test when inserting into the project_memberships table caused by logical replication message with nil
tags.
Details here: https://linear.app/electric-sql/issue/VAX-1750/inserting-into-a-table-fails-when-electrifying-a-table-with-existing
might be worth adding an e2e test that reproduces this situation
end | ||
|
||
defp unwrap_quotes("\"" <> _ = name), do: String.slice(name, 1..-2//1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be entirely over-defensive about it we should also be replacing any ""
with "
. Wouldn't String.trim_trailing\2
be a little more explicit about what we're doing here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically not equivalent given that a double-quote inside the quoted string will be represented by ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started hating this "defensive" function definition the moment wrote it. I have since changed the approach to use unquoted {<schema>, <table>}
tuples and only produce quoted identifiers immediately prior to using them in an SQL string.
@magnetised Good catch! We could try addressing this issue in a general way by creating a view over the shadow table that would return default values for all columns if a shadow row is missing. But then those defaults would need to work in different contexts where shadow rows are queried. Right now we just have these two places in the code where only @icehaunter thoughts? |
I think addressing it in those places is good enough |
10e51a9
to
50ad6e2
Compare
8ec5298
to
bbe03f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
schema_version | ||
|> SchemaVersion.table!(layer.target_table) | ||
|> Schema.single_table_info(schema_version.schema) | ||
|
||
columns = Enum.map_join(table.columns, ", ", &~s|this."#{&1.name}"|) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should maybe document a restriction that electrified tables or columns in electrified tables can't contain "
in their names... seems a) reasonable and b) that it would save us a lot of time defensively escaping quotes everywhere...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the reasonable part. People have all kinds of weird things in their schemas when those are generated by a tool instead of being written by hand.
We should pick some SQL fragment builder utility and use it pervasively. Switching to using Ecto's query API is one option. That will get easier to do if #1136 is accepted it merged (once it's done).
] | ||
|> Enum.reject(&(is_nil(&1) or &1 == "")) | ||
|> Enum.intersperse(" AND ") | ||
|
||
where = if where_clauses != [], do: ["WHERE ", where_clauses], else: "" | ||
|
||
user_table = {table_info.schema, table_info.name} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this just layer.target_table
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, great point!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice job!
When a table is electrified, its newly created shadow table is empty. If the table had any rows prior to electrification, they would remain invisible to Electric due to the JOIN between the user table and its shadow table performed when querying for initial subscription data.
7856b97
to
13e3b72
Compare
When a table is electrified, its newly created shadow table is empty. If the user table had any rows prior to electrification, they would remain invisible to Electric due to the JOIN between the user table and its shadow table performed when querying for initial subscription data.
Fixes #1106, VAX-1750.