Repository navigation
feat(graphile-function-source): create/updateFunctionFromSource — write functions from SQL text - #1918
Merged
Conversation
…unctions from SQL text
Contributor
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
Review complete. No blocking issues — approved ✅; 1 nitpick below. 🧹 Nitpicks (1) — 🟢 1 low
This PR introduces a new
Reviewed commit: 690aa0e |
…function's definition from SQL text
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets a client create and replace a function from
CREATE FUNCTIONtext through GraphQL, without pre-parsing it intobody_ast. The server parses the text and writes the same row the generatedcreateFunction/updateFunctionwould. The database decides whether a definition is allowed; this plugin only parses and writes.It ships as a new standalone package,
graphile-function-source(graphile/graphile-function-source, laid out likegraphile-upload-plugin). It ownsparseFunctionSource,FunctionFromSourcePlugin/FunctionFromSourcePreset, the error codes and theFunctionDefinitiontype, and depends onplpgsql-parser.graphile-settingsdepends on it (workspace:^), andConstructivePresetextendsFunctionFromSourcePresetthe same way it extendsUploadPreset.graphile-settingsdoesn't re-export it and doesn't depend onplpgsql-parser. The package's tests run in thepg-graphqlCI job.CREATE FUNCTIONstatement.CREATE OR REPLACEis refused by both withFUNCTION_SOURCE_UNSUPPORTED. The message points toupdateFunctionFromSourcewith the function's id, because replacing is chosen by the mutation, not by the text.parseFunctionSource,plpgsql-parser@^18.5.14). The statement maps onto the existingmetaschema_public.functioncolumns:name,kind(plpgsql/sql/triggerwhenRETURNS trigger),arguments[{name,type:FieldType,mode}],returns({type,setof}or{table}),volatility,is_strict,security_invoker,body_ast.body_astis the hydratedPLpgSQL_function,datumsintact.body_astis the parsed body ({stmts}).pgInsertSingle(resource, {database_id, schema_id, api_exposed, ...definition})andpgUpdateSingle(resource, { id }, definition), sharing onedefinitionColumnshelper, on the request's own pg client. Update writes only the 8 definition columns;database_id,schema_idandapi_exposedare not touched. There's no role switch and no hand-written SQL.extensions: { code: 'FUNCTION_SOURCE_PARSE_ERROR', position }.positionis the parser's 0-based offset into the submitted source; for SQL-body errors it is mapped back to the source.FUNCTION_SOURCE_UNSUPPORTEDinstead of being silently dropped. That covers qualified names,OR REPLACE, argument defaults,COST/SET/…, other languages, and multiple statements.SECURITY DEFINERis passed through assecurity_invoker = false, so the database can refuse it.syntax error at or near "RETRN") but noposition.Tests
These cover the plugin's mechanics only. Authorization belongs to the database and is tested with the database.
__tests__/function-from-source.test.ts: mapping for plpgsql / sql / trigger /RETURNS TABLE/ typmods / variadic, parse-error positions, and the unsupported refusals (OR REPLACEincluded; one parser serves both mutations).__tests__/function-from-source.integration.test.ts(graphile-test +FunctionFromSourcePresetovermetaschema_public, with one database and schema seeded):datumsintact;OR REPLACEand changes nothing;Before / after
Current tests against the plugin before
updateFunctionFromSource(0a33ca0):After:
The create tests were checked the same way when they were added: with the plugin removed they failed, and with it they passed.
Publish
graphile-function-source(new), thengraphile-settingsand whatever lerna bumps with it (constructive-graphql-test,@constructive-io/graphql-test, …).Link to Devin session: https://app.devin.ai/sessions/b8a3bb3787ae4afb991d6498d1c51f7d
Open in Devin Desktop: https://app.devin.ai/desktop/session/b8a3bb3787ae4afb991d6498d1c51f7d?variant=devin
Requested by: @pyramation