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

Encode links in a way the server can understand #5835

Merged
merged 9 commits into from
Sep 15, 2022
Merged

Conversation

jedelbo
Copy link
Contributor

@jedelbo jedelbo commented Sep 8, 2022

What, How & Why?

Fixes #5409

☑️ ToDos

  • 📝 Changelog update
  • 🚦 Tests (or not relevant)
  • C-API, if public C++ API changed.

@jedelbo jedelbo requested a review from ironage September 8, 2022 09:57
@cla-bot cla-bot bot added the cla: yes label Sep 8, 2022
@jedelbo jedelbo requested a review from mpobrien September 8, 2022 10:27
src/realm/query_engine.hpp Outdated Show resolved Hide resolved
src/realm/query_engine.hpp Show resolved Hide resolved
test/test_parser.cpp Outdated Show resolved Hide resolved
test/test_parser.cpp Show resolved Hide resolved
src/realm/query_expression.hpp Outdated Show resolved Hide resolved
@jedelbo jedelbo force-pushed the je/parser-primary-key branch from 111c1b7 to af5ae16 Compare September 9, 2022 11:38
@jedelbo jedelbo force-pushed the je/parser-primary-key branch from af5ae16 to 8e028eb Compare September 9, 2022 12:35
Copy link

@mpobrien mpobrien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other follow-up; on the original ticket description we were talking about two forms of link, one which has the table explicitly set (for a "typed link" or for use in a mixed column) and one which just holds the primary key of the target object, without specifying the target table.
AFAICT this only covers the former case; do we need to also implement the latter as well, or is that a separate task?

@@ -109,6 +112,8 @@ struct SerialisationState {
std::string get_variable_name(ConstTableRef table);
std::vector<std::string> subquery_prefix_list;
std::string class_prefix;
Group* group;
ConstTableRef taget_table;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ConstTableRef taget_table;
ConstTableRef target_table;

if constexpr (std::is_same_v<T, TypeOfValue>) {
return util::serializer::print_value(val.get_type_of_value());
}
else if constexpr (std::is_same_v<T, ObjKey>) {
ObjLink link(state.taget_table->get_key(), val.template get<ObjKey>());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to have a defensive check in case the target table is null before dereferencing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

}
else {
ss << "L" << link.get_table_key().value << ":" << link.get_obj_key().value;
TableRef target_table = g->get_table(link.get_table_key());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a null check on the group and fallback to the "Lx:y" syntax if not found.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check!

ss << "L" << link.get_table_key().value << ":" << link.get_obj_key().value;
TableRef target_table = g->get_table(link.get_table_key());
if (ColKey pk_col = target_table ? target_table->get_primary_key_column() : ColKey{}) {
if (auto obj = target_table->try_get_object(link.get_obj_key())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice a problem here which is not trivial to solve:

  1. User A makes a subscription which queries to a link that exists locally.
  2. User B deletes the target object.
  3. User A adds another unrelated query to the subscription set.
  4. Realm serializes User A's subscription queries again, but not finding the original target object locally here uses the Lx:y syntax.
  5. Server cannot parse this and sends a subscription error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could refuse to serialize this query.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about giving ObjLink an util::Optional<Mixed> m_pk member field? Then the serializer would use that info to print the primary key directly without looking up the object key which will work even if the object is deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a hack, I think. But are you sure the scenario will play out as described above? As far as I can tell, the query string is stored as text in the file. Will the query ever be serialized again?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, you are correct. A subscription query is serialized once and the text is stored and reused. So maybe this is not a problem after all. @jbreams can you confirm this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed.

@jedelbo
Copy link
Contributor Author

jedelbo commented Sep 12, 2022

@mpobrien I suggest that we only support the form where we supply both table and object. I don't see any downsides and it makes implementation much easier.

@mpobrien
Copy link

@mpobrien I suggest that we only support the form where we supply both table and object. I don't see any downsides and it makes implementation much easier.

Sounds good to me. I think there is one additional consideration related to this for when we get to implementing support for this on the server side. The client's query might try to be querying on a link identity like foo = obj('TableX', '...') but the server schema actually defines that field foo has a relationship with TableY, not TableX. I believe we'd need the server to detect this condition and reject it as an invalid query.

@jedelbo jedelbo merged commit 8f49440 into master Sep 15, 2022
@jedelbo jedelbo deleted the je/parser-primary-key branch September 15, 2022 13:59
tgoyne added a commit that referenced this pull request Sep 16, 2022
…nification

* origin/master:
  Stop forcing enums to be 64 bits unnecessarily
  clean up documentation of internal fields in config structs
  SyncConfig should be default constructible
  Traversal functions use IteratorControl values rather than true/false which is more expressive (#5857)
  Fix handling of 4-byte UTF8 values on Windows (#5803)
  Encode links in a way the server can understand (#5835)
  expose `Group::remove_table` in the C API (#5860)
  Disable auto refresh for old realm during migration (#5856)
  Expose `list_find` in the c api (#5848)
  Do not allow asymmetric tables in pbs (#5853)
  Refactor link tracing code (#5796)
  Expose `Obj::get_parent_object` in the C API (#5851)
  Update app.hpp (#5854)
  Fix appending to list ignores existing query (#5850)
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RQL sent to server for links should use encoding that the server can understand
4 participants