Adds LegacyFilterToQueryFilterTransformer#271
Adds LegacyFilterToQueryFilterTransformer#271suddendust wants to merge 8 commits intohypertrace:mainfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #271 +/- ##
============================================
+ Coverage 80.52% 80.63% +0.10%
Complexity 1396 1396
============================================
Files 239 240 +1
Lines 6695 6815 +120
Branches 615 636 +21
============================================
+ Hits 5391 5495 +104
- Misses 900 907 +7
- Partials 404 413 +9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| * | ||
| * <p>Resolution strategy: progressively try shorter prefixes to find a JSONB column. | ||
| */ | ||
| private Optional<String> findJsonbColumnPrefix(String path) { |
There was a problem hiding this comment.
what is the use case for this one? Maybe some documented example will help
There was a problem hiding this comment.
So say the identifier in the filter is props.inheritiedAttributes.color = 'red'. Now, three possibilities arise:
propsis the json col andinheritiedAttributes.coloris the path.props.inheritiedAttributesis the jsonb col andcoloris the path.props.inheritiedAttributes.coloris the jsonb col.
This method progressively looks for prefixes and checks its type to determine which case it is.
| return Optional.empty(); | ||
| } | ||
|
|
||
| /** Extracts the nested JSONB path from a full path given the resolved column name. */ |
| } | ||
|
|
||
| if (value instanceof Object[]) { | ||
| return createConstantExpressionFromCollection(Arrays.asList((Object[]) value)); |
There was a problem hiding this comment.
so, if query is getting fired from the old path, we would need to figure out type at runtime?
There was a problem hiding this comment.
By old path, do you mean Mongo? If so, then it doesn't really case about the types. Here's how the parser looks:
Object value = filter.getValue();
Map<String, Object> map = new HashMap<>();
switch (op) {
case EQ:
map.put(filter.getFieldName(), value);
It just puts in the object. The driver determines the type at runtime.
There was a problem hiding this comment.
I meant if someone is using legacy filter?
There was a problem hiding this comment.
Oh gotcha. Since legacy filters with PG is today works on nested docs, it basically extracts them as text using ->> and cast:
public static String prepareCast(String field, Object value) {
return prepareCast(field, getType(value));
}
public static String prepareCast(String field, Type type) {
String fmt = "CAST (%s AS %s)";
if (type.equals(Type.NUMERIC)) {
return String.format(fmt, field, type);
} else if (type.equals(Type.BOOLEAN)) {
return String.format(fmt, field, type);
} else /* default is string */ {
return field;
}
}
Type is determined by the value:
public static Type getType(Object value) {
boolean isArrayType = false;
Type type = Type.STRING;
// handle the case if the value type is collection for filter operator - `IN`
// Currently, for `IN` operator, we are considering List collection, and it is fair
// assumption that all its value of the same types. Based on that and for consistency
// we will use CAST ( <field name> as <type> ) for all non string operator.
// Ref : https://github.com/hypertrace/document-store/pull/30#discussion_r571782575
if (value instanceof List<?> && ((List<Object>) value).size() > 0) {
List<Object> listValue = (List<Object>) value;
value = listValue.get(0);
isArrayType = true;
}
if (value instanceof Number) {
type = Type.NUMERIC;
} else if (value instanceof Boolean) {
type = Type.BOOLEAN;
} else if (isArrayType) {
type = Type.STRING_ARRAY;
}
return type;
}
There was a problem hiding this comment.
So, for anyone migrating, the recommendation would be to use new filter interface?
There was a problem hiding this comment.
I haven't added any new methods to the Collection interface that accept the new filter directly - Clients would still have to pass in the older filter and this converter would convert it internally. While I can add those methods, I feel this way clients wouldn't have to change their code.
There was a problem hiding this comment.
Would that leave us in the same inefficient query problems that we faced in the read path? Might be non-issue if update patterns are largely id based.
…to pg_writes_filter_transformer
Add Legacy-to-Query Filter Transformer
Summary
Enables flat PostgreSQL collections to use the v1 query parser by transforming legacy filters to the newer query filter format.
Why
We want to move to using the new filter API now. It's also hardened in production since the query layer uses it throughout.
What
AND,OR,EQ,IN,LIKE, etc).SchemaRegistryto detect the type of the columns (since this information is not carried in the legacy filters).Transformation Example