-
Notifications
You must be signed in to change notification settings - Fork 7
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
tweak(adminPanel): RN-1273: Map overlay relations by code #5646
Conversation
function getColSelector(connection, inputColStr) { | ||
const jsonOperatorPattern = /->>?/g; | ||
if (!jsonOperatorPattern.test(inputColStr)) return inputColStr; | ||
if (jsonOperatorPattern.test(inputColStr)) { | ||
const params = inputColStr.split(jsonOperatorPattern); | ||
const allButFirst = params.slice(1); | ||
const lastIndexOfLookupAsText = inputColStr.lastIndexOf('->>'); | ||
const lastIndexOfLookupAsJson = inputColStr.lastIndexOf('->'); | ||
const selector = lastIndexOfLookupAsText >= lastIndexOfLookupAsJson ? '#>>' : '#>'; | ||
|
||
// Turn `config->item->>colour` into `config #>> '{item,colour}'` | ||
// For some reason, Knex fails when we try to convert it to `config->'item'->>'colour'` | ||
return connection.raw(`?? ${selector} '{${allButFirst.map(() => '??').join(',')}}'`, params); | ||
} | ||
|
||
const params = inputColStr.split(jsonOperatorPattern); | ||
const allButFirst = params.slice(1); | ||
const lastIndexOfLookupAsText = inputColStr.lastIndexOf('->>'); | ||
const lastIndexOfLookupAsJson = inputColStr.lastIndexOf('->'); | ||
const selector = lastIndexOfLookupAsText >= lastIndexOfLookupAsJson ? '#>>' : '#>'; | ||
/** | ||
* Special handling of COALESCE() - one of the {@link supportedFunctions} - to treat its arguments | ||
* as identifiers individually rather than trying to treat ‘COALESCE(foo, bar)’ as a single | ||
* identifier. | ||
*/ | ||
const coalescePattern = /^COALESCE\(.+\)$/; | ||
if (coalescePattern.test(inputColStr)) { | ||
const [, argsString] = inputColStr.match(/^COALESCE\((.+)\)$/); | ||
const bindings = argsString.split(',').map(arg => arg.trim()); | ||
const identifiers = bindings.map(() => '??'); | ||
|
||
return connection.raw(`COALESCE(${identifiers})`, bindings); | ||
} | ||
|
||
// Turn `config->item->>colour` into `config #>> '{item,colour}'` | ||
// For some reason, Knex fails when we try to convert it to `config->'item'->>'colour'` | ||
return connection.raw(`?? ${selector} '{${allButFirst.map(() => '??').join(',')}}'`, params); | ||
return inputColStr; | ||
} |
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.
Two notes:
- This implementation assumes we never have a column selector which both calls
COALESCE()
and uses JSON selectors. If that happens, this algorithm fails. Is this a concern? - Should I make it iterate through
supportedFunctions
to handle any function in that array?
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.
- Ah that's fine I think
- Probably worth it I think! Would make this functionality a lot more future proof if we want to make more use of db functions. If you're happy to 🙏
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.
Hm, it occurs to me that, given some supportedFunction
, it would be difficult to know whether to treat its arguments as ?
values or ??
identifiers
I could just build in an assumption and always use ??
, but this would silently break any attempt to use a function that takes, say, a number. For example, if we have ROUND(foo, 2)
Knex would complain that there’s no column called "2"
. As far as I can tell, we would need to hard-code it to do ROUND(??, ?)
I can’t think of a clean way about this, so have left some comments about why COALESCE
gets special handling, and that this might extend to future supported functions too. Would be thrilled if you can think of something obvious I’ve missed, but going to go ahead as-is for now
packages/admin-panel/src/routes/visualisations/mapOverlayGroupRelations.js
Show resolved
Hide resolved
139b415
to
2809015
Compare
2809015
to
8920597
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.
Awesome stuff @jaskfla 🎉
This issue is definitely one of those things that looks super easy on the surface, but is deceptively tricky. Thanks for pushing through with it and really happy with the end result (I feel like it tidies up and makes a few things more consistent with the CRUDHandler
and DatabaseModel
behaviour)
Just a comment to ask if we can loop over the supported functions when sanitizing the WHERE clause identifier, but pre-approving
function getColSelector(connection, inputColStr) { | ||
const jsonOperatorPattern = /->>?/g; | ||
if (!jsonOperatorPattern.test(inputColStr)) return inputColStr; | ||
if (jsonOperatorPattern.test(inputColStr)) { | ||
const params = inputColStr.split(jsonOperatorPattern); | ||
const allButFirst = params.slice(1); | ||
const lastIndexOfLookupAsText = inputColStr.lastIndexOf('->>'); | ||
const lastIndexOfLookupAsJson = inputColStr.lastIndexOf('->'); | ||
const selector = lastIndexOfLookupAsText >= lastIndexOfLookupAsJson ? '#>>' : '#>'; | ||
|
||
// Turn `config->item->>colour` into `config #>> '{item,colour}'` | ||
// For some reason, Knex fails when we try to convert it to `config->'item'->>'colour'` | ||
return connection.raw(`?? ${selector} '{${allButFirst.map(() => '??').join(',')}}'`, params); | ||
} | ||
|
||
const params = inputColStr.split(jsonOperatorPattern); | ||
const allButFirst = params.slice(1); | ||
const lastIndexOfLookupAsText = inputColStr.lastIndexOf('->>'); | ||
const lastIndexOfLookupAsJson = inputColStr.lastIndexOf('->'); | ||
const selector = lastIndexOfLookupAsText >= lastIndexOfLookupAsJson ? '#>>' : '#>'; | ||
/** | ||
* Special handling of COALESCE() - one of the {@link supportedFunctions} - to treat its arguments | ||
* as identifiers individually rather than trying to treat ‘COALESCE(foo, bar)’ as a single | ||
* identifier. | ||
*/ | ||
const coalescePattern = /^COALESCE\(.+\)$/; | ||
if (coalescePattern.test(inputColStr)) { | ||
const [, argsString] = inputColStr.match(/^COALESCE\((.+)\)$/); | ||
const bindings = argsString.split(',').map(arg => arg.trim()); | ||
const identifiers = bindings.map(() => '??'); | ||
|
||
return connection.raw(`COALESCE(${identifiers})`, bindings); | ||
} | ||
|
||
// Turn `config->item->>colour` into `config #>> '{item,colour}'` | ||
// For some reason, Knex fails when we try to convert it to `config->'item'->>'colour'` | ||
return connection.raw(`?? ${selector} '{${allButFirst.map(() => '??').join(',')}}'`, params); | ||
return inputColStr; | ||
} |
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.
- Ah that's fine I think
- Probably worth it I think! Would make this functionality a lot more future proof if we want to make more use of db functions. If you're happy to 🙏
Issue RN-1273: Map overlay group relation id to code
Changes
child_code
toMapOverlayGroupRelation
at the model levelModel changes based largely off #4270, which was closed without mergingNot anymore