├── .babelrc ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .vscode └── launch.json ├── LICENSE ├── _from-postgraphile ├── PgIntrospectionPlugin.js └── introspectionQuery.js ├── _tmp ├── intro.sql ├── ownership.sql ├── roles.sql └── usage.sql ├── bin ├── pgdbi │ ├── __test │ │ └── test_helper.ts │ ├── dist │ │ ├── be8c8ec05b6dad115347.worker.js │ │ ├── be8c8ec05b6dad115347.worker.js.map │ │ ├── css │ │ │ ├── app.89ce3cd1.css │ │ │ └── chunk-vendors.89bed726.css │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── js │ │ │ ├── about.5bee4903.js │ │ │ ├── about.5bee4903.js.map │ │ │ ├── app.0637cf86.js │ │ │ ├── app.0637cf86.js.map │ │ │ ├── chunk-vendors.13f58bb9.js │ │ │ ├── chunk-vendors.13f58bb9.js.map │ │ │ ├── pdfjsWorker.157d1873.js │ │ │ └── pdfjsWorker.157d1873.js.map │ │ └── logo.png │ ├── graphile-extensions │ │ ├── dbSchema │ │ │ ├── index.js │ │ │ ├── introspection.js │ │ │ ├── pgdbiOptions.js │ │ │ └── resolvers │ │ │ │ ├── checkConstraint │ │ │ │ └── tableConstraint.js │ │ │ │ ├── column │ │ │ │ └── keyColumnUsage.js │ │ │ │ ├── enabledRole │ │ │ │ └── applicableRoles.js │ │ │ │ ├── function │ │ │ │ ├── functionById.js │ │ │ │ └── searchFunctions.js │ │ │ │ ├── keyColumnUsage │ │ │ │ └── referentialConstraints.js │ │ │ │ ├── referentialConstraint │ │ │ │ ├── referencedColumnUsage.js │ │ │ │ └── referencingColumnUsage.js │ │ │ │ ├── schema │ │ │ │ ├── id.js │ │ │ │ ├── schemaEnums.js │ │ │ │ ├── schemaFunctions.js │ │ │ │ ├── schemaTables.js │ │ │ │ └── schemaTreeBySchemaName.js │ │ │ │ ├── table │ │ │ │ ├── checkConstraints.js │ │ │ │ ├── id.js │ │ │ │ ├── indices.js │ │ │ │ ├── policies.js │ │ │ │ ├── primaryKeyConstraints.js │ │ │ │ ├── psqlDescription.js │ │ │ │ ├── referentialConstraints.js │ │ │ │ ├── roleColumnGrants.js │ │ │ │ ├── roleTableGrants.js │ │ │ │ ├── tableById.js │ │ │ │ ├── tableColumns.js │ │ │ │ ├── tableConstraints.js │ │ │ │ ├── triggers.js │ │ │ │ └── uniqueConstraints.js │ │ │ │ ├── tableConstraint │ │ │ │ └── keyColumnUsage.js │ │ │ │ └── trigger │ │ │ │ ├── id.js │ │ │ │ └── triggerFunction.js │ │ ├── execSql.js │ │ ├── pgIntrospectionResultsByKind.js │ │ ├── pgdbirc-default.js │ │ ├── pgdbirc.js │ │ ├── pglint.js │ │ ├── pglintrc-default.js │ │ ├── project.js │ │ └── writeArtifacts.js │ ├── index.js │ ├── pg10IntrospectionQuery.js │ ├── pg11IntrospectionQuery.js │ └── transformBuild.js └── sql │ └── schema_usage.sql ├── build.sh ├── columns.sql ├── evals.json ├── exampleScript-terse.sql ├── exampleScript-verbose.sql ├── index.js ├── introResult.json ├── meh.sql ├── package-lock.json ├── package.json ├── pglint-bash.sh ├── pglint-npx.sh ├── pglint.sh ├── project.md ├── readme.md ├── roadmap.md ├── src ├── dbDev │ ├── constraints.sql │ ├── execute.sh │ ├── functions.sql │ ├── indices.sql │ ├── inheritance.sql │ ├── intro.json │ ├── pgdbi-dev.sql │ ├── samp.sql │ ├── schemaTree.sql │ ├── scratch.sql │ ├── testSchema.sql │ └── udt.sql ├── devServer │ ├── index.js │ ├── phile.js │ ├── sqitch.conf │ ├── tasks │ │ └── testTask.js │ ├── voyager.worker.js │ └── worker.js ├── pgdbi │ ├── __test │ │ └── test_helper.ts │ ├── dist │ │ ├── be8c8ec05b6dad115347.worker.js │ │ ├── be8c8ec05b6dad115347.worker.js.map │ │ ├── css │ │ │ ├── app.89ce3cd1.css │ │ │ └── chunk-vendors.89bed726.css │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── js │ │ │ ├── about.5bee4903.js │ │ │ ├── about.5bee4903.js.map │ │ │ ├── app.0637cf86.js │ │ │ ├── app.0637cf86.js.map │ │ │ ├── chunk-vendors.13f58bb9.js │ │ │ ├── chunk-vendors.13f58bb9.js.map │ │ │ ├── pdfjsWorker.157d1873.js │ │ │ └── pdfjsWorker.157d1873.js.map │ │ └── logo.png │ ├── graphile-extensions │ │ ├── dbSchema │ │ │ ├── index.js │ │ │ ├── introspection.js │ │ │ ├── pgdbiOptions.js │ │ │ └── resolvers │ │ │ │ ├── checkConstraint │ │ │ │ └── tableConstraint.js │ │ │ │ ├── column │ │ │ │ └── keyColumnUsage.js │ │ │ │ ├── enabledRole │ │ │ │ └── applicableRoles.js │ │ │ │ ├── function │ │ │ │ ├── functionById.js │ │ │ │ └── searchFunctions.js │ │ │ │ ├── keyColumnUsage │ │ │ │ └── referentialConstraints.js │ │ │ │ ├── referentialConstraint │ │ │ │ ├── referencedColumnUsage.js │ │ │ │ └── referencingColumnUsage.js │ │ │ │ ├── schema │ │ │ │ ├── id.js │ │ │ │ ├── schemaEnums.js │ │ │ │ ├── schemaFunctions.js │ │ │ │ ├── schemaTables.js │ │ │ │ └── schemaTreeBySchemaName.js │ │ │ │ ├── table │ │ │ │ ├── checkConstraints.js │ │ │ │ ├── id.js │ │ │ │ ├── indices.js │ │ │ │ ├── policies.js │ │ │ │ ├── primaryKeyConstraints.js │ │ │ │ ├── psqlDescription.js │ │ │ │ ├── referentialConstraints.js │ │ │ │ ├── roleColumnGrants.js │ │ │ │ ├── roleTableGrants.js │ │ │ │ ├── tableById.js │ │ │ │ ├── tableColumns.js │ │ │ │ ├── tableConstraints.js │ │ │ │ ├── triggers.js │ │ │ │ └── uniqueConstraints.js │ │ │ │ ├── tableConstraint │ │ │ │ └── keyColumnUsage.js │ │ │ │ └── trigger │ │ │ │ ├── id.js │ │ │ │ └── triggerFunction.js │ │ ├── execSql.js │ │ ├── pgIntrospectionResultsByKind.js │ │ ├── pgdbirc-default.js │ │ ├── pgdbirc.js │ │ ├── pglint.js │ │ ├── pglintrc-default.js │ │ ├── project.js │ │ └── writeArtifacts.js │ ├── index.js │ ├── pg10IntrospectionQuery.js │ ├── pg11IntrospectionQuery.js │ └── transformBuild.js └── web-vue │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── delete │ ├── EnabledRoleListMixin.vue │ ├── RoleFilterFunctionsMixin.vue │ ├── RoleList.vue │ ├── SchemaFilter copy.vue │ ├── SchemaFilter.vue │ ├── SchemaTree copy.vue │ └── Table copy.vue │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── logo.png │ ├── src │ ├── App.vue │ ├── AppBus.js │ ├── assets │ │ └── logo.svg │ ├── components │ │ ├── Enum │ │ │ └── Enum.vue │ │ ├── ForeignKeyIndex │ │ │ ├── Constraints │ │ │ │ └── CheckConstraints.vue │ │ │ ├── ConstraintsAndIndices.vue │ │ │ ├── ConstraintsAndIndicesManager.vue │ │ │ ├── FkIndexConstraints.vue │ │ │ ├── GenericIndexDetail.vue │ │ │ ├── GenericIndexSet.vue │ │ │ └── UqIndexSet.vue │ │ ├── Function │ │ │ ├── Function.vue │ │ │ ├── FunctionList.vue │ │ │ └── FunctionSearch.vue │ │ ├── FunctionSecurity │ │ │ ├── Assignment │ │ │ │ ├── FunctionPolicyAssignment.vue │ │ │ │ ├── FunctionPolicyAssignmentByPolicy.vue │ │ │ │ ├── FunctionPolicyAssignmentBySchema.vue │ │ │ │ ├── FunctionPolicyAssignmentDialog.vue │ │ │ │ ├── FunctionPolicyAssignmentPolicy.vue │ │ │ │ └── FunctionPolicyAssignmentSchema.vue │ │ │ ├── Definition │ │ │ │ ├── FunctionPolicyDefinition.vue │ │ │ │ ├── FunctionPolicyDefinitionGrantGrid copy.vue │ │ │ │ └── FunctionPolicyDefinitionGrantGrid.vue │ │ │ ├── FunctionPolicyManager.vue │ │ │ └── Realization │ │ │ │ ├── FunctionPolicyRealization.vue │ │ │ │ └── FunctionSchemaSecurityScripts.vue │ │ ├── Help │ │ │ └── Help.vue │ │ ├── PgLint │ │ │ └── PgLintResult.vue │ │ ├── Project │ │ │ ├── ProjectExport.vue │ │ │ ├── ProjectImport.vue │ │ │ ├── ProjectNavigator.vue │ │ │ └── ProjectResetDialog.vue │ │ ├── Role │ │ │ ├── ChooseRoleSet.vue │ │ │ ├── CreateRolesRealization.vue │ │ │ └── Roles.vue │ │ ├── Schema │ │ │ ├── SchemaNavigator.vue │ │ │ ├── SchemaTree.vue │ │ │ └── SchemaUsageRealization.vue │ │ ├── Security │ │ │ ├── MasterSecurityPolicyRealization.vue │ │ │ └── OwnershipPolicyRealization.vue │ │ ├── Settings │ │ │ ├── DefaultRlsUsing.vue │ │ │ ├── SecurityPolicySettings.vue │ │ │ └── Settings.vue │ │ ├── SmartCommentManager │ │ │ └── SmartCommentManager.vue │ │ ├── Table │ │ │ ├── ColumnDetail.vue │ │ │ ├── Constraints │ │ │ │ ├── TableCheckConstraints.vue │ │ │ │ ├── TableKeyColumnUsage.vue │ │ │ │ ├── TableReferentialConstraints.vue │ │ │ │ └── TableUniqueConstraints.vue │ │ │ ├── Table.vue │ │ │ ├── TableColumnGrants.vue │ │ │ ├── TableColumns copy.vue │ │ │ ├── TableColumns.vue │ │ │ ├── TableConstraints.vue │ │ │ ├── TableDetail.vue │ │ │ ├── TableFkIndices.vue │ │ │ ├── TableGenericIndexDetail.vue │ │ │ ├── TableGenericIndices.vue │ │ │ ├── TableGrants.vue │ │ │ ├── TableIndices copy.vue │ │ │ ├── TableIndices.vue │ │ │ ├── TablePolicies.vue │ │ │ ├── TableScripts.vue │ │ │ ├── TableUqIndices.vue │ │ │ └── Triggers │ │ │ │ ├── TableTriggerSet.vue │ │ │ │ └── TableTriggers.vue │ │ ├── TableSecurity copy │ │ │ ├── Assignment │ │ │ │ ├── TablePolicyAssignment.vue │ │ │ │ ├── TablePolicyAssignmentByPolicy.vue │ │ │ │ ├── TablePolicyAssignmentBySchema.vue │ │ │ │ ├── TablePolicyAssignmentDialog.vue │ │ │ │ ├── TablePolicyAssignmentPolicy.vue │ │ │ │ └── TablePolicyAssignmentSchema.vue │ │ │ ├── Definition │ │ │ │ ├── Grants │ │ │ │ │ ├── ColumnExclusions │ │ │ │ │ │ ├── ColumnExclusionSet.vue │ │ │ │ │ │ ├── TablePolicyColumnExclusionDialog.vue │ │ │ │ │ │ └── TablePolicyDefinitionColumnExclusions.vue │ │ │ │ │ ├── TablePolicyDefinitionGrantGrid.vue │ │ │ │ │ └── TablePolicyDefinitionGrants.vue │ │ │ │ ├── TablePolicyDefinition.vue │ │ │ │ ├── TablePolicyRlsAction.vue │ │ │ │ └── TablePolicyRlsQualifierGrid.vue │ │ │ ├── Dialogs │ │ │ │ ├── RlsPolicyDialog.vue │ │ │ │ ├── TablePolicyCustomizeDialog.vue │ │ │ │ ├── TablePolicyDeleteDialog.vue │ │ │ │ ├── TablePolicyMakeGlobalDialog.vue │ │ │ │ └── TablePolicyRenameDialog.vue │ │ │ ├── Evaluation │ │ │ │ ├── TablePolicyEvaluatorCalculatorMixin.vue │ │ │ │ ├── TablePolicyEvaluatorDetail.vue │ │ │ │ └── TablePolicyEvaluatorSummary.vue │ │ │ ├── Realization │ │ │ │ ├── SchemaSecurityScripts.vue │ │ │ │ └── TablePolicyRealization.vue │ │ │ └── TablePolicyManager.vue │ │ ├── TableSecurity-next │ │ │ ├── Assignment │ │ │ │ ├── TablePolicyAssignment.vue │ │ │ │ ├── TablePolicyAssignmentByPolicy.vue │ │ │ │ ├── TablePolicyAssignmentBySchema.vue │ │ │ │ ├── TablePolicyAssignmentDialog.vue │ │ │ │ ├── TablePolicyAssignmentPolicy.vue │ │ │ │ └── TablePolicyAssignmentSchema.vue │ │ │ ├── Definition │ │ │ │ ├── Grants │ │ │ │ │ ├── ColumnExclusions │ │ │ │ │ │ ├── ColumnExclusionSet.vue │ │ │ │ │ │ ├── TablePolicyColumnExclusionDialog.vue │ │ │ │ │ │ └── TablePolicyDefinitionColumnExclusions.vue │ │ │ │ │ ├── TablePolicyDefinitionGrantGrid.vue │ │ │ │ │ └── TablePolicyDefinitionGrants.vue │ │ │ │ ├── TableGrantGrid.vue │ │ │ │ ├── TablePolicyDefinition.vue │ │ │ │ ├── TablePolicyRlsAction.vue │ │ │ │ ├── TablePolicyRlsQualifierGrid.vue │ │ │ │ ├── TableSecurityProfile.vue │ │ │ │ └── TableSecurityProfileManager.vue │ │ │ ├── Dialogs │ │ │ │ ├── RlsPolicyDialog.vue │ │ │ │ ├── TablePolicyCustomizeDialog.vue │ │ │ │ ├── TablePolicyDeleteDialog.vue │ │ │ │ ├── TablePolicyMakeGlobalDialog.vue │ │ │ │ └── TablePolicyRenameDialog.vue │ │ │ ├── Evaluation │ │ │ │ ├── TablePolicyEvaluatorCalculatorMixin.vue │ │ │ │ ├── TablePolicyEvaluatorDetail.vue │ │ │ │ └── TablePolicyEvaluatorSummary.vue │ │ │ ├── Realization │ │ │ │ ├── SchemaSecurityScripts.vue │ │ │ │ └── TablePolicyRealization.vue │ │ │ ├── Rls │ │ │ │ ├── CurrentRlsPolicies.vue │ │ │ │ ├── TableGrantGrid.vue │ │ │ │ └── TableSecurityProfile.vue │ │ │ └── TablePolicyManager.vue │ │ ├── TableSecurity │ │ │ ├── Assignment │ │ │ │ ├── TablePolicyAssignment.vue │ │ │ │ ├── TablePolicyAssignmentByPolicy.vue │ │ │ │ ├── TablePolicyAssignmentBySchema.vue │ │ │ │ ├── TablePolicyAssignmentDialog.vue │ │ │ │ ├── TablePolicyAssignmentPolicy.vue │ │ │ │ └── TablePolicyAssignmentSchema.vue │ │ │ ├── Definition │ │ │ │ ├── Grants │ │ │ │ │ ├── ColumnExclusions │ │ │ │ │ │ ├── ColumnExclusionSet.vue │ │ │ │ │ │ ├── TablePolicyColumnExclusionDialog.vue │ │ │ │ │ │ └── TablePolicyDefinitionColumnExclusions.vue │ │ │ │ │ ├── TablePolicyDefinitionGrantGrid.vue │ │ │ │ │ └── TablePolicyDefinitionGrants.vue │ │ │ │ ├── TableGrantGrid.vue │ │ │ │ ├── TablePolicyDefinition.vue │ │ │ │ ├── TablePolicyRlsAction.vue │ │ │ │ ├── TablePolicyRlsQualifierGrid.vue │ │ │ │ ├── TableSecurityProfile.vue │ │ │ │ └── TableSecurityProfileDefinitions.vue │ │ │ ├── Dialogs │ │ │ │ ├── RlsPolicyDialog.vue │ │ │ │ ├── TablePolicyCustomizeDialog.vue │ │ │ │ ├── TablePolicyDeleteDialog.vue │ │ │ │ ├── TablePolicyMakeGlobalDialog.vue │ │ │ │ ├── TablePolicyRenameDialog.vue │ │ │ │ └── TableRlsPolicyDialog.vue │ │ │ ├── Evaluation │ │ │ │ ├── TablePolicyEvaluatorCalculatorMixin.vue │ │ │ │ ├── TablePolicyEvaluatorDetail.vue │ │ │ │ └── TablePolicyEvaluatorSummary.vue │ │ │ └── Realization │ │ │ │ ├── SchemaSecurityScripts.vue │ │ │ │ └── TablePolicyRealization.vue │ │ ├── Udt │ │ │ └── Udt.vue │ │ ├── View │ │ │ ├── View.vue │ │ │ ├── ViewColumns.vue │ │ │ └── ViewSearch.vue │ │ └── _common │ │ │ └── ScriptViewer.vue │ ├── gql │ │ ├── mutation │ │ │ ├── execSql.graphql │ │ │ ├── pgLint.graphql │ │ │ ├── searchFunctions.graphql │ │ │ └── writeArtifacts.graphql │ │ └── query │ │ │ ├── allEnabledRoles.graphql │ │ │ ├── dbIntrospection.graphql │ │ │ ├── functionById.graphql │ │ │ ├── getDbSchemaList.graphql │ │ │ ├── getDbSchemaTree.graphql │ │ │ ├── getDbSchemaTreeBySchemaName.graphql │ │ │ ├── getDbSecurityTree.graphql │ │ │ ├── getDbSecurityTreeFiltered.graphql │ │ │ ├── pgdbirc.graphql │ │ │ ├── pglintrc.graphql │ │ │ ├── project.graphql │ │ │ ├── tableById-not.graphql │ │ │ └── tableById.graphql │ ├── main.js │ ├── plugins │ │ └── vuetify.js │ ├── router.js │ ├── scriptCompute │ │ ├── computeAllSchemaFunctionPolicies.js │ │ ├── computeAllSchemaTablePolicies.js │ │ ├── computeFunctionPolicy.js │ │ ├── computeMasterFunctionPolicy.js │ │ ├── computeMasterSecurityPolicy.js │ │ ├── computeMasterTablePolicy.js │ │ ├── computeOwnershipPolicy.js │ │ ├── computeRemoveRls.js │ │ ├── computeRolesSql.js │ │ ├── computeSchemaFunctionPolicy.js │ │ ├── computeSchemaTablePolicy.js │ │ ├── computeSchemaUsageSql.js │ │ ├── computeTablePolicy.js │ │ └── index.js │ ├── store │ │ ├── actions │ │ │ ├── index.js │ │ │ ├── loadFromDisk.js │ │ │ ├── pgdbirc.js │ │ │ ├── resetDefaultState.js │ │ │ ├── setManagedSchemata.js │ │ │ ├── setProjectRoleSet.js │ │ │ └── writeToDisk.js │ │ ├── defaultState.js │ │ ├── mutations │ │ │ ├── assignFunctionPolicy.js │ │ │ ├── assignTablePolicy.js │ │ │ ├── createRlsPolicy.js │ │ │ ├── customizeTablePolicy.js │ │ │ ├── defaultRlsUsing.js │ │ │ ├── defaultRlsWithCheck.js │ │ │ ├── deleteRlsPolicy.js │ │ │ ├── deleteTablePolicy.js │ │ │ ├── evaluate │ │ │ │ ├── evaluateAll.js │ │ │ │ ├── evaluateEnumScripts.js │ │ │ │ ├── evaluateFkIndexes.js │ │ │ │ ├── evaluateGenericIndices.js │ │ │ │ ├── evaluateUdtScripts.js │ │ │ │ ├── evaluateUqIndexes.js │ │ │ │ └── storeEvaluations.js │ │ │ ├── filterSchemata.js │ │ │ ├── importProject.js │ │ │ ├── makeGlobalTablePolicy.js │ │ │ ├── mutations.js │ │ │ ├── newFunctionPolicy.js │ │ │ ├── newPolicy.js │ │ │ ├── projectRoles.js │ │ │ ├── renameTablePolicy.js │ │ │ ├── resetDefaultState.js │ │ │ ├── saveFunctionPolicy.js │ │ │ ├── savePgLintResult.js │ │ │ ├── savePolicy.js │ │ │ ├── selectedRoleFamilies.js │ │ │ ├── setAllRoleSets.js │ │ │ ├── setEnabledRoles.js │ │ │ ├── setExistingRlsPolicies.js │ │ │ ├── setManagedSchemata.js │ │ │ ├── setPgdbiOptions.js │ │ │ ├── setProjectRoleSet.js │ │ │ ├── toggleIgnoreRole.js │ │ │ ├── toggleIndexForDrop.js │ │ │ ├── updateDefaultRlsUsing.js │ │ │ └── updateTablePolicyTemplate.js │ │ ├── store.js │ │ └── templates │ │ │ ├── policyFooterTemplate.js │ │ │ ├── policyHeaderTemplate.js │ │ │ └── roleTableGrantTemplate.js │ ├── views │ │ ├── About.vue │ │ ├── ForeignKeyIndexView.vue │ │ ├── FunctionSecurityView.vue │ │ ├── Home.vue │ │ ├── Initialize.vue │ │ ├── PgLintView.vue │ │ ├── RoleManagerView.vue │ │ ├── SearchView.vue │ │ ├── SecurityScriptsSummaryView.vue │ │ ├── SecurityView.vue │ │ ├── SqitchView.vue │ │ ├── TableSecurityProfileDefinitionView.vue │ │ ├── TableSecurityProfileView.vue │ │ ├── TableSecurityView copy.vue │ │ ├── TableSecurityView-next.vue │ │ ├── TableSecurityView.vue │ │ └── WorkerView.vue │ └── vue-apollo.js │ ├── test │ └── blah.spec.js │ ├── tsconfigs.json │ └── vue.config.js ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", { 5 | "targets": { 6 | "node": "current" 7 | } 8 | } 9 | ], 10 | [ 11 | "@babel/typescript", { 12 | "targets": { 13 | "node": "current" 14 | } 15 | } 16 | ] 17 | ] 18 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # pde-directory 2 | pde-directory 3 | .pgdbi 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | # next.js build output 65 | .next 66 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/devServer/voyager.worker.js 2 | src/pgdbi/dist/ 3 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | singleQuote: true, 4 | }; 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/index.js" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 stlbucket 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/pgdbi/dist/css/app.89ce3cd1.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes shadow-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(182,179,26,.253);box-shadow:0 0 0 0 rgba(182,179,26,.253)}to{-webkit-box-shadow:0 0 0 15px rgba(182,179,26,.253);box-shadow:0 0 0 15px rgba(182,179,26,.253)}}@keyframes shadow-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(182,179,26,.253);box-shadow:0 0 0 0 rgba(182,179,26,.253)}to{-webkit-box-shadow:0 0 0 15px rgba(182,179,26,.253);box-shadow:0 0 0 15px rgba(182,179,26,.253)}}.refreshBtnInitializing{-webkit-animation:shadow-pulse 2s infinite;animation:shadow-pulse 2s infinite}.blah{color:red}.norm-text{text-transform:none!important} -------------------------------------------------------------------------------- /bin/pgdbi/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/bin/pgdbi/dist/favicon.ico -------------------------------------------------------------------------------- /bin/pgdbi/dist/index.html: -------------------------------------------------------------------------------- 1 | pg-db-inspector
-------------------------------------------------------------------------------- /bin/pgdbi/dist/js/about.5bee4903.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{f820:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},s=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"about"},[n("h1",[t._v("This is an about page")])])}],u=n("2877"),c={},i=Object(u["a"])(c,a,s,!1,null,null,null);e["default"]=i.exports}}]); 2 | //# sourceMappingURL=about.5bee4903.js.map -------------------------------------------------------------------------------- /bin/pgdbi/dist/js/about.5bee4903.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///./src/views/About.vue?05f7","webpack:///./src/views/About.vue"],"names":["render","_vm","this","_h","$createElement","_self","_c","_m","staticRenderFns","staticClass","_v","script","component"],"mappings":"8GAAA,IAAIA,EAAS,WAAa,IAAIC,EAAIC,KAASC,EAAGF,EAAIG,eAAsBH,EAAII,MAAMC,GAAO,OAAOL,EAAIM,GAAG,IACnGC,EAAkB,CAAC,WAAa,IAAIP,EAAIC,KAASC,EAAGF,EAAIG,eAAmBE,EAAGL,EAAII,MAAMC,IAAIH,EAAG,OAAOG,EAAG,MAAM,CAACG,YAAY,SAAS,CAACH,EAAG,KAAK,CAACL,EAAIS,GAAG,+B,YCAtJC,EAAS,GAKTC,EAAY,eACdD,EACAX,EACAQ,GACA,EACA,KACA,KACA,MAIa,aAAAI,E","file":"js/about.5bee4903.js","sourcesContent":["var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _vm._m(0)}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"about\"},[_c('h1',[_vm._v(\"This is an about page\")])])}]\n\nexport { render, staticRenderFns }","import { render, staticRenderFns } from \"./About.vue?vue&type=template&id=1ae8a7be&\"\nvar script = {}\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports"],"sourceRoot":""} -------------------------------------------------------------------------------- /bin/pgdbi/dist/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/bin/pgdbi/dist/logo.png -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/introspection.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const pgdbiApp = require('../../index') 3 | 4 | module.exports = build => { 5 | return async (_schema, args, context, resolveInfo) => { 6 | return pgdbiApp.schemaTree() 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/pgdbiOptions.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const pgdbiApp = require('../../index') 3 | 4 | module.exports = build => { 5 | return async (_schema, args, context, resolveInfo) => { 6 | return pgdbiApp.pdgbiOptions() 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/checkConstraint/tableConstraint.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_checkConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _checkConstraint.constraintSchema; 8 | const constraintName = _checkConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/column/keyColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_column, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _column.tableSchema; 8 | const tableName = _column.tableName; 9 | const columnName = _column.columnName; 10 | 11 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 12 | sql.fragment`information_schema.key_column_usage`, 13 | (tableAlias, sqlBuilder) => { 14 | sqlBuilder.where( 15 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 16 | tableSchema, 17 | )}`, 18 | ); 19 | sqlBuilder.where( 20 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 21 | ); 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.column_name = ${sql.value(columnName)}`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/enabledRole/applicableRoles.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_enabledRole, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const roleName = _enabledRole.roleName; 8 | 9 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 10 | sql.fragment`information_schema.applicable_roles`, 11 | (tableAlias, sqlBuilder) => { 12 | sqlBuilder.where( 13 | sql.fragment`${tableAlias}.grantee = ${sql.value(roleName)}`, 14 | ); 15 | }, 16 | ); 17 | 18 | return rows; 19 | } catch (e) { 20 | throw e; 21 | } 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/function/functionById.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const schemaName = args.id.split(':')[1].split('.')[0]; 6 | const functionName = args.id.split(':')[1].split('.')[1]; 7 | 8 | const sql = ` 9 | select 10 | jsonb_build_object( 11 | 'functionById', ( 12 | jsonb_build_object( 13 | 'id', 'function:' || n.nspname || '.' || p.proname 14 | ,'functionName', p.proname 15 | ,'functionSchema', n.nspname 16 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 17 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 18 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 19 | ) 20 | ) 21 | ) 22 | from pg_catalog.pg_proc p 23 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 24 | where n.nspname = '${schemaName}' 25 | and p.proname = '${functionName}' 26 | ; 27 | `; 28 | 29 | const result = await pgClient.query(sql, []); 30 | 31 | return result.rows[0].jsonb_build_object.functionById; 32 | } catch (e) { 33 | throw e; 34 | } 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/function/searchFunctions.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const searchTerm = args.searchTerm; 6 | 7 | const sql = ` 8 | with procs as ( 9 | select 10 | p.oid 11 | ,p.proname 12 | ,n.nspname 13 | from pg_proc p 14 | join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 15 | where lower(p.prosrc) like '%${searchTerm}%' 16 | or lower(p.proname) like '%%${searchTerm}%' 17 | ) 18 | select 19 | jsonb_build_object( 20 | 'searchFunctions', ( 21 | coalesce( 22 | array_agg( 23 | jsonb_build_object( 24 | 'id', 'function:' || p.nspname || '.' || p.proname 25 | ,'functionName', p.proname 26 | ,'functionSchema', p.nspname 27 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 28 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 29 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 30 | ) 31 | ) 32 | ) 33 | ) 34 | ) 35 | from procs p 36 | ; 37 | `; 38 | 39 | const result = await pgClient.query(sql, []); 40 | 41 | return result.rows[0].jsonb_build_object.searchFunctions; 42 | } catch (e) { 43 | throw e; 44 | } 45 | }; 46 | }; 47 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/keyColumnUsage/referentialConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_keyColumnUsage, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _keyColumnUsage.tableSchema; 8 | const constraintName = _keyColumnUsage.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.referential_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/referentialConstraint/referencedColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_referentialConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _referentialConstraint.uniqueConstraintSchema; 8 | const constraintName = _referentialConstraint.uniqueConstraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/referentialConstraint/referencingColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_referentialConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _referentialConstraint.constraintSchema; 8 | const constraintName = _referentialConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/schema/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_schema, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const schemaName = _schema.schemaName; 8 | 9 | return `schema:${schemaName}`; 10 | } catch (e) { 11 | throw e; 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaEnums.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_schema, args, context, resolveInfo) => { 5 | const { pgClient } = context; 6 | try { 7 | const schemaName = _schema.schemaName; 8 | 9 | const sql = ` 10 | select jsonb_build_object( 11 | 'id', 'enum:' || n.nspname || '.' || t.typname 12 | ,'enumName', t.typname 13 | ,'enumSchema', n.nspname 14 | ,'enumValues', ( 15 | with vals as( 16 | select e.enumlabel 17 | from pg_enum e 18 | where e.enumtypid = t.oid 19 | order by e.enumlabel 20 | ) 21 | select array_agg(enumlabel) 22 | from vals 23 | ) 24 | ) 25 | from pg_type t 26 | join pg_catalog.pg_namespace n ON n.oid = t.typnamespace 27 | where t.oid in (select enumtypid from pg_enum) 28 | and n.nspname = '${schemaName}' 29 | group by 30 | n.nspname 31 | ,t.typname 32 | ,t.oid 33 | order by 34 | t.typname 35 | ; 36 | `; 37 | 38 | const result = await pgClient.query(sql, []); 39 | 40 | return result.rows.map(r => { 41 | return r.jsonb_build_object; 42 | }); 43 | } catch (e) { 44 | throw e; 45 | } 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaFunctions.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const sql = ` 8 | select 9 | jsonb_build_object( 10 | 'schemaFunctions', ( 11 | coalesce( 12 | array_agg( 13 | jsonb_build_object( 14 | 'id', 'function:' || n.nspname || '.' || p.proname 15 | ,'functionName', p.proname 16 | ,'functionSchema', n.nspname 17 | ) 18 | ) 19 | , '{}') 20 | ) 21 | ) 22 | from pg_catalog.pg_proc p 23 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 24 | where n.nspname = '${schemaName}' 25 | -- group by p.proname 26 | -- order by p.proname 27 | ; 28 | `; 29 | 30 | const result = await pgClient.query(sql, []); 31 | return result.rows[0].jsonb_build_object.schemaFunctions; 32 | } catch (e) { 33 | console.log('err', e); 34 | throw e; 35 | } 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaTables.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 8 | sql.fragment`information_schema.tables`, 9 | (tableAlias, sqlBuilder) => { 10 | sqlBuilder.where( 11 | sql.fragment`${tableAlias}.table_schema = ${sql.value(schemaName)}`, 12 | ); 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_type = 'BASE TABLE'`, 15 | ); 16 | sqlBuilder.orderBy(() => sql.fragment`table_name`, true); 17 | }, 18 | ); 19 | 20 | return rows; 21 | } catch (e) { 22 | throw e; 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaTreeBySchemaName.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 8 | sql.fragment`information_schema.tables`, 9 | (tableAlias, sqlBuilder) => { 10 | sqlBuilder.where( 11 | sql.fragment`${tableAlias}.table_schema = ${sql.value(schemaName)}`, 12 | ); 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_type = 'BASE TABLE'`, 15 | ); 16 | sqlBuilder.orderBy(() => sql.fragment`table_name`, true); 17 | }, 18 | ); 19 | 20 | return rows; 21 | } catch (e) { 22 | throw e; 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/checkConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.check_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name in ( 20 | SELECT constraint_name 21 | from information_schema.table_constraints 22 | where table_name = ${sql.value(tableName)} 23 | )`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | return `table:${tableSchema}.${tableName}`; 11 | } catch (e) { 12 | throw e; 13 | } 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/indices.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const sql = ` 9 | select 10 | ns.nspname || '.' || t.relname id 11 | ,t.relname "tableName" 12 | ,ns.nspname "tableSchema" 13 | ,a.attname "columnName" 14 | ,i.relname "indexName" 15 | from 16 | pg_index ix 17 | join pg_class t on t.oid = ix.indrelid 18 | join pg_class i on i.oid = ix.indexrelid 19 | join pg_namespace ns on t.relnamespace = ns.oid 20 | join pg_attribute a on a.attrelid = t.oid and a.attnum = ANY(ix.indkey) 21 | where 22 | ns.nspname = '${tableSchema}' 23 | and 24 | t.relname = '${tableName}' 25 | group by 26 | ns.nspname, 27 | t.relname, 28 | a.attname, 29 | i.relname 30 | order by 31 | ns.nspname, 32 | t.relname, 33 | a.attname, 34 | i.relname 35 | ; 36 | `; 37 | 38 | const result = await pgClient.query(sql, []); 39 | return result.rows; 40 | } catch (e) { 41 | throw e; 42 | } 43 | }; 44 | }; 45 | 46 | // select 47 | // jsonb_build_object( 48 | // 'tableIndices', ( 49 | // coalesce( 50 | // array_agg( 51 | // jsonb_build_object( 52 | // 'id', 'index:' || ns.nspname || '.' || t.relname 53 | // ,'tableName', t.relname 54 | // ,'tableSchema', ns.nspname 55 | // ,'columnName', a.attname 56 | // ,'indexName', i.relname 57 | // ) 58 | // ) 59 | // , '{}') 60 | // ) 61 | // ) 62 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/policies.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const sql = ` 9 | select 10 | jsonb_build_object( 11 | 'tablePolicies', ( 12 | coalesce( 13 | array_agg( 14 | jsonb_build_object( 15 | 'schemaName', p.schemaname 16 | ,'tableName', p.tablename 17 | ,'policyName', p.policyname 18 | ,'roles', p.roles 19 | ,'cmd', p.cmd 20 | ,'qual', p.qual 21 | ,'withCheck', p.with_check 22 | ) 23 | ) 24 | , '{}') 25 | ) 26 | ) 27 | FROM pg_policies p 28 | where 29 | p.schemaname = '${tableSchema}' 30 | and 31 | p.tablename = '${tableName}' 32 | ; 33 | `; 34 | 35 | const result = await pgClient.query(sql, []); 36 | return result.rows[0].jsonb_build_object.tablePolicies; 37 | } catch (e) { 38 | throw e; 39 | } 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/primaryKeyConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 18 | tableSchema, 19 | )}`, 20 | ); 21 | 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.constraint_type = ${sql.value( 24 | 'PRIMARY KEY', 25 | )}`, 26 | ); 27 | }, 28 | ); 29 | 30 | return rows; 31 | } catch (e) { 32 | throw e; 33 | } 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/psqlDescription.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | console.log('_table', _table) 6 | const tableSchema = _table.tableSchema; 7 | const tableName = _table.tableName; 8 | 9 | const sql = `\d+ ${tableSchema}.${tableName};`; 10 | console.log('sql', sql) 11 | 12 | const result = await pgClient.query(sql, []); 13 | return result.rows[0].jsonb_build_object.tablePolicies; 14 | } catch (e) { 15 | throw e; 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/referentialConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.referential_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name in ( 20 | SELECT constraint_name 21 | from information_schema.table_constraints 22 | where table_name = ${sql.value(tableName)} 23 | )`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/roleColumnGrants.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.role_column_grants`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 15 | tableSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 20 | ); 21 | }, 22 | ); 23 | 24 | return rows; 25 | } catch (e) { 26 | throw e; 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/roleTableGrants.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.role_table_grants`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 15 | tableSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 20 | ); 21 | sqlBuilder.where(sql.fragment`${tableAlias}.grantee != 'postgres'`); 22 | }, 23 | ); 24 | 25 | return rows; 26 | } catch (e) { 27 | throw e; 28 | } 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableById.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = args.id.split(':')[1].split('.')[0]; 6 | const tableName = args.id.split(':')[1].split('.')[1]; 7 | 8 | // console.log('args', args) 9 | // console.log('tableSchema', tableSchema) 10 | // console.log('tableName', tableName) 11 | 12 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 13 | sql.fragment`information_schema.tables`, 14 | (tableAlias, sqlBuilder) => { 15 | sqlBuilder.where( 16 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 17 | tableSchema, 18 | )}`, 19 | ); 20 | sqlBuilder.where( 21 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows[0]; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableColumns.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.columns`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 18 | ); 19 | }, 20 | ); 21 | 22 | return rows; 23 | } catch (e) { 24 | throw e; 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableConstraints.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.constraint_table_usage`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 18 | ); 19 | }, 20 | ); 21 | 22 | return rows; 23 | } catch (e) { 24 | throw e; 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/triggers.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.triggers`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.event_object_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.event_object_table = ${sql.value( 18 | tableName, 19 | )}`, 20 | ); 21 | }, 22 | ); 23 | 24 | return rows; 25 | } catch (e) { 26 | throw e; 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/table/uniqueConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 18 | tableSchema, 19 | )}`, 20 | ); 21 | 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.constraint_type = ${sql.value( 24 | 'UNIQUE', 25 | )}`, 26 | ); 27 | }, 28 | ); 29 | 30 | return rows; 31 | } catch (e) { 32 | throw e; 33 | } 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/tableConstraint/keyColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_tableConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _tableConstraint.constraintSchema; 8 | const constraintName = _tableConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/trigger/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_trigger, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const eventManipulation = _trigger.eventManipulation; 8 | const eventObjectSchema = _trigger.eventObjectSchema; 9 | const eventObjectTable = _trigger.eventObjectTable; 10 | const actionTiming = _trigger.actionTiming; 11 | 12 | return `trigger:${actionTiming}.${eventManipulation}.${eventObjectSchema}.${eventObjectTable}`; 13 | } catch (e) { 14 | throw e; 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/dbSchema/resolvers/trigger/triggerFunction.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_trigger, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | // assumes action statement of the form: 'EXECUTE PROCEDURE schema_name.function_name()' 6 | const schemaName = _trigger.actionStatement.split(' ')[2].split('.')[0]; 7 | const functionName = _trigger.actionStatement 8 | .split(' ')[2] 9 | .split('.')[1] 10 | .split('(')[0]; 11 | 12 | const sql = ` 13 | select 14 | jsonb_build_object( 15 | 'triggerFunction', ( 16 | jsonb_build_object( 17 | 'id', 'function:' || n.nspname || '.' || p.proname 18 | ,'functionName', p.proname 19 | ,'functionSchema', n.nspname 20 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 21 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 22 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 23 | ) 24 | ) 25 | ) 26 | from pg_catalog.pg_proc p 27 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 28 | where n.nspname = '${schemaName}' 29 | and p.proname = '${functionName}' 30 | ; 31 | `; 32 | // console.log('sql',sql) 33 | const result = await pgClient.query(sql, []); 34 | // console.log('result',result) 35 | return result.rows[0].jsonb_build_object.triggerFunction; 36 | } catch (e) { 37 | throw e; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/execSql.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | 3 | const ExecSqlPlugin = makeExtendSchemaPlugin(build => { 4 | const { pgSql: sql } = build; 5 | return { 6 | typeDefs: gql` 7 | input ExecSqlInput { 8 | clientMutationId: String 9 | sql: String! 10 | } 11 | 12 | type ExecSqlPayload { 13 | sql: String! 14 | result: JSON! 15 | } 16 | 17 | extend type Mutation { 18 | ExecSql(input: ExecSqlInput!): ExecSqlPayload 19 | } 20 | `, 21 | resolvers: { 22 | Mutation: { 23 | ExecSql: async ( 24 | _mutation, 25 | args, 26 | context, 27 | resolveInfo, 28 | { selectGraphQLResultFromTable } 29 | ) => { 30 | const { pgClient } = context; 31 | // Start a sub-transaction 32 | await pgClient.query("SAVEPOINT graphql_mutation"); 33 | try { 34 | 35 | // clog('LET US EXEC SQL', pgClient) 36 | const result = await pgClient.query(args.input.sql, []); 37 | 38 | await pgClient.query("RELEASE SAVEPOINT graphql_mutation"); 39 | 40 | return { 41 | sql: args.input.sql, 42 | result: result 43 | }; 44 | } catch (e) { 45 | // Oh noes! If at first you don't succeed, 46 | // destroy all evidence you ever tried. 47 | await pgClient.query("ROLLBACK TO SAVEPOINT graphql_mutation"); 48 | throw e; 49 | } 50 | }, 51 | }, 52 | }, 53 | }; 54 | }); 55 | 56 | module.exports = ExecSqlPlugin 57 | 58 | 59 | // the above was built from the below 60 | // https://www.graphile.org/postgraphile/make-extend-schema-plugin/ 61 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/pgIntrospectionResultsByKind.js: -------------------------------------------------------------------------------- 1 | module.exports = callback => builder => builder.hook('build', (build) =>{callback(build.pgIntrospectionResultsByKind); return build}) 2 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/pgdbirc-default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | defaultRlsUsing: '( owner_id = viewer_id() )', 3 | allRoleSets: [ 4 | { 5 | name: 'graphile-visitor', 6 | dbOwnerRole: { 7 | roleName: 'app_owner', 8 | applicableRoles: [] 9 | }, 10 | dbAuthenticatorRole: { 11 | roleName: 'app_authenticator', 12 | applicableRoles: [ {roleName: 'app_visitor'}, {roleName: 'app_anonymous'} ] 13 | }, 14 | dbUserRoles: [ 15 | { 16 | roleName: 'app_visitor', 17 | applicableRoles: [ {roleName: 'app_anonymous'} ] 18 | }, 19 | { 20 | roleName: 'app_anonymous', 21 | applicableRoles: [] 22 | } 23 | ], 24 | }, 25 | { 26 | name: 'multi-user', 27 | dbOwnerRole: { 28 | roleName: 'app_owner', 29 | applicableRoles: [] 30 | }, 31 | dbAuthenticatorRole: { 32 | roleName: 'app_authenticator', 33 | applicableRoles: [ {roleName: 'app_super_admin'}, {roleName: 'app_admin'}, {roleName: 'app_user'}, {roleName: 'app_anonymous'} ] 34 | }, 35 | dbUserRoles: [ 36 | { 37 | roleName: 'app_super_admin', 38 | applicableRoles: [ {roleName: 'app_admin'}, {roleName: 'app_user'}, {roleName: 'app_anonymous'} ] 39 | }, 40 | { 41 | roleName: 'app_admin', 42 | applicableRoles: [ {roleName: 'app_user'}, {roleName: 'app_anonymous'} ] 43 | }, 44 | { 45 | roleName: 'app_user', 46 | applicableRoles: [ {roleName: 'app_anonymous'} ] 47 | }, 48 | { 49 | roleName: 'app_anonymous', 50 | applicableRoles: [] 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/pgdbirc.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | const fs = require('fs') 3 | const defaultPgdbirc = require('./pgdbirc-default') 4 | 5 | const PGDBIRCPlugin = makeExtendSchemaPlugin(build => { 6 | const { pgSql: sql } = build; 7 | const pgdbiDir = `${process.cwd()}/.pgdbi` 8 | const pgdbircPath = `${pgdbiDir}/.pgdbirc.json` 9 | 10 | fs.mkdirSync(pgdbiDir, {recursive: true}) 11 | 12 | const exists = fs.existsSync(pgdbircPath) 13 | if (!exists) { 14 | fs.writeFileSync(pgdbircPath, JSON.stringify(defaultPgdbirc,0,2)) 15 | } 16 | 17 | return { 18 | typeDefs: gql` 19 | type PGDBIRCPayload { 20 | pgdbirc: JSON! 21 | } 22 | 23 | extend type Query { 24 | PGDBIRC: PGDBIRCPayload 25 | } 26 | `, 27 | resolvers: { 28 | Query: { 29 | PGDBIRC: async ( 30 | _query, 31 | args, 32 | context, 33 | resolveInfo, 34 | { selectGraphQLResultFromTable } 35 | ) => { 36 | try { 37 | const pgdbirc = fs.readFileSync(pgdbircPath) 38 | 39 | return { 40 | pgdbirc: JSON.parse(pgdbirc) 41 | }; 42 | } catch (e) { 43 | // Oh noes! If at first you don't succeed, 44 | // destroy all evidence you ever tried. 45 | throw e; 46 | } 47 | }, 48 | }, 49 | }, 50 | }; 51 | }); 52 | 53 | module.exports = PGDBIRCPlugin 54 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/pglintrc-default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | project: null, 3 | token: null 4 | } 5 | -------------------------------------------------------------------------------- /bin/pgdbi/graphile-extensions/project.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | const fs = require('fs') 3 | 4 | const PGDBIRCPlugin = makeExtendSchemaPlugin(build => { 5 | const { pgSql: sql } = build; 6 | const pgdbiDir = `${process.cwd()}/.pgdbi` 7 | const projectPath = `${pgdbiDir}/project.json` 8 | 9 | return { 10 | typeDefs: gql` 11 | type ProjectPayload { 12 | project: JSON! 13 | } 14 | 15 | extend type Query { 16 | project: ProjectPayload 17 | } 18 | `, 19 | resolvers: { 20 | Query: { 21 | project: async ( 22 | _query, 23 | args, 24 | context, 25 | resolveInfo, 26 | { selectGraphQLResultFromTable } 27 | ) => { 28 | try { 29 | const exists = fs.existsSync(projectPath) 30 | if (!exists) { 31 | throw new Error('Project file does not exist') 32 | } 33 | 34 | const project = fs.readFileSync(projectPath) 35 | 36 | return { 37 | project: JSON.parse(project) 38 | }; 39 | } catch (e) { 40 | // Oh noes! If at first you don't succeed, 41 | // destroy all evidence you ever tried. 42 | throw e; 43 | } 44 | }, 45 | }, 46 | }, 47 | }; 48 | }); 49 | 50 | module.exports = PGDBIRCPlugin 51 | -------------------------------------------------------------------------------- /bin/pgdbi/transformBuild.js: -------------------------------------------------------------------------------- 1 | const camelCaseKeys = require('camelcase-keys') 2 | const pg10IntrospectionQuery = require('./pg10IntrospectionQuery') 3 | 4 | const queryBuilderMap = { 5 | "10": require('./pg10IntrospectionQuery'), 6 | "11": require('./pg11IntrospectionQuery'), 7 | "12": require('./pg11IntrospectionQuery') 8 | } 9 | 10 | async function transformBuild(build, pgPool) { 11 | try { 12 | const version = (await pgPool.query('SHOW server_version;')).rows[0].server_version.split('.')[0]; 13 | console.log('version', version) 14 | // console.log('build.options', build.options) 15 | const schemas = build.options.pgSchemas.join("','"); 16 | console.log('schemas', schemas) 17 | const querySql = await queryBuilderMap[version](schemas) 18 | const schemaTree = camelCaseKeys((await pgPool.query(querySql)).rows[0], {deep:true}) 19 | return schemaTree 20 | 21 | } catch (e) { 22 | console.log('CAUGHT ERROR', e.toString()) 23 | throw e; 24 | } 25 | } 26 | 27 | module.exports = transformBuild -------------------------------------------------------------------------------- /bin/sql/schema_usage.sql: -------------------------------------------------------------------------------- 1 | WITH "names"("name") AS ( 2 | SELECT n.nspname AS "name" 3 | FROM pg_catalog.pg_namespace n 4 | WHERE n.nspname !~ '^pg_' 5 | AND n.nspname <> 'information_schema' 6 | ) SELECT "name", 7 | pg_catalog.has_schema_privilege(current_user, "name", 'CREATE') AS "create", 8 | pg_catalog.has_schema_privilege(current_user, "name", 'USAGE') AS "usage" 9 | FROM "names"; 10 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf ./src/pgdbi/dist 4 | rm -rf ./bin/pgdbi 5 | 6 | cd ./src/web-vue 7 | yarn build 8 | cd ../.. 9 | cp -R ./src/web-vue/dist ./src/pgdbi/dist/ 10 | cp -R ./src/pgdbi ./bin/pgdbi/ -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./bin/pgdbi'); 2 | -------------------------------------------------------------------------------- /introResult.json: -------------------------------------------------------------------------------- 1 | [object Object] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@graphile-contrib/pgdbi", 3 | "version": "1.0.9-alpha.111", 4 | "main": "index.js", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/graphile-contrib/pgdbi" 8 | }, 9 | "license": "MIT", 10 | "scripts": { 11 | "dev-server": "node -r dotenv/config --inspect src/devServer", 12 | "dev-web-vue": "cd ./src/web-vue && yarn serve", 13 | "prettier:fix": "prettier --write 'src/**/*.{js,md,json}' '*.{js,md,json}'", 14 | "prod-build": "cd ./src/web-vue && yarn build" 15 | }, 16 | "files": [ 17 | "bin/**/*" 18 | ], 19 | "dependencies": { 20 | "@types/jest": "^24.0.16", 21 | "camelcase-keys": "^6.0.1", 22 | "compressed-json": "^1.0.15", 23 | "dotenv": "^8.1.0", 24 | "express": "^4.16.4", 25 | "fbkt-clog": "^1.0.5", 26 | "flatted": "^2.0.1", 27 | "graphile-utils": "^4.2.1", 28 | "graphile-worker": "^0.1.0-alpha.0", 29 | "handlebars": "^4.3.0", 30 | "pglint": "^1.1.0", 31 | "postgraphile": "^4.4.0", 32 | "postgraphile-plugin-connection-filter": "^1.0.1", 33 | "rimraf": "^3.0.2" 34 | }, 35 | "devDependencies": { 36 | "@babel/cli": "^7.4.4", 37 | "@babel/core": "^7.4.5", 38 | "@babel/node": "^7.4.5", 39 | "@babel/preset-env": "^7.4.5", 40 | "@babel/preset-typescript": "^7.3.3", 41 | "babel-jest": "^24.8.0", 42 | "jest": "^24.8.0", 43 | "nodemon": "^1.19.1", 44 | "typescript": "^3.5.2" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pglint-bash.sh: -------------------------------------------------------------------------------- 1 | bash pglint.sh "0dc056d563216b428314add7" "stlbucket/pgdbi-try" "postgres://postgres:1234@0.0.0.0/lcb" -------------------------------------------------------------------------------- /pglint-npx.sh: -------------------------------------------------------------------------------- 1 | npx pglint --token "0dc056d563216b428314add7" --project "stlbucket/pgdbi-try" --connection "postgres://postgres:1234@0.0.0.0/lcb" -------------------------------------------------------------------------------- /project.md: -------------------------------------------------------------------------------- 1 | ### phase the now 2 | 3 | - [X] upgrade to latest vuetify 2 4 | - [X] hopefully vuetify 2 fixes the panel expansion problem 5 | - [X] update search page to do front-end search 6 | - [X] improve UI feedback during schema refresh 7 | - [ ] build new table detail: https://github.com/graphile-contrib/pgdbi/issues/8 8 | - [ ] add ignore role feature 9 | - [ ] rethink tools menu, move away from top level buttons 10 | - [ ] refactor store structure for modular rule management 11 | - [ ] improve the build/publish process 12 | 13 | ### phase the next 14 | 15 | - [ ] add enums/types browser 16 | - [ ] implement index page 17 | - [ ] settings page 18 | - [ ] function component needs to be spiffed up 19 | - [ ] finish policy evaluation components 20 | - [ ] create by-policy view: basically a pivot on policy assignment 21 | - [ ] make a better color scheme. maybe something close to: https://www.graphile.org 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # @graphile-contrib/pgdbi 2 | 3 | ## Installation 4 | 5 | ``` 6 | yarn add @graphile-contrib/pgdbi 7 | ``` 8 | 9 | ## Usage 10 | 11 | Currently recommended for development only; to disable in production, do not 12 | load this plugin. 13 | 14 | This is a [PostGraphile Server Plugin](https://www.graphile.org/postgraphile/plugins/) so you can follow the standard server plugin instructions, namely: 15 | 16 | For the CLI, use `--plugins` to load the plugin (and remember this flag must come at the very start!) 17 | 18 | ``` 19 | postgraphile --plugins @graphile-contrib/pgdbis -c my_db 20 | ``` 21 | 22 | For PostGraphile as a library/middleware, you must use the plugin hook functionality: 23 | 24 | ```js 25 | const pgdbi = require('@graphile-contrib/pgdbi'); 26 | const { postgraphile, makePluginHook } = require('postgraphile'); 27 | 28 | const pluginHook = makePluginHook([ 29 | pgdbi, 30 | /* other server plugins can be added here */ 31 | ]); 32 | 33 | app.use( 34 | postgraphile(connectionString, schemas, { 35 | pluginHook, 36 | }), 37 | ); 38 | ``` 39 | 40 | You can access pgdbi at the `/pgdbi` sub path, e.g. [http://localhost:5000/pgdbi](http://localhost:5000/pgdbi). 41 | -------------------------------------------------------------------------------- /src/dbDev/constraints.sql: -------------------------------------------------------------------------------- 1 | select 2 | c.* 3 | ,'unique_constraint' __typename 4 | -- ,s.schema_name || '.' || t.table_name || '.' || c.constraint_name id 5 | ,( 6 | select (array_to_json(array_agg(row_to_json(kcu))))::jsonb 7 | from ( 8 | select 9 | kcu.* 10 | from information_schema.key_column_usage kcu 11 | where kcu.constraint_schema = c.constraint_schema 12 | and kcu.constraint_name = c.constraint_name 13 | ) kcu 14 | ) key_column_usage 15 | ,pg_get_constraintdef(pgc.oid) constraint_definition 16 | from information_schema.table_constraints c 17 | join pg_catalog.pg_constraint pgc on pgc.conname = c.constraint_name 18 | -- join pg_catalog.pg_namespace pgn on pgn.nspname = 'pgdbi_dev' 19 | -- join pg_catalog.pg_class tbl on tbl.relnamespace = pgn.oid and tbl.relname = 'contrived_sink_reference' 20 | where c.table_schema = 'pgdbi_dev' 21 | and c.table_name = 'contrived_sink_reference' 22 | and c.constraint_type = 'UNIQUE' 23 | ; 24 | 25 | select oid, relname from pg_class where relname = 'contrived_sink_reference'; 26 | 27 | select pg_get_tabledef(574884); -------------------------------------------------------------------------------- /src/dbDev/execute.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo -d pg_phile_starter -h 0.0.0.0 3 | echo script: $1 4 | psql -U postgres -f $1 -d pg_phile_starter -h 0.0.0.0 5 | -------------------------------------------------------------------------------- /src/dbDev/functions.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'function' __typename 3 | ,'public' || '.' || p.proname || '--' || replace(replace(coalesce(pg_catalog.pg_get_function_identity_arguments(p.oid), 'N/A'),', ','_'),' ',':') id 4 | ,p.proname function_name 5 | ,n.nspname function_schema 6 | -- ,coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') result_data_type 7 | -- ,coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') argument_data_types 8 | -- ,coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') definition 9 | from pg_catalog.pg_proc p 10 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 11 | where n.nspname = 'public' 12 | and p.proisagg = false 13 | order by p.proname 14 | -------------------------------------------------------------------------------- /src/dbDev/inheritance.sql: -------------------------------------------------------------------------------- 1 | 2 | ALTER TABLE tunz.band_member ADD CONSTRAINT fk_band_member_contact FOREIGN KEY ( musician_id ) REFERENCES org.contact( id ); 3 | -------------------------------------------------------------------------------- /src/devServer/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { 4 | PORT = 3000, 5 | } = process.env; 6 | 7 | const port = PORT; 8 | const app = express(); 9 | const phile = require('./phile') 10 | 11 | app.use(phile); 12 | 13 | const server = app.listen(port); 14 | 15 | /* 16 | * When being used in nodemon, SIGUSR2 is issued to restart the process. We 17 | * listen for this and shut down cleanly. 18 | */ 19 | process.once('SIGUSR2', function() { 20 | server.close(); 21 | const t = setTimeout(function() { 22 | process.kill(process.pid, 'SIGUSR2'); 23 | }, 200); 24 | // Don't prevent clean shutdown: 25 | t.unref(); 26 | }); 27 | 28 | console.log(`listening on http://localhost:${port}/graphiql`); -------------------------------------------------------------------------------- /src/devServer/phile.js: -------------------------------------------------------------------------------- 1 | try { 2 | require('./.env'); 3 | } catch (e) { 4 | // No envvars 🤷 5 | } 6 | const { postgraphile, makePluginHook } = require('postgraphile'); 7 | 8 | const plugins = [ 9 | // require('postgraphile-plugin-connection-filter'), 10 | ]; 11 | 12 | const isProd = process.env.NODE_ENV === 'production'; 13 | 14 | const { 15 | POSTGRES_CONNECTION, 16 | POSTGRAPHILE_SCHEMAS = 'public', 17 | DYNAMIC_JSON = 'true', 18 | DISABLE_DEFAULT_MUTATIONS = null, 19 | WATCH_PG = isProd ? null : 'true', 20 | ENABLE_PGDBI = isProd ? null : 'true', 21 | } = process.env; 22 | 23 | if (!POSTGRES_CONNECTION) { 24 | throw new Error( 25 | "No 'POSTGRES_CONNECTION' envvar found, we don't know which database to connect to.", 26 | ); 27 | } 28 | console.log('POSTGRES_CONNECTION', POSTGRES_CONNECTION) 29 | const identity = _ => _; 30 | 31 | const connection = POSTGRES_CONNECTION; 32 | const schemas = POSTGRAPHILE_SCHEMAS.split(','); 33 | const dynamicJson = DYNAMIC_JSON === 'true'; 34 | const disableDefaultMutations = DISABLE_DEFAULT_MUTATIONS === 'true'; 35 | const watchPg = WATCH_PG === 'true'; 36 | const enablePgdbi = ENABLE_PGDBI === 'true'; 37 | 38 | const pluginHook = makePluginHook( 39 | [enablePgdbi ? require('../pgdbi') : null].filter(identity), 40 | ); 41 | 42 | const phile = postgraphile(connection, schemas, { 43 | pluginHook, 44 | dynamicJson: dynamicJson, 45 | showErrorStack: true, 46 | extendedErrors: [ 47 | 'severity', 48 | 'code', 49 | 'detail', 50 | 'hint', 51 | 'positon', 52 | 'internalPosition', 53 | 'internalQuery', 54 | 'where', 55 | 'schema', 56 | 'table', 57 | 'column', 58 | 'dataType', 59 | 'constraint', 60 | 'file', 61 | 'line', 62 | 'routine', 63 | ], 64 | disableDefaultMutations: disableDefaultMutations, 65 | appendPlugins: plugins, 66 | watchPg: watchPg, 67 | graphiql: true, 68 | pgdbi: { 69 | enableSqitch: false, 70 | enableGraphileWorker: false 71 | } 72 | }) 73 | 74 | module.exports = phile -------------------------------------------------------------------------------- /src/devServer/sqitch.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | host = 0.0.0.0 4 | # plan_file = sqitch.plan 5 | # top_dir = . 6 | # [engine "pg"] 7 | # target = db:pg: 8 | # registry = sqitch 9 | # client = psql 10 | [deploy] 11 | verify = false 12 | [target "phile"] 13 | uri = db:pg:phile_test 14 | [engine "pg"] 15 | target = phile_test 16 | [target "phile_test"] 17 | uri = db:pg:phile_test 18 | -------------------------------------------------------------------------------- /src/devServer/tasks/testTask.js: -------------------------------------------------------------------------------- 1 | // tasks/testTask.js 2 | module.exports = async (payload, { debug }) => { 3 | // async is optional, but best practice 4 | debug(`Received ${JSON.stringify(payload)}`); 5 | }; 6 | -------------------------------------------------------------------------------- /src/devServer/worker.js: -------------------------------------------------------------------------------- 1 | const { Pool } = require("pg"); 2 | const { run } = require("graphile-worker"); 3 | 4 | const pgPool = new Pool({ 5 | connectionString: "postgres://postgres:1234@0.0.0.0/pg_phile_starter", 6 | }); 7 | 8 | async function main() { 9 | const runner = await run({ 10 | pgPool, 11 | // or: connectionString: process.env.DATABASE_URL, 12 | 13 | concurrency: 1, 14 | pollInterval: 2000, 15 | 16 | taskList: { 17 | testTask: async (payload, { debug }) => { 18 | console.log(`Received ${JSON.stringify(payload)}`); 19 | throw new Error('bad things, man') 20 | }, 21 | }, 22 | // or: taskDirectory: `${__dirname}/tasks`, 23 | }); 24 | // to clean up: runner.stop() 25 | } 26 | 27 | main().catch(err => { 28 | console.error(err); 29 | process.exit(1); 30 | }); 31 | -------------------------------------------------------------------------------- /src/pgdbi/dist/css/app.89ce3cd1.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes shadow-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(182,179,26,.253);box-shadow:0 0 0 0 rgba(182,179,26,.253)}to{-webkit-box-shadow:0 0 0 15px rgba(182,179,26,.253);box-shadow:0 0 0 15px rgba(182,179,26,.253)}}@keyframes shadow-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(182,179,26,.253);box-shadow:0 0 0 0 rgba(182,179,26,.253)}to{-webkit-box-shadow:0 0 0 15px rgba(182,179,26,.253);box-shadow:0 0 0 15px rgba(182,179,26,.253)}}.refreshBtnInitializing{-webkit-animation:shadow-pulse 2s infinite;animation:shadow-pulse 2s infinite}.blah{color:red}.norm-text{text-transform:none!important} -------------------------------------------------------------------------------- /src/pgdbi/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/src/pgdbi/dist/favicon.ico -------------------------------------------------------------------------------- /src/pgdbi/dist/index.html: -------------------------------------------------------------------------------- 1 | pg-db-inspector
-------------------------------------------------------------------------------- /src/pgdbi/dist/js/about.5bee4903.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{f820:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},s=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"about"},[n("h1",[t._v("This is an about page")])])}],u=n("2877"),c={},i=Object(u["a"])(c,a,s,!1,null,null,null);e["default"]=i.exports}}]); 2 | //# sourceMappingURL=about.5bee4903.js.map -------------------------------------------------------------------------------- /src/pgdbi/dist/js/about.5bee4903.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///./src/views/About.vue?05f7","webpack:///./src/views/About.vue"],"names":["render","_vm","this","_h","$createElement","_self","_c","_m","staticRenderFns","staticClass","_v","script","component"],"mappings":"8GAAA,IAAIA,EAAS,WAAa,IAAIC,EAAIC,KAASC,EAAGF,EAAIG,eAAsBH,EAAII,MAAMC,GAAO,OAAOL,EAAIM,GAAG,IACnGC,EAAkB,CAAC,WAAa,IAAIP,EAAIC,KAASC,EAAGF,EAAIG,eAAmBE,EAAGL,EAAII,MAAMC,IAAIH,EAAG,OAAOG,EAAG,MAAM,CAACG,YAAY,SAAS,CAACH,EAAG,KAAK,CAACL,EAAIS,GAAG,+B,YCAtJC,EAAS,GAKTC,EAAY,eACdD,EACAX,EACAQ,GACA,EACA,KACA,KACA,MAIa,aAAAI,E","file":"js/about.5bee4903.js","sourcesContent":["var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _vm._m(0)}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"about\"},[_c('h1',[_vm._v(\"This is an about page\")])])}]\n\nexport { render, staticRenderFns }","import { render, staticRenderFns } from \"./About.vue?vue&type=template&id=1ae8a7be&\"\nvar script = {}\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports"],"sourceRoot":""} -------------------------------------------------------------------------------- /src/pgdbi/dist/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/src/pgdbi/dist/logo.png -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/introspection.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const pgdbiApp = require('../../index') 3 | 4 | module.exports = build => { 5 | return async (_schema, args, context, resolveInfo) => { 6 | return pgdbiApp.schemaTree() 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/pgdbiOptions.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | const pgdbiApp = require('../../index') 3 | 4 | module.exports = build => { 5 | return async (_schema, args, context, resolveInfo) => { 6 | return pgdbiApp.pdgbiOptions() 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/checkConstraint/tableConstraint.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_checkConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _checkConstraint.constraintSchema; 8 | const constraintName = _checkConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/column/keyColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_column, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _column.tableSchema; 8 | const tableName = _column.tableName; 9 | const columnName = _column.columnName; 10 | 11 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 12 | sql.fragment`information_schema.key_column_usage`, 13 | (tableAlias, sqlBuilder) => { 14 | sqlBuilder.where( 15 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 16 | tableSchema, 17 | )}`, 18 | ); 19 | sqlBuilder.where( 20 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 21 | ); 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.column_name = ${sql.value(columnName)}`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/enabledRole/applicableRoles.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_enabledRole, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const roleName = _enabledRole.roleName; 8 | 9 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 10 | sql.fragment`information_schema.applicable_roles`, 11 | (tableAlias, sqlBuilder) => { 12 | sqlBuilder.where( 13 | sql.fragment`${tableAlias}.grantee = ${sql.value(roleName)}`, 14 | ); 15 | }, 16 | ); 17 | 18 | return rows; 19 | } catch (e) { 20 | throw e; 21 | } 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/function/functionById.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const schemaName = args.id.split(':')[1].split('.')[0]; 6 | const functionName = args.id.split(':')[1].split('.')[1]; 7 | 8 | const sql = ` 9 | select 10 | jsonb_build_object( 11 | 'functionById', ( 12 | jsonb_build_object( 13 | 'id', 'function:' || n.nspname || '.' || p.proname 14 | ,'functionName', p.proname 15 | ,'functionSchema', n.nspname 16 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 17 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 18 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 19 | ) 20 | ) 21 | ) 22 | from pg_catalog.pg_proc p 23 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 24 | where n.nspname = '${schemaName}' 25 | and p.proname = '${functionName}' 26 | ; 27 | `; 28 | 29 | const result = await pgClient.query(sql, []); 30 | 31 | return result.rows[0].jsonb_build_object.functionById; 32 | } catch (e) { 33 | throw e; 34 | } 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/function/searchFunctions.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const searchTerm = args.searchTerm; 6 | 7 | const sql = ` 8 | with procs as ( 9 | select 10 | p.oid 11 | ,p.proname 12 | ,n.nspname 13 | from pg_proc p 14 | join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 15 | where lower(p.prosrc) like '%${searchTerm}%' 16 | or lower(p.proname) like '%%${searchTerm}%' 17 | ) 18 | select 19 | jsonb_build_object( 20 | 'searchFunctions', ( 21 | coalesce( 22 | array_agg( 23 | jsonb_build_object( 24 | 'id', 'function:' || p.nspname || '.' || p.proname 25 | ,'functionName', p.proname 26 | ,'functionSchema', p.nspname 27 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 28 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 29 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 30 | ) 31 | ) 32 | ) 33 | ) 34 | ) 35 | from procs p 36 | ; 37 | `; 38 | 39 | const result = await pgClient.query(sql, []); 40 | 41 | return result.rows[0].jsonb_build_object.searchFunctions; 42 | } catch (e) { 43 | throw e; 44 | } 45 | }; 46 | }; 47 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/keyColumnUsage/referentialConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_keyColumnUsage, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _keyColumnUsage.tableSchema; 8 | const constraintName = _keyColumnUsage.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.referential_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/referentialConstraint/referencedColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_referentialConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _referentialConstraint.uniqueConstraintSchema; 8 | const constraintName = _referentialConstraint.uniqueConstraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/referentialConstraint/referencingColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_referentialConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _referentialConstraint.constraintSchema; 8 | const constraintName = _referentialConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/schema/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_schema, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const schemaName = _schema.schemaName; 8 | 9 | return `schema:${schemaName}`; 10 | } catch (e) { 11 | throw e; 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaEnums.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_schema, args, context, resolveInfo) => { 5 | const { pgClient } = context; 6 | try { 7 | const schemaName = _schema.schemaName; 8 | 9 | const sql = ` 10 | select jsonb_build_object( 11 | 'id', 'enum:' || n.nspname || '.' || t.typname 12 | ,'enumName', t.typname 13 | ,'enumSchema', n.nspname 14 | ,'enumValues', ( 15 | with vals as( 16 | select e.enumlabel 17 | from pg_enum e 18 | where e.enumtypid = t.oid 19 | order by e.enumlabel 20 | ) 21 | select array_agg(enumlabel) 22 | from vals 23 | ) 24 | ) 25 | from pg_type t 26 | join pg_catalog.pg_namespace n ON n.oid = t.typnamespace 27 | where t.oid in (select enumtypid from pg_enum) 28 | and n.nspname = '${schemaName}' 29 | group by 30 | n.nspname 31 | ,t.typname 32 | ,t.oid 33 | order by 34 | t.typname 35 | ; 36 | `; 37 | 38 | const result = await pgClient.query(sql, []); 39 | 40 | return result.rows.map(r => { 41 | return r.jsonb_build_object; 42 | }); 43 | } catch (e) { 44 | throw e; 45 | } 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaFunctions.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const sql = ` 8 | select 9 | jsonb_build_object( 10 | 'schemaFunctions', ( 11 | coalesce( 12 | array_agg( 13 | jsonb_build_object( 14 | 'id', 'function:' || n.nspname || '.' || p.proname 15 | ,'functionName', p.proname 16 | ,'functionSchema', n.nspname 17 | ) 18 | ) 19 | , '{}') 20 | ) 21 | ) 22 | from pg_catalog.pg_proc p 23 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 24 | where n.nspname = '${schemaName}' 25 | -- group by p.proname 26 | -- order by p.proname 27 | ; 28 | `; 29 | 30 | const result = await pgClient.query(sql, []); 31 | return result.rows[0].jsonb_build_object.schemaFunctions; 32 | } catch (e) { 33 | console.log('err', e); 34 | throw e; 35 | } 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaTables.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 8 | sql.fragment`information_schema.tables`, 9 | (tableAlias, sqlBuilder) => { 10 | sqlBuilder.where( 11 | sql.fragment`${tableAlias}.table_schema = ${sql.value(schemaName)}`, 12 | ); 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_type = 'BASE TABLE'`, 15 | ); 16 | sqlBuilder.orderBy(() => sql.fragment`table_name`, true); 17 | }, 18 | ); 19 | 20 | return rows; 21 | } catch (e) { 22 | throw e; 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/schema/schemaTreeBySchemaName.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const schemaName = _schema.schemaName; 6 | 7 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 8 | sql.fragment`information_schema.tables`, 9 | (tableAlias, sqlBuilder) => { 10 | sqlBuilder.where( 11 | sql.fragment`${tableAlias}.table_schema = ${sql.value(schemaName)}`, 12 | ); 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_type = 'BASE TABLE'`, 15 | ); 16 | sqlBuilder.orderBy(() => sql.fragment`table_name`, true); 17 | }, 18 | ); 19 | 20 | return rows; 21 | } catch (e) { 22 | throw e; 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/checkConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.check_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name in ( 20 | SELECT constraint_name 21 | from information_schema.table_constraints 22 | where table_name = ${sql.value(tableName)} 23 | )`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | return `table:${tableSchema}.${tableName}`; 11 | } catch (e) { 12 | throw e; 13 | } 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/indices.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const sql = ` 9 | select 10 | ns.nspname || '.' || t.relname id 11 | ,t.relname "tableName" 12 | ,ns.nspname "tableSchema" 13 | ,a.attname "columnName" 14 | ,i.relname "indexName" 15 | from 16 | pg_index ix 17 | join pg_class t on t.oid = ix.indrelid 18 | join pg_class i on i.oid = ix.indexrelid 19 | join pg_namespace ns on t.relnamespace = ns.oid 20 | join pg_attribute a on a.attrelid = t.oid and a.attnum = ANY(ix.indkey) 21 | where 22 | ns.nspname = '${tableSchema}' 23 | and 24 | t.relname = '${tableName}' 25 | group by 26 | ns.nspname, 27 | t.relname, 28 | a.attname, 29 | i.relname 30 | order by 31 | ns.nspname, 32 | t.relname, 33 | a.attname, 34 | i.relname 35 | ; 36 | `; 37 | 38 | const result = await pgClient.query(sql, []); 39 | return result.rows; 40 | } catch (e) { 41 | throw e; 42 | } 43 | }; 44 | }; 45 | 46 | // select 47 | // jsonb_build_object( 48 | // 'tableIndices', ( 49 | // coalesce( 50 | // array_agg( 51 | // jsonb_build_object( 52 | // 'id', 'index:' || ns.nspname || '.' || t.relname 53 | // ,'tableName', t.relname 54 | // ,'tableSchema', ns.nspname 55 | // ,'columnName', a.attname 56 | // ,'indexName', i.relname 57 | // ) 58 | // ) 59 | // , '{}') 60 | // ) 61 | // ) 62 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/policies.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const sql = ` 9 | select 10 | jsonb_build_object( 11 | 'tablePolicies', ( 12 | coalesce( 13 | array_agg( 14 | jsonb_build_object( 15 | 'schemaName', p.schemaname 16 | ,'tableName', p.tablename 17 | ,'policyName', p.policyname 18 | ,'roles', p.roles 19 | ,'cmd', p.cmd 20 | ,'qual', p.qual 21 | ,'withCheck', p.with_check 22 | ) 23 | ) 24 | , '{}') 25 | ) 26 | ) 27 | FROM pg_policies p 28 | where 29 | p.schemaname = '${tableSchema}' 30 | and 31 | p.tablename = '${tableName}' 32 | ; 33 | `; 34 | 35 | const result = await pgClient.query(sql, []); 36 | return result.rows[0].jsonb_build_object.tablePolicies; 37 | } catch (e) { 38 | throw e; 39 | } 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/primaryKeyConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 18 | tableSchema, 19 | )}`, 20 | ); 21 | 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.constraint_type = ${sql.value( 24 | 'PRIMARY KEY', 25 | )}`, 26 | ); 27 | }, 28 | ); 29 | 30 | return rows; 31 | } catch (e) { 32 | throw e; 33 | } 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/psqlDescription.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | console.log('_table', _table) 6 | const tableSchema = _table.tableSchema; 7 | const tableName = _table.tableName; 8 | 9 | const sql = `\d+ ${tableSchema}.${tableName};`; 10 | console.log('sql', sql) 11 | 12 | const result = await pgClient.query(sql, []); 13 | return result.rows[0].jsonb_build_object.tablePolicies; 14 | } catch (e) { 15 | throw e; 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/referentialConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.referential_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name in ( 20 | SELECT constraint_name 21 | from information_schema.table_constraints 22 | where table_name = ${sql.value(tableName)} 23 | )`, 24 | ); 25 | }, 26 | ); 27 | 28 | return rows; 29 | } catch (e) { 30 | throw e; 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/roleColumnGrants.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.role_column_grants`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 15 | tableSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 20 | ); 21 | }, 22 | ); 23 | 24 | return rows; 25 | } catch (e) { 26 | throw e; 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/roleTableGrants.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.role_table_grants`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 15 | tableSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 20 | ); 21 | sqlBuilder.where(sql.fragment`${tableAlias}.grantee != 'postgres'`); 22 | }, 23 | ); 24 | 25 | return rows; 26 | } catch (e) { 27 | throw e; 28 | } 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableById.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_schema, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = args.id.split(':')[1].split('.')[0]; 6 | const tableName = args.id.split(':')[1].split('.')[1]; 7 | 8 | // console.log('args', args) 9 | // console.log('tableSchema', tableSchema) 10 | // console.log('tableName', tableName) 11 | 12 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 13 | sql.fragment`information_schema.tables`, 14 | (tableAlias, sqlBuilder) => { 15 | sqlBuilder.where( 16 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 17 | tableSchema, 18 | )}`, 19 | ); 20 | sqlBuilder.where( 21 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows[0]; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableColumns.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.columns`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 18 | ); 19 | }, 20 | ); 21 | 22 | return rows; 23 | } catch (e) { 24 | throw e; 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/tableConstraints.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.constraint_table_usage`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 18 | ); 19 | }, 20 | ); 21 | 22 | return rows; 23 | } catch (e) { 24 | throw e; 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/triggers.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_table, args, context, resolveInfo) => { 3 | const { pgSql: sql } = build; 4 | try { 5 | const tableSchema = _table.tableSchema; 6 | const tableName = _table.tableName; 7 | 8 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 9 | sql.fragment`information_schema.triggers`, 10 | (tableAlias, sqlBuilder) => { 11 | sqlBuilder.where( 12 | sql.fragment`${tableAlias}.event_object_schema = ${sql.value( 13 | tableSchema, 14 | )}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.event_object_table = ${sql.value( 18 | tableName, 19 | )}`, 20 | ); 21 | }, 22 | ); 23 | 24 | return rows; 25 | } catch (e) { 26 | throw e; 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/table/uniqueConstraints.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_table, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const tableSchema = _table.tableSchema; 8 | const tableName = _table.tableName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.table_constraints`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.table_name = ${sql.value(tableName)}`, 15 | ); 16 | sqlBuilder.where( 17 | sql.fragment`${tableAlias}.table_schema = ${sql.value( 18 | tableSchema, 19 | )}`, 20 | ); 21 | 22 | sqlBuilder.where( 23 | sql.fragment`${tableAlias}.constraint_type = ${sql.value( 24 | 'UNIQUE', 25 | )}`, 26 | ); 27 | }, 28 | ); 29 | 30 | return rows; 31 | } catch (e) { 32 | throw e; 33 | } 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/tableConstraint/keyColumnUsage.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_tableConstraint, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const constraintSchema = _tableConstraint.constraintSchema; 8 | const constraintName = _tableConstraint.constraintName; 9 | 10 | const rows = await resolveInfo.graphile.selectGraphQLResultFromTable( 11 | sql.fragment`information_schema.key_column_usage`, 12 | (tableAlias, sqlBuilder) => { 13 | sqlBuilder.where( 14 | sql.fragment`${tableAlias}.constraint_schema = ${sql.value( 15 | constraintSchema, 16 | )}`, 17 | ); 18 | sqlBuilder.where( 19 | sql.fragment`${tableAlias}.constraint_name = ${sql.value( 20 | constraintName, 21 | )}`, 22 | ); 23 | }, 24 | ); 25 | 26 | return rows; 27 | } catch (e) { 28 | throw e; 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/trigger/id.js: -------------------------------------------------------------------------------- 1 | const clog = require('fbkt-clog'); 2 | 3 | module.exports = build => { 4 | return async (_trigger, args, context, resolveInfo) => { 5 | const { pgSql: sql } = build; 6 | try { 7 | const eventManipulation = _trigger.eventManipulation; 8 | const eventObjectSchema = _trigger.eventObjectSchema; 9 | const eventObjectTable = _trigger.eventObjectTable; 10 | const actionTiming = _trigger.actionTiming; 11 | 12 | return `trigger:${actionTiming}.${eventManipulation}.${eventObjectSchema}.${eventObjectTable}`; 13 | } catch (e) { 14 | throw e; 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/dbSchema/resolvers/trigger/triggerFunction.js: -------------------------------------------------------------------------------- 1 | module.exports = build => { 2 | return async (_trigger, args, context, resolveInfo) => { 3 | const { pgClient } = context; 4 | try { 5 | // assumes action statement of the form: 'EXECUTE PROCEDURE schema_name.function_name()' 6 | const schemaName = _trigger.actionStatement.split(' ')[2].split('.')[0]; 7 | const functionName = _trigger.actionStatement 8 | .split(' ')[2] 9 | .split('.')[1] 10 | .split('(')[0]; 11 | 12 | const sql = ` 13 | select 14 | jsonb_build_object( 15 | 'triggerFunction', ( 16 | jsonb_build_object( 17 | 'id', 'function:' || n.nspname || '.' || p.proname 18 | ,'functionName', p.proname 19 | ,'functionSchema', n.nspname 20 | ,'resultDataType', coalesce(pg_catalog.pg_get_function_result(p.oid), 'N/A') 21 | ,'argumentDataTypes', coalesce(pg_catalog.pg_get_function_arguments(p.oid), 'N/A') 22 | ,'definition', coalesce(pg_catalog.pg_get_functiondef(p.oid)::text, 'N/A') 23 | ) 24 | ) 25 | ) 26 | from pg_catalog.pg_proc p 27 | left join pg_catalog.pg_namespace n ON n.oid = p.pronamespace 28 | where n.nspname = '${schemaName}' 29 | and p.proname = '${functionName}' 30 | ; 31 | `; 32 | // console.log('sql',sql) 33 | const result = await pgClient.query(sql, []); 34 | // console.log('result',result) 35 | return result.rows[0].jsonb_build_object.triggerFunction; 36 | } catch (e) { 37 | throw e; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/execSql.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | 3 | const ExecSqlPlugin = makeExtendSchemaPlugin(build => { 4 | const { pgSql: sql } = build; 5 | return { 6 | typeDefs: gql` 7 | input ExecSqlInput { 8 | clientMutationId: String 9 | sql: String! 10 | } 11 | 12 | type ExecSqlPayload { 13 | sql: String! 14 | result: JSON! 15 | } 16 | 17 | extend type Mutation { 18 | ExecSql(input: ExecSqlInput!): ExecSqlPayload 19 | } 20 | `, 21 | resolvers: { 22 | Mutation: { 23 | ExecSql: async ( 24 | _mutation, 25 | args, 26 | context, 27 | resolveInfo, 28 | { selectGraphQLResultFromTable } 29 | ) => { 30 | const { pgClient } = context; 31 | // Start a sub-transaction 32 | await pgClient.query("SAVEPOINT graphql_mutation"); 33 | try { 34 | 35 | // clog('LET US EXEC SQL', pgClient) 36 | const result = await pgClient.query(args.input.sql, []); 37 | 38 | await pgClient.query("RELEASE SAVEPOINT graphql_mutation"); 39 | 40 | return { 41 | sql: args.input.sql, 42 | result: result 43 | }; 44 | } catch (e) { 45 | // Oh noes! If at first you don't succeed, 46 | // destroy all evidence you ever tried. 47 | await pgClient.query("ROLLBACK TO SAVEPOINT graphql_mutation"); 48 | throw e; 49 | } 50 | }, 51 | }, 52 | }, 53 | }; 54 | }); 55 | 56 | module.exports = ExecSqlPlugin 57 | 58 | 59 | // the above was built from the below 60 | // https://www.graphile.org/postgraphile/make-extend-schema-plugin/ 61 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/pgIntrospectionResultsByKind.js: -------------------------------------------------------------------------------- 1 | module.exports = callback => builder => builder.hook('build', (build) =>{callback(build.pgIntrospectionResultsByKind); return build}) 2 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/pgdbirc.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | const fs = require('fs') 3 | const defaultPgdbirc = require('./pgdbirc-default') 4 | 5 | const PGDBIRCPlugin = makeExtendSchemaPlugin(build => { 6 | const { pgSql: sql } = build; 7 | const pgdbiDir = `${process.cwd()}/.pgdbi` 8 | const pgdbircPath = `${pgdbiDir}/.pgdbirc.json` 9 | 10 | fs.mkdirSync(pgdbiDir, {recursive: true}) 11 | 12 | const exists = fs.existsSync(pgdbircPath) 13 | if (!exists) { 14 | fs.writeFileSync(pgdbircPath, JSON.stringify(defaultPgdbirc,0,2)) 15 | } 16 | 17 | return { 18 | typeDefs: gql` 19 | type PGDBIRCPayload { 20 | pgdbirc: JSON! 21 | } 22 | 23 | extend type Query { 24 | PGDBIRC: PGDBIRCPayload 25 | } 26 | `, 27 | resolvers: { 28 | Query: { 29 | PGDBIRC: async ( 30 | _query, 31 | args, 32 | context, 33 | resolveInfo, 34 | { selectGraphQLResultFromTable } 35 | ) => { 36 | try { 37 | const pgdbirc = fs.readFileSync(pgdbircPath) 38 | 39 | return { 40 | pgdbirc: JSON.parse(pgdbirc) 41 | }; 42 | } catch (e) { 43 | // Oh noes! If at first you don't succeed, 44 | // destroy all evidence you ever tried. 45 | throw e; 46 | } 47 | }, 48 | }, 49 | }, 50 | }; 51 | }); 52 | 53 | module.exports = PGDBIRCPlugin 54 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/pglintrc-default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | project: null, 3 | token: null 4 | } 5 | -------------------------------------------------------------------------------- /src/pgdbi/graphile-extensions/project.js: -------------------------------------------------------------------------------- 1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils"); 2 | const fs = require('fs') 3 | 4 | const PGDBIRCPlugin = makeExtendSchemaPlugin(build => { 5 | const { pgSql: sql } = build; 6 | const pgdbiDir = `${process.cwd()}/.pgdbi` 7 | const projectPath = `${pgdbiDir}/project.json` 8 | 9 | return { 10 | typeDefs: gql` 11 | type ProjectPayload { 12 | project: JSON! 13 | } 14 | 15 | extend type Query { 16 | project: ProjectPayload 17 | } 18 | `, 19 | resolvers: { 20 | Query: { 21 | project: async ( 22 | _query, 23 | args, 24 | context, 25 | resolveInfo, 26 | { selectGraphQLResultFromTable } 27 | ) => { 28 | try { 29 | const exists = fs.existsSync(projectPath) 30 | if (!exists) { 31 | throw new Error('Project file does not exist') 32 | } 33 | 34 | const project = fs.readFileSync(projectPath) 35 | 36 | return { 37 | project: JSON.parse(project) 38 | }; 39 | } catch (e) { 40 | // Oh noes! If at first you don't succeed, 41 | // destroy all evidence you ever tried. 42 | throw e; 43 | } 44 | }, 45 | }, 46 | }, 47 | }; 48 | }); 49 | 50 | module.exports = PGDBIRCPlugin 51 | -------------------------------------------------------------------------------- /src/pgdbi/transformBuild.js: -------------------------------------------------------------------------------- 1 | const camelCaseKeys = require('camelcase-keys') 2 | const pg10IntrospectionQuery = require('./pg10IntrospectionQuery') 3 | 4 | const queryBuilderMap = { 5 | "10": require('./pg10IntrospectionQuery'), 6 | "11": require('./pg11IntrospectionQuery'), 7 | "12": require('./pg11IntrospectionQuery') 8 | } 9 | 10 | async function transformBuild(build, pgPool) { 11 | try { 12 | const version = (await pgPool.query('SHOW server_version;')).rows[0].server_version.split('.')[0]; 13 | console.log('version', version) 14 | // console.log('build.options', build.options) 15 | const schemas = build.options.pgSchemas.join("','"); 16 | console.log('schemas', schemas) 17 | const querySql = await queryBuilderMap[version](schemas) 18 | const schemaTree = camelCaseKeys((await pgPool.query(querySql)).rows[0], {deep:true}) 19 | return schemaTree 20 | } catch (e) { 21 | console.log('CAUGHT ERROR', e.toString()) 22 | throw e; 23 | } 24 | } 25 | 26 | module.exports = transformBuild -------------------------------------------------------------------------------- /src/web-vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /src/web-vue/README.md: -------------------------------------------------------------------------------- 1 | # web-vue 2 | 3 | ## Project setup 4 | 5 | ``` 6 | yarn install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | yarn run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | yarn run build 19 | ``` 20 | 21 | ### Run your tests 22 | 23 | ``` 24 | yarn run test 25 | ``` 26 | 27 | ### Lints and fixes files 28 | 29 | ``` 30 | yarn run lint 31 | ``` 32 | 33 | ### Customize configuration 34 | 35 | See [Configuration Reference](https://cli.vuejs.org/config/). 36 | -------------------------------------------------------------------------------- /src/web-vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/app'], 3 | }; 4 | -------------------------------------------------------------------------------- /src/web-vue/delete/EnabledRoleListMixin.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /src/web-vue/delete/RoleFilterFunctionsMixin.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/web-vue/delete/RoleList.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 59 | 60 | 63 | -------------------------------------------------------------------------------- /src/web-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/src/web-vue/public/favicon.ico -------------------------------------------------------------------------------- /src/web-vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | pg-db-inspector 12 | 13 | 14 | 15 | 16 | 17 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/web-vue/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/src/web-vue/public/logo.png -------------------------------------------------------------------------------- /src/web-vue/src/AppBus.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue'; 3 | 4 | const bus = new Vue(); 5 | 6 | export default bus; -------------------------------------------------------------------------------- /src/web-vue/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | Artboard 46 2 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Enum/Enum.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 67 | 68 | 71 | -------------------------------------------------------------------------------- /src/web-vue/src/components/ForeignKeyIndex/Constraints/CheckConstraints.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/web-vue/src/components/FunctionSecurity/Assignment/FunctionPolicyAssignment.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Help/Help.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /src/web-vue/src/components/PgLint/PgLintResult.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Project/ProjectExport.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Project/ProjectImport.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Project/ProjectNavigator.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Project/ProjectResetDialog.vue: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 70 | 71 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Role/CreateRolesRealization.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Schema/SchemaUsageRealization.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Settings/DefaultRlsUsing.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 50 | 51 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Settings/SecurityPolicySettings.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 28 | 29 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Settings/Settings.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /src/web-vue/src/components/SmartCommentManager/SmartCommentManager.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/Constraints/TableCheckConstraints.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 71 | 72 | 75 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/Constraints/TableKeyColumnUsage.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 50 | 51 | 54 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/Constraints/TableUniqueConstraints.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 56 | 57 | 60 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/TableGrants.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 61 | 62 | 65 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/TableIndices copy.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 68 | 69 | 72 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Table/TablePolicies.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 76 | 77 | 80 | -------------------------------------------------------------------------------- /src/web-vue/src/components/TableSecurity copy/Assignment/TablePolicyAssignment.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /src/web-vue/src/components/TableSecurity-next/Assignment/TablePolicyAssignment.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /src/web-vue/src/components/TableSecurity/Assignment/TablePolicyAssignment.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /src/web-vue/src/components/Udt/Udt.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 67 | 68 | 71 | -------------------------------------------------------------------------------- /src/web-vue/src/components/View/ViewColumns.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 60 | 61 | 64 | -------------------------------------------------------------------------------- /src/web-vue/src/components/View/ViewSearch.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /src/web-vue/src/gql/mutation/execSql.graphql: -------------------------------------------------------------------------------- 1 | mutation ExecSql( 2 | $sql: String! 3 | ){ 4 | ExecSql(input: { 5 | sql: $sql 6 | }) { 7 | result 8 | } 9 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/mutation/pgLint.graphql: -------------------------------------------------------------------------------- 1 | mutation PgLint( 2 | $project: String! 3 | $token: String! 4 | ) { 5 | PgLint(input: { 6 | project: $project 7 | token: $token 8 | }) { 9 | result 10 | } 11 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/mutation/searchFunctions.graphql: -------------------------------------------------------------------------------- 1 | mutation SearchFunctions( 2 | $searchTerm: String! 3 | ){ 4 | searchFunctions(searchTerm: $searchTerm) { 5 | id 6 | functionName 7 | functionSchema 8 | resultDataType 9 | argumentDataTypes 10 | definition 11 | } 12 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/mutation/writeArtifacts.graphql: -------------------------------------------------------------------------------- 1 | mutation WriteArtifacts( 2 | $projectState: JSON! 3 | $masterSecurityPolicy: String! 4 | $ownershipPolicy: String! 5 | $schemaUsageSql: String! 6 | $masterTablePolicy: String! 7 | $masterFunctionPolicy: String! 8 | $allSchemaTablePolicies: JSON! 9 | $allSchemaFunctionPolicies: JSON! 10 | ){ 11 | WriteArtifacts(input: { 12 | projectState: $projectState 13 | masterSecurityPolicy: $masterSecurityPolicy 14 | ownershipPolicy: $ownershipPolicy 15 | schemaUsageSql: $schemaUsageSql 16 | masterTablePolicy: $masterTablePolicy 17 | masterFunctionPolicy: $masterFunctionPolicy 18 | allSchemaTablePolicies: $allSchemaTablePolicies 19 | allSchemaFunctionPolicies: $allSchemaFunctionPolicies 20 | }) { 21 | result 22 | } 23 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/allEnabledRoles.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | allEnabledRoles { 3 | nodes { 4 | roleName 5 | applicableRoles { 6 | grantee 7 | roleName 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/dbIntrospection.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | dbIntrospection 3 | pgdbiOptions 4 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/functionById.graphql: -------------------------------------------------------------------------------- 1 | query FunctionById($id: String!) { 2 | functionById(id: $id) { 3 | id 4 | functionName 5 | functionSchema 6 | resultDataType 7 | argumentDataTypes 8 | definition 9 | } 10 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/getDbSchemaList.graphql: -------------------------------------------------------------------------------- 1 | query GetDbSchemaList{ 2 | allSchemata( 3 | orderBy: SCHEMA_NAME_ASC 4 | ) 5 | { 6 | nodes { 7 | id 8 | schemaName 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/getDbSchemaTree.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | allSchemata 3 | ( 4 | filter: { 5 | schemaName: { 6 | notIn: [ 7 | "pg_toast", 8 | "pg_temp_1", 9 | "pg_toast_temp_1", 10 | "pg_catalog", 11 | "information_schema", 12 | "public" 13 | ] 14 | } 15 | } 16 | ) 17 | { 18 | nodes { 19 | id 20 | schemaName 21 | schemaTables { 22 | id 23 | name: tableName 24 | tableSchema 25 | tableColumns { 26 | tableName 27 | tableSchema 28 | columnName 29 | dataType 30 | } 31 | } 32 | schemaFunctions { 33 | id 34 | name: functionName 35 | functionSchema 36 | } 37 | schemaEnums { 38 | id 39 | name: enumName 40 | enumSchema 41 | enumValues 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/getDbSchemaTreeBySchemaName.graphql: -------------------------------------------------------------------------------- 1 | query GetDbSchemaTreeBySchemaName($schemaNames: [SqlIdentifier!]){ 2 | allSchemata 3 | ( 4 | filter: { 5 | schemaName: { 6 | in: $schemaNames 7 | } 8 | } 9 | ) 10 | { 11 | nodes { 12 | id 13 | schemaName 14 | schemaTables { 15 | id 16 | name: tableName 17 | tableSchema 18 | tableColumns { 19 | tableName 20 | tableSchema 21 | columnName 22 | dataType 23 | } 24 | indices { 25 | tableName 26 | tableSchema 27 | columnName 28 | indexName 29 | } 30 | referentialConstraints { 31 | constraintName 32 | constraintSchema 33 | uniqueConstraintName 34 | uniqueConstraintSchema 35 | matchOption 36 | updateRule 37 | deleteRule 38 | referencingColumnUsage { 39 | constraintName 40 | tableSchema 41 | tableName 42 | columnName 43 | ordinalPosition 44 | positionInUniqueConstraint 45 | } 46 | referencedColumnUsage { 47 | constraintName 48 | tableSchema 49 | tableName 50 | columnName 51 | ordinalPosition 52 | positionInUniqueConstraint 53 | } 54 | } 55 | roleTableGrants { 56 | grantor 57 | grantee 58 | tableName 59 | tableSchema 60 | privilegeType 61 | isGrantable 62 | withHierarchy 63 | } 64 | } 65 | schemaFunctions { 66 | id 67 | name: functionName 68 | functionSchema 69 | } 70 | schemaEnums { 71 | id 72 | name: enumName 73 | enumSchema 74 | enumValues 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/getDbSecurityTree.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | allSchemata 3 | ( 4 | filter: { 5 | schemaName: { 6 | notIn: [ 7 | "pg_toast", 8 | "pg_temp_1", 9 | "pg_toast_temp_1", 10 | "pg_catalog", 11 | "information_schema", 12 | "public" 13 | ] 14 | } 15 | } 16 | ) 17 | { 18 | nodes { 19 | id 20 | schemaName 21 | schemaTables { 22 | id 23 | tableName 24 | tableSchema 25 | policies { 26 | tableName 27 | schemaName 28 | policyName 29 | roles 30 | cmd 31 | withCheck 32 | qual 33 | } 34 | roleTableGrants { 35 | grantor 36 | grantee 37 | tableName 38 | tableSchema 39 | privilegeType 40 | isGrantable 41 | withHierarchy 42 | } 43 | } 44 | schemaFunctions { 45 | id 46 | name: functionName 47 | functionSchema 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/getDbSecurityTreeFiltered.graphql: -------------------------------------------------------------------------------- 1 | query GetDbSecurityTreeFiltered( 2 | $filter: [SqlIdentifier!]! 3 | ){ 4 | allSchemata(filter: { 5 | schemaName: { 6 | in: $filter 7 | } 8 | }) { 9 | nodes { 10 | id 11 | schemaName 12 | schemaTables { 13 | id 14 | tableName 15 | tableSchema 16 | policies { 17 | tableName 18 | schemaName 19 | policyName 20 | roles 21 | cmd 22 | withCheck 23 | qual 24 | } 25 | roleTableGrants { 26 | grantor 27 | grantee 28 | tableName 29 | tableSchema 30 | privilegeType 31 | isGrantable 32 | withHierarchy 33 | } 34 | roleColumnGrants { 35 | grantor 36 | grantee 37 | tableName 38 | tableSchema 39 | privilegeType 40 | isGrantable 41 | columnName 42 | } 43 | } 44 | schemaFunctions { 45 | id 46 | name: functionName 47 | functionSchema 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/pgdbirc.graphql: -------------------------------------------------------------------------------- 1 | query PGDBIRC { 2 | PGDBIRC { 3 | pgdbirc 4 | } 5 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/pglintrc.graphql: -------------------------------------------------------------------------------- 1 | query pgpintrc { 2 | pglintrc { 3 | pglintrc 4 | } 5 | } -------------------------------------------------------------------------------- /src/web-vue/src/gql/query/project.graphql: -------------------------------------------------------------------------------- 1 | query Project { 2 | project { 3 | project 4 | } 5 | } -------------------------------------------------------------------------------- /src/web-vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import vuetify from './plugins/vuetify'; 3 | import App from './App.vue'; 4 | import router from './router'; 5 | import store from './store/store'; 6 | import { createProvider } from './vue-apollo'; 7 | import VueClipboard from 'vue-clipboard2'; 8 | import VueLoading from 'vuejs-loading-plugin' 9 | 10 | 11 | Vue.config.productionTip = false; 12 | 13 | Vue.use(VueClipboard); 14 | Vue.use(VueLoading) 15 | 16 | new Vue({ 17 | vuetify, 18 | router, 19 | store, 20 | apolloProvider: createProvider(), 21 | render: h => h(App), 22 | }).$mount('#app'); 23 | -------------------------------------------------------------------------------- /src/web-vue/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuetify from 'vuetify/lib'; 3 | // import 'material-design-icons-iconfont/dist/material-design-icons.css' 4 | import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader 5 | 6 | Vue.use(Vuetify); 7 | 8 | export default new Vuetify({ 9 | icons: { 10 | iconfont: 'mdi', 11 | }, 12 | // theme: { 13 | // primary: '#2196f3', 14 | // secondary: '#3f51b5', 15 | // accent: '#03a9f4', 16 | // error: '#f44336', 17 | // warning: '#ffc107', 18 | // info: '#607d8b', 19 | // success: '#4caf50' 20 | // }, 21 | // theme: { 22 | // themes: { 23 | // dark: { 24 | // primary: '#2196f3', 25 | // secondary: '#3f51b5', 26 | // accent: '#03a9f4', 27 | // error: '#f44336', 28 | // warning: '#ffc107', 29 | // info: '#607d8b', 30 | // success: '#4caf50' 31 | // } 32 | // } 33 | // } 34 | }); 35 | -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeAllSchemaFunctionPolicies.js: -------------------------------------------------------------------------------- 1 | import computeSchemaFunctionPolicy from './computeSchemaFunctionPolicy' 2 | 3 | function computeAllSchemaFunctionPolicies (state, policyReadability) { 4 | return state.managedSchemata 5 | .filter(s => !s.parked) 6 | .filter(s => s.schemaFunctions.length > 0) 7 | .reduce( 8 | (all, schema) => { 9 | const schemaFunctions = schema.schemaFunctions 10 | const schemaPolicy = { 11 | name: `${schema.schemaName}`, 12 | policy: computeSchemaFunctionPolicy(state, policyReadability, schemaFunctions) 13 | } 14 | return all.concat([schemaPolicy]) 15 | }, [] 16 | ) 17 | .sort( 18 | (a,b)=>{ 19 | return a.name < b.name ? -1 : 1 20 | } 21 | ) 22 | } 23 | 24 | export default computeAllSchemaFunctionPolicies -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeAllSchemaTablePolicies.js: -------------------------------------------------------------------------------- 1 | // import computeRemoveRls from './computeRemoveRls' 2 | import computeSchemaTablePolicy from './computeSchemaTablePolicy' 3 | 4 | function computeAllSchemaTablePolicies (state, policyReadability) { 5 | return state.managedSchemata 6 | .filter(s => !s.parked) 7 | .filter(s => s.schemaTables.length > 0) 8 | .reduce( 9 | (all, schema) => { 10 | const schemaTables = schema.schemaTables.filter(t => t.tableType === 'BASE TABLE') 11 | // const schemaRemoveRls = computeRemoveRls(schema.schemaName) 12 | 13 | const schemaPolicy = { 14 | name: `${schema.schemaName}`, 15 | policy: computeSchemaTablePolicy(state, policyReadability, schemaTables) 16 | } 17 | return all.concat([schemaPolicy]) 18 | }, [] 19 | ) 20 | .sort( 21 | (a,b)=>{ 22 | return a.name < b.name ? -1 : 1 23 | } 24 | ) 25 | } 26 | 27 | export default computeAllSchemaTablePolicies -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeMasterFunctionPolicy.js: -------------------------------------------------------------------------------- 1 | import computeAllSchemaFunctionPolicies from './computeAllSchemaFunctionPolicies' 2 | 3 | function computeMasterFunctionPolicy (state, policyReadability) { 4 | const masterPolicyName = 'All Schemata - Functions' 5 | const schemaFunctionPolicies = computeAllSchemaFunctionPolicies(state, policyReadability) 6 | const masterPolicy = schemaFunctionPolicies.reduce( 7 | (m, p) => { 8 | return m.concat(p.policy) 9 | }, '' 10 | ) 11 | 12 | return { 13 | name: masterPolicyName, 14 | policy: masterPolicy 15 | } 16 | } 17 | 18 | export default computeMasterFunctionPolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeMasterSecurityPolicy.js: -------------------------------------------------------------------------------- 1 | import computeRolesSql from "./computeRolesSql" 2 | import computeSchemaUsageSql from "./computeSchemaUsageSql" 3 | import computeMasterTablePolicy from "./computeMasterTablePolicy" 4 | import computeMasterFunctionPolicy from "./computeMasterFunctionPolicy" 5 | import computeOwnershipPolicy from "./computeOwnershipPolicy" 6 | 7 | function computeMasterSecurityPolicy (state, policyReadability) { 8 | return [ 9 | '--===== BEGIN COMPLETE SECURITY POLICY -========', 10 | computeRolesSql(state), 11 | '\n\n--***** BEGIN OWNERSHIP -********', 12 | computeOwnershipPolicy(state, policyReadability), 13 | '--***** END OWNERSHIP -**********', 14 | '\n\n--***** BEGIN SCHEMA USAGE -********', 15 | computeSchemaUsageSql(state, policyReadability), 16 | '--***** END SCHEMA USAGE -**********', 17 | '\n\n--***** BEGIN TABLE POLICIES -********', 18 | computeMasterTablePolicy(state, policyReadability).policy, 19 | '--***** END TABLE POLICIES -**********', 20 | '\n\n--***** BEGIN FUNCTION POLICIES -********', 21 | computeMasterFunctionPolicy(state, policyReadability).policy, 22 | '--***** END FUNCTION POLICIES -**********', 23 | '\n\n--===== END COMPLETE SECURITY POLICY -==========', 24 | ].join('\n') 25 | 26 | } 27 | 28 | export default computeMasterSecurityPolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeMasterTablePolicy.js: -------------------------------------------------------------------------------- 1 | import computeAllSchemaTablePolicies from './computeAllSchemaTablePolicies' 2 | 3 | function computeMasterTablePolicy (state, policyReadability) { 4 | const masterPolicyName = 'All Schemata - Tables' 5 | const schemaTablePolicies = computeAllSchemaTablePolicies(state, policyReadability) 6 | const masterPolicy = schemaTablePolicies.reduce( 7 | (m, p) => { 8 | return m.concat(p.policy) 9 | }, '' 10 | ) 11 | 12 | return { 13 | name: masterPolicyName, 14 | policy: masterPolicy 15 | } 16 | 17 | } 18 | 19 | export default computeMasterTablePolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeOwnershipPolicy.js: -------------------------------------------------------------------------------- 1 | import Mustache from 'mustache' 2 | 3 | const ownershipPolicyTemplate = ` 4 | ---------- 5 | ---------- BEGIN OWNERSHIP SQL 6 | ---------- 7 | 8 | 9 | {{#schemata}} 10 | ---------- SCHEMA: {{schemaName}} 11 | ALTER SCHEMA {{schemaName}} OWNER TO {{dbOwnerRole}}; 12 | -- tables 13 | {{#schemaTables}} 14 | ALTER TABLE {{schemaName}}.{{tableName}} OWNER TO {{dbOwnerRole}}; 15 | {{/schemaTables}} 16 | -- functions 17 | {{#schemaFunctions}} 18 | ALTER FUNCTION {{schemaName}}.{{functionName}}({{argumentDataTypes}}) OWNER TO {{dbOwnerRole}}; 19 | {{/schemaFunctions}} 20 | ---------- END SCHEMA: {{schemaName}} 21 | {{/schemata}} 22 | ---------- 23 | ---------- END OWNERSHIP SQL 24 | ---------- 25 | --== 26 | ` 27 | 28 | const computeOwnershipPolicy = (state) => { 29 | const sortedSchemata = state.managedSchemata 30 | .sort((a,b)=>{ 31 | if ( a.schemaName < b.schemaName ){ 32 | return -1; 33 | } 34 | if ( a.schemaName > b.schemaName ){ 35 | return 1; 36 | } 37 | return 0; 38 | }) 39 | .map(s=>{ 40 | return { 41 | ...s, 42 | schemaFunctions: s.schemaFunctions.map(f=>{ 43 | const argumentDataTypes = f.argumentDataTypes 44 | .split(',') 45 | .map(adt => adt.replace('timestamp with time zone', 'timestamptz')) 46 | .map(adt => adt.trim().split(' ')[1]) 47 | .join(', ') 48 | 49 | return { 50 | ...f, 51 | argumentDataTypes: argumentDataTypes 52 | } 53 | }) 54 | } 55 | }) 56 | 57 | return Mustache.render( 58 | ownershipPolicyTemplate, 59 | { 60 | schemata: sortedSchemata, 61 | dbOwnerRole: state.roleSet.dbOwnerRole.roleName 62 | } 63 | ).split("'").join("'") 64 | } 65 | 66 | export default computeOwnershipPolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeRemoveRls.js: -------------------------------------------------------------------------------- 1 | import Mustache from 'mustache' 2 | 3 | function computeRemoveRls (schemaName) { 4 | return Mustache.render( 5 | removeAllRlsScriptTemplate, 6 | { schemaName: schemaName } 7 | ) 8 | } 9 | 10 | export default computeRemoveRls 11 | 12 | const removeAllRlsScriptTemplate = ` 13 | ---------- 14 | ---------- remove all rls policies for schema: {{schemaName}} 15 | ---------- 16 | DO 17 | $body$ 18 | DECLARE 19 | _pol pg_policies; 20 | _drop_sql text; 21 | BEGIN 22 | 23 | for _pol in 24 | select 25 | * 26 | from pg_policies 27 | where schemaname = '{{schemaName}}' 28 | loop 29 | _drop_sql := 'drop policy if exists ' || _pol.policyname || ' on ' || _pol.schemaname || '.' || _pol.tablename || ';'; 30 | execute _drop_sql; 31 | end loop 32 | ; 33 | END 34 | $body$; 35 | ` -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeSchemaFunctionPolicy.js: -------------------------------------------------------------------------------- 1 | import computeFunctionPolicy from './computeFunctionPolicy' 2 | 3 | function computeSchemaFunctionPolicy (state, policyReadability, someFunctions) { 4 | const retval = someFunctions.sort((a,b)=>{return a.functionname < b.functionname ? -1 : 1}).reduce( 5 | (policy, aFunction) => { 6 | const policyTemplate = state.functionPolicies.find(p => p.id === state.functionPolicyAssignments[aFunction.id].policyDefinitionId) 7 | const variables = { 8 | } 9 | const aFunctionPolicy = computeFunctionPolicy(policyTemplate, policyReadability, variables, aFunction) 10 | return policy.concat(aFunctionPolicy) 11 | }, '' 12 | ) 13 | return retval 14 | } 15 | 16 | export default computeSchemaFunctionPolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/computeSchemaTablePolicy.js: -------------------------------------------------------------------------------- 1 | import computeTablePolicy from './computeTablePolicy' 2 | 3 | function computeSchemaTablePolicy (state, policyReadability, tables) { 4 | return tables.sort((a,b)=>{return a.tablename < b.tablename ? -1 : 1}).reduce( 5 | (policy, table) => { 6 | const policyTemplate = state.policies.find(p => p.id === state.tablePolicyAssignments[table.id].policyDefinitionId) 7 | const variables = { 8 | schemaName: table.tableSchema, 9 | tableName: table.tablename 10 | } 11 | const tablePolicy = computeTablePolicy(policyTemplate, policyReadability, variables, table) 12 | return policy.concat(tablePolicy) 13 | }, '' 14 | ) 15 | } 16 | 17 | export default computeSchemaTablePolicy -------------------------------------------------------------------------------- /src/web-vue/src/scriptCompute/index.js: -------------------------------------------------------------------------------- 1 | import computeAllSchemaFunctionPolicies from './computeAllSchemaFunctionPolicies' 2 | import computeAllSchemaTablePolicies from './computeAllSchemaTablePolicies' 3 | import computeFunctionPolicy from './computeFunctionPolicy' 4 | import computeMasterFunctionPolicy from './computeMasterFunctionPolicy' 5 | import computeMasterSecurityPolicy from './computeMasterSecurityPolicy' 6 | import computeMasterTablePolicy from './computeMasterTablePolicy' 7 | import computeOwnershipPolicy from './computeOwnershipPolicy' 8 | import computeRemoveRls from './computeRemoveRls' 9 | import computeRolesSql from './computeRolesSql' 10 | import computeSchemaFunctionPolicy from './computeSchemaFunctionPolicy' 11 | import computeSchemaTablePolicy from './computeSchemaTablePolicy' 12 | import computeSchemaUsageSql from './computeSchemaUsageSql' 13 | import computeTablePolicy from './computeTablePolicy' 14 | 15 | export default { 16 | computeAllSchemaFunctionPolicies, 17 | computeAllSchemaTablePolicies, 18 | computeFunctionPolicy, 19 | computeMasterFunctionPolicy, 20 | computeMasterSecurityPolicy, 21 | computeMasterTablePolicy, 22 | computeOwnershipPolicy, 23 | computeRemoveRls, 24 | computeRolesSql, 25 | computeSchemaFunctionPolicy, 26 | computeSchemaTablePolicy, 27 | computeSchemaUsageSql, 28 | computeTablePolicy 29 | } -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/index.js: -------------------------------------------------------------------------------- 1 | import setProjectRoleSet from './setProjectRoleSet' 2 | import setManagedSchemata from './setManagedSchemata' 3 | import resetDefaultState from './resetDefaultState' 4 | import writeToDisk from './writeToDisk' 5 | import loadFromDisk from './loadFromDisk' 6 | 7 | export default { 8 | setProjectRoleSet, 9 | setManagedSchemata, 10 | resetDefaultState, 11 | writeToDisk, 12 | loadFromDisk 13 | } -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/loadFromDisk.js: -------------------------------------------------------------------------------- 1 | import {getApolloClient} from '@/vue-apollo' 2 | import project from '@/gql/query/project.graphql' 3 | 4 | async function loadFromDisk({commit}) { 5 | const apolloClient = getApolloClient() 6 | 7 | const queryResult = await apolloClient.query({ 8 | query: project, 9 | fetchPolicy: 'network-only' 10 | }) 11 | 12 | const theProject = queryResult.data.project.project 13 | 14 | commit('importProject', { 15 | project: theProject 16 | }) 17 | 18 | } 19 | 20 | export default loadFromDisk 21 | -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/pgdbirc.js: -------------------------------------------------------------------------------- 1 | import {getApolloClient} from '@/vue-apollo' 2 | import getPgdbirc from '@/gql/query/pgdbirc.graphql' 3 | 4 | async function pgdbirc() { 5 | const apolloClient = getApolloClient() 6 | 7 | const queryResult = await apolloClient.query({ 8 | query: getPgdbirc, 9 | fetchPolicy: 'network-only' 10 | }) 11 | 12 | return queryResult.data.PGDBIRC.pgdbirc 13 | } 14 | 15 | export default pgdbirc 16 | -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/resetDefaultState.js: -------------------------------------------------------------------------------- 1 | import getGetPgdbirc from './pgdbirc' 2 | 3 | async function resetDefaultState(context) { 4 | const pgdbirc = await getGetPgdbirc() 5 | await context.commit('resetDefaultState', pgdbirc) 6 | } 7 | 8 | export default resetDefaultState 9 | -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/setManagedSchemata.js: -------------------------------------------------------------------------------- 1 | async function setManagedSchemata({commit}, payload) { 2 | await commit('setManagedSchemata', payload.schemaTree) 3 | commit('setPgdbiOptions', payload.pgdbiOptions) 4 | commit('setExistingRlsPolicies', payload.rlsPolicies) 5 | } 6 | 7 | export default setManagedSchemata; 8 | -------------------------------------------------------------------------------- /src/web-vue/src/store/actions/setProjectRoleSet.js: -------------------------------------------------------------------------------- 1 | 2 | async function setProjectRoleSet({commit, dispatch}, roleSet) { 3 | await dispatch('resetDefaultState') 4 | await commit('setProjectRoleSet', roleSet) 5 | await commit('defaultRlsUsing', roleSet.defaultRlsUsing) 6 | return `role set set - ${roleSet}` 7 | } 8 | 9 | export default setProjectRoleSet; 10 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/assignFunctionPolicy.js: -------------------------------------------------------------------------------- 1 | function evaluateFunctionPolicy(functionId, policyDefinitionId) { 2 | return { 3 | functionId: functionId 4 | ,policyDefinitionId: policyDefinitionId 5 | ,evaluation: { 6 | status: 'PASS' 7 | ,errors: [] 8 | } 9 | } 10 | } 11 | 12 | function assignAll(state, payload) { 13 | state.isDirty = true 14 | const functionIds = payload.functionIds; 15 | const policyDefinitionId = payload.policyDefinitionId; 16 | 17 | functionIds.forEach( 18 | functionId => { 19 | state.functionPolicyAssignments[functionId] = evaluateFunctionPolicy(functionId, policyDefinitionId) 20 | } 21 | ) 22 | } 23 | 24 | export default assignAll; 25 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/assignTablePolicy.js: -------------------------------------------------------------------------------- 1 | function evaluateTablePolicy(tableId, policyDefinitionId) { 2 | return { 3 | tableId: tableId 4 | ,policyDefinitionId: policyDefinitionId 5 | ,evaluation: { 6 | status: 'PASS' 7 | ,errors: [] 8 | } 9 | } 10 | } 11 | 12 | function assignAll(state, payload) { 13 | state.isDirty = true 14 | const tableIds = payload.tableIds; 15 | const policyDefinitionId = payload.policyDefinitionId; 16 | 17 | tableIds.forEach( 18 | tableId => { 19 | state.tablePolicyAssignments[tableId] = evaluateTablePolicy(tableId, policyDefinitionId) 20 | } 21 | ) 22 | } 23 | 24 | export default assignAll; 25 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/createRlsPolicy.js: -------------------------------------------------------------------------------- 1 | function createRlsPolicy(state, payload) { 2 | const policy = state.policies.find(p => p.id === payload.policyId); 3 | const otherPolicies = state.policies.filter(p => p.id !== payload.policyId); 4 | const roleName = payload.roleName; 5 | const action = payload.action; 6 | 7 | const id = new Date().getTime() * 10000 + 621355968000000000; 8 | const newRlsPolicy = { 9 | id: id, 10 | name: payload.name || `rls_${id}`, 11 | using: payload.using || state.defaultRlsUsing, 12 | withCheck: payload.withCheck || state.defaultRlsWithCheck, 13 | passStrategy: payload.passStrategy || 'permissive', 14 | }; 15 | 16 | const updatedPolicy = { 17 | ...policy, 18 | rlsQualifiers: { 19 | ...policy.rlsQualifiers, 20 | [roleName]: { 21 | ...policy.rlsQualifiers[roleName], 22 | [action]: { 23 | ...policy.rlsQualifiers[roleName][action], 24 | policies: [ 25 | ...policy.rlsQualifiers[roleName][action].policies, 26 | ...[newRlsPolicy], 27 | ], 28 | }, 29 | }, 30 | }, 31 | }; 32 | 33 | state.policies = [...otherPolicies, ...[updatedPolicy]]; 34 | } 35 | 36 | export default createRlsPolicy; 37 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/customizeTablePolicy.js: -------------------------------------------------------------------------------- 1 | import assignTablePolicy from './assignTablePolicy' 2 | 3 | function customizeTablePolicy(state, payload) { 4 | state.isDirty = true 5 | const sourcePolicyDefinitionId = payload.sourcePolicyDefinitionId; 6 | const newFields = payload.newFields; 7 | const tableIds = payload.tableIds || []; 8 | 9 | const sourcePolicyDefinition = state.policies.find( 10 | p => p.id === sourcePolicyDefinitionId, 11 | ); 12 | 13 | const newPolicy = { 14 | ...sourcePolicyDefinition, 15 | id: new Date().getTime() * 10000 + 621355968000000000, 16 | name: newFields.name, 17 | customIdentifier: tableIds.length === 1 ? tableIds[0] : null, 18 | }; 19 | 20 | state.policies = [...state.policies, newPolicy] 21 | .sort(function(a, b) { 22 | return a.id < b.id; 23 | }); 24 | 25 | assignTablePolicy(state, { 26 | tableIds: tableIds, 27 | policyDefinitionId: newPolicy.id 28 | }); 29 | } 30 | 31 | export default customizeTablePolicy; 32 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/defaultRlsUsing.js: -------------------------------------------------------------------------------- 1 | function defaultRlsUsing(state, payload) { 2 | state.isDirty = true 3 | state.defaultRlsUsing = payload; 4 | } 5 | 6 | export default defaultRlsUsing; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/defaultRlsWithCheck.js: -------------------------------------------------------------------------------- 1 | function defaultRlsWithCheck(state, payload) { 2 | state.isDirty = true 3 | state.defaultRlsWithCheck = payload.defaultRlsWithCheck; 4 | } 5 | 6 | export default defaultRlsWithCheck; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/deleteRlsPolicy.js: -------------------------------------------------------------------------------- 1 | function deleteRlsPolicy(state, payload) { 2 | state.isDirty = true 3 | const policy = state.policies.find(p => p.id === payload.policyId); 4 | const otherPolicies = state.policies.filter(p => p.id !== payload.policyId); 5 | const roleName = payload.roleName; 6 | const action = payload.action; 7 | const rlsPolicyId = payload.rlsPolicyId; 8 | 9 | const updatedPolicy = { 10 | ...policy, 11 | rlsQualifiers: { 12 | ...policy.rlsQualifiers, 13 | [roleName]: { 14 | ...policy.rlsQualifiers[roleName], 15 | [action]: { 16 | ...policy.rlsQualifiers[roleName][action], 17 | policies: policy.rlsQualifiers[roleName][action].policies.filter( 18 | rp => rp.id !== rlsPolicyId, 19 | ), 20 | }, 21 | }, 22 | }, 23 | }; 24 | 25 | state.policies = [...otherPolicies, ...[updatedPolicy]]; 26 | } 27 | 28 | export default deleteRlsPolicy; 29 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/deleteTablePolicy.js: -------------------------------------------------------------------------------- 1 | function deleteTablePolicy(state, payload) { 2 | state.isDirty = true 3 | const policyDefinitionId = payload.policyDefinitionId; 4 | 5 | const otherPolicies = state.policies.filter(p => p.id !== policyDefinitionId); 6 | 7 | state.policies = [...otherPolicies].sort(function(a, b) { 8 | return a.id < b.id; 9 | }); 10 | 11 | Object.keys(state.tablePolicyAssignments).forEach( 12 | tableId => { 13 | if (state.tablePolicyAssignments[tableId] === policyDefinitionId) { 14 | state.tablePolicyAssignments[tableId] = state.defaultPolicy.id 15 | } 16 | } 17 | ) 18 | } 19 | 20 | export default deleteTablePolicy; 21 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/evaluate/evaluateAll.js: -------------------------------------------------------------------------------- 1 | import evaluateFkIndexes from './evaluateFkIndexes' 2 | import evaluateUqIndexes from './evaluateUqIndexes' 3 | import evaluateGenericIndices from './evaluateGenericIndices' 4 | import evaluateEnumScripts from './evaluateEnumScripts' 5 | import evaluateUdtScripts from './evaluateUdtScripts' 6 | 7 | 8 | function evaluateAll(state){ 9 | evaluateFkIndexes(state) 10 | evaluateUqIndexes(state) 11 | evaluateGenericIndices(state) 12 | evaluateEnumScripts(state) 13 | evaluateUdtScripts(state) 14 | } 15 | 16 | export default evaluateAll -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/evaluate/evaluateEnumScripts.js: -------------------------------------------------------------------------------- 1 | import Mustache from 'mustache' 2 | 3 | const enumTemplate = ` 4 | create type {{enumSchema}}.{{enumName}} as ( 5 | {{#enumValues}} 6 | '{{value}}'{{comma}} 7 | {{/enumValues}} 8 | ); 9 | ` 10 | 11 | function evaluateEnumScripts(state){ 12 | state.managedSchemata = state.managedSchemata 13 | .map( 14 | schema => { 15 | return { 16 | ...schema 17 | ,schemaEnums: schema.schemaEnums 18 | .map( 19 | e => { 20 | const enumDefinition = Mustache.render( 21 | enumTemplate, 22 | { 23 | ...e 24 | ,enumValues: e.enumValues.map( 25 | (v,i) => { 26 | return { 27 | value: v 28 | ,comma: i === e.enumValues.length -1 ? '' : ',' 29 | } 30 | } 31 | ) 32 | } 33 | ) 34 | 35 | return { 36 | ...e 37 | ,enumDefinition: enumDefinition 38 | } 39 | } 40 | ) 41 | } 42 | } 43 | ) 44 | } 45 | 46 | export default evaluateEnumScripts -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/evaluate/evaluateUdtScripts.js: -------------------------------------------------------------------------------- 1 | import Mustache from 'mustache' 2 | 3 | const udtTemplate = ` 4 | create type {{udtSchema}}.{{udtName}} as ( 5 | {{#fields}} 6 | {{fieldName}} {{dataType}}{{comma}} 7 | {{/fields}} 8 | ); 9 | ` 10 | 11 | function evaluateUdtScripts(state){ 12 | state.managedSchemata = state.managedSchemata 13 | .map( 14 | schema => { 15 | return { 16 | ...schema 17 | ,schemaUdts: schema.schemaUdts 18 | .map( 19 | e => { 20 | const udtDefinition = Mustache.render( 21 | udtTemplate, 22 | { 23 | ...e 24 | ,fields: e.fields.map( 25 | (f, i) => { 26 | return { 27 | ...f 28 | ,comma: i === e.fields.length -1 ? '' : ',' 29 | } 30 | } 31 | ) 32 | } 33 | ) 34 | 35 | return { 36 | ...e 37 | ,udtDefinition: udtDefinition 38 | } 39 | } 40 | ) 41 | } 42 | } 43 | ) 44 | } 45 | 46 | export default evaluateUdtScripts -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/evaluate/storeEvaluations.js: -------------------------------------------------------------------------------- 1 | function storeEvaluations(state, evaluations){ 2 | const indexEvaluations = Object.keys(evaluations) 3 | .reduce( 4 | (all, k) => { 5 | const existing = state.indexEvaluations[k] 6 | const thisEvaluation = existing ? [...existing, ...evaluations[k]] : evaluations[k] 7 | // console.log('evaluations', evaluations) 8 | // console.log('evaluations[k]', k, evaluations[k]) 9 | // console.log('existing', existing) 10 | // console.log('thisEvaluation', thisEvaluation) 11 | return thisEvaluation.length === 0 ? all : { 12 | ...all 13 | ,[thisEvaluation[0].idxKey]: thisEvaluation 14 | } 15 | }, {} 16 | ) 17 | 18 | state.indexEvaluations = { 19 | ...state.indexEvaluations, 20 | ...indexEvaluations 21 | } 22 | } 23 | 24 | export default storeEvaluations -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/filterSchemata.js: -------------------------------------------------------------------------------- 1 | function filterSchemata(state) { 2 | state.isDirty = true 3 | state.schemaFilterOn = true; 4 | } 5 | 6 | export default filterSchemata; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/importProject.js: -------------------------------------------------------------------------------- 1 | function importProject(state, payload) { 2 | Object.keys(payload.project).forEach(key => { 3 | state[key] = payload.project[key]; 4 | }); 5 | } 6 | 7 | export default importProject; 8 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/makeGlobalTablePolicy.js: -------------------------------------------------------------------------------- 1 | function makeGlobalTablePolicy(state, payload) { 2 | state.isDirty = true 3 | const policyDefinitionId = payload.policyDefinitionId; 4 | const newFields = payload.newFields; 5 | 6 | const existing = state.policies.find(p => p.name === newFields.name); 7 | if (existing) { 8 | throw new Error('A policy with this name already exists'); 9 | } else { 10 | const policyDefinition = state.policies.find( 11 | p => p.id === policyDefinitionId, 12 | ); 13 | const otherPolicies = state.policies.filter( 14 | p => p.id !== policyDefinition.id, 15 | ); 16 | 17 | const newGlobalPolicy = { 18 | ...policyDefinition, 19 | name: newFields.name, 20 | customIdentifier: null, 21 | }; 22 | 23 | state.policies = [...otherPolicies, ...[newGlobalPolicy]].sort(function( 24 | a, 25 | b, 26 | ) { 27 | return a.id < b.id; 28 | }); 29 | } 30 | } 31 | 32 | export default makeGlobalTablePolicy; 33 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/newFunctionPolicy.js: -------------------------------------------------------------------------------- 1 | function newFunctionPolicy(state, payload) { 2 | state.isDirty = true 3 | const existing = state.policies.find(p => p.name === payload.name); 4 | if (existing) { 5 | throw new Error('A policy with this name already exists'); 6 | } else { 7 | const name = payload.name; 8 | const dbUserRoles = state.roleSet.dbUserRoles; 9 | 10 | const newPolicy = { 11 | id: new Date().getTime() * 10000 + 621355968000000000, 12 | name: name, 13 | functionPolicyHeaderTemplate: state.functionPolicyHeaderTemplate, 14 | functionPolicyFooterTemplate: state.functionPolicyFooterTemplate, 15 | roleFunctionGrants: dbUserRoles.reduce((all, projectRole) => { 16 | return { 17 | ...all, 18 | [projectRole.roleName]: state.defaultFunctionRoleGrants, 19 | }; 20 | }, {}), 21 | }; 22 | 23 | state.functionPolicies = [...state.functionPolicies, ...[newPolicy]].sort( 24 | function(a, b) { 25 | return a.id < b.id; 26 | }, 27 | ); 28 | } 29 | } 30 | 31 | export default newFunctionPolicy; 32 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/newPolicy.js: -------------------------------------------------------------------------------- 1 | function newPolicy(state, payload) { 2 | const existing = state.policies.find(p => p.name === payload.name); 3 | if (existing) { 4 | throw new Error('A policy with this name already exists'); 5 | } else { 6 | state.isDirty = true 7 | const name = payload.name; 8 | const dbUserRoles = state.roleSet.dbUserRoles; 9 | 10 | const newPolicy = { 11 | id: new Date().getTime() * 10000 + 621355968000000000, 12 | name: name, 13 | policyHeaderTemplate: state.policyHeaderTemplate, 14 | policyFooterTemplate: state.policyFooterTemplate, 15 | enableRls: false, 16 | columnExclusionOverrides: { 17 | insert: [], 18 | update: [], 19 | }, 20 | columnExclusions: { 21 | insert: {}, 22 | update: {}, 23 | }, 24 | roleGrants: dbUserRoles.reduce((all, projectRole) => { 25 | return { 26 | ...all, 27 | [projectRole.roleName]: state.defaultRoleGrants, 28 | }; 29 | }, {}), 30 | rlsQualifiers: dbUserRoles.reduce((all, projectRole) => { 31 | return { 32 | ...all, 33 | [projectRole.roleName]: state.defaultRlsQualifiers, 34 | }; 35 | }, {}), 36 | }; 37 | 38 | state.policies = [...state.policies, ...[newPolicy]].sort(function(a, b) { 39 | return a.id < b.id; 40 | }); 41 | } 42 | } 43 | 44 | export default newPolicy; 45 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/projectRoles.js: -------------------------------------------------------------------------------- 1 | function dbUserRoles(state, payload) { 2 | state.isDirty = true 3 | const dbUserRoles = (state.roleSet.dbUserRoles = payload.dbUserRoles.map(role => { 4 | return { 5 | ...role, 6 | applicableRoles: role.applicableRoles || [], 7 | }; 8 | })); 9 | 10 | state.policies = state.policies.map(policy => { 11 | return { 12 | ...policy, 13 | roleGrants: dbUserRoles.reduce((all, projectRole) => { 14 | // const existing = policy.roleGrants[projectRole.name] 15 | 16 | return { 17 | ...all, 18 | [projectRole.roleName]: 19 | policy.roleGrants[projectRole.name] || state.defaultRoleGrants, 20 | }; 21 | }, {}), 22 | rlsQualifiers: dbUserRoles.reduce((all, projectRole) => { 23 | return { 24 | ...all, 25 | [projectRole.roleName]: 26 | policy.rlsQualifiers[projectRole.name] || 27 | state.defaultRlsQualifiers, 28 | }; 29 | }, {}), 30 | }; 31 | }); 32 | 33 | state.functionPolicies = state.functionPolicies.map(policy => { 34 | return { 35 | ...policy, 36 | roleFunctionGrants: dbUserRoles.reduce((all, projectRole) => { 37 | return { 38 | ...all, 39 | [projectRole.roleName]: 40 | policy.roleFunctionGrants[projectRole.name] || 41 | state.defaultFunctionRoleGrants, 42 | }; 43 | }, {}), 44 | }; 45 | }); 46 | 47 | const projectRoleNames = dbUserRoles.map(pr => pr.roleName) 48 | 49 | state.ignoredRoles = state.ignoredRoles.filter(ir => projectRoleNames.indexOf(ir.roleName) === -1) 50 | } 51 | 52 | export default dbUserRoles; 53 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/renameTablePolicy.js: -------------------------------------------------------------------------------- 1 | function renameTablePolicy(state, payload) { 2 | state.isDirty = true 3 | const policy = state.policies.find(p => p.id === payload.policyDefinitionId) 4 | const others = state.policies.filter(p => p.id !== payload.policyDefinitionId) 5 | 6 | state.policies = [ 7 | ...others, 8 | { 9 | ...policy, 10 | name: payload.name 11 | } 12 | ] 13 | } 14 | 15 | export default renameTablePolicy; 16 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/resetDefaultState.js: -------------------------------------------------------------------------------- 1 | import defaultState from '../defaultState'; 2 | 3 | function resetDefaultState(state, pgdbirc) { 4 | Object.keys(defaultState) 5 | .forEach(key => { 6 | state[key] = (pgdbirc[key] || defaultState[key]); 7 | }); 8 | state.isDirty = false 9 | } 10 | 11 | export default resetDefaultState; 12 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/saveFunctionPolicy.js: -------------------------------------------------------------------------------- 1 | function saveFunctionPolicy(state, payload) { 2 | state.isDirty = true 3 | const functionPolicies = state.functionPolicies.filter( 4 | p => p.id !== payload.policy.id, 5 | ); 6 | state.functionPolicies = [...functionPolicies, ...[payload.policy]].sort( 7 | (a, b) => { 8 | return a.id - b.id; 9 | }, 10 | ); 11 | } 12 | 13 | export default saveFunctionPolicy; 14 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/savePgLintResult.js: -------------------------------------------------------------------------------- 1 | function savePgLintResult(state, payload) { 2 | state.pgLintResults = [...state.pgLintResults, payload] 3 | } 4 | 5 | export default savePgLintResult -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/savePolicy.js: -------------------------------------------------------------------------------- 1 | function savePolicy(state, payload) { 2 | state.isDirty = true 3 | const policies = state.policies.filter(p => p.name !== payload.policy.name); 4 | state.policies = [...policies, ...[payload.policy]].sort((a, b) => { 5 | return a.id - b.id; 6 | }); 7 | } 8 | 9 | export default savePolicy; 10 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/selectedRoleFamilies.js: -------------------------------------------------------------------------------- 1 | function selectedRoleFamilies(state, payload) { 2 | state.isDirty = true 3 | state.selectedRoleFamilies = payload.selectedRoleFamilies; 4 | } 5 | 6 | export default selectedRoleFamilies; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/setAllRoleSets.js: -------------------------------------------------------------------------------- 1 | function setAllRoleSets(state, payload) { 2 | state.isDirty = true 3 | state.allRoleSets = payload 4 | } 5 | 6 | export default setAllRoleSets; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/setEnabledRoles.js: -------------------------------------------------------------------------------- 1 | function setEnabledRoles(state, payload) { 2 | state.isDirty = true 3 | state.enabledRoles = payload.enabledRoles 4 | } 5 | 6 | export default setEnabledRoles; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/setExistingRlsPolicies.js: -------------------------------------------------------------------------------- 1 | function setExistingRlsPolicies(state, payload) { 2 | state.existingRlsPolicies = payload 3 | } 4 | 5 | export default setExistingRlsPolicies -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/setPgdbiOptions.js: -------------------------------------------------------------------------------- 1 | function setPgdbiOptions(state, payload) { 2 | state.isDirty = true 3 | state.pgdbiOptions = payload.pgdbiOptions 4 | } 5 | 6 | export default setPgdbiOptions; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/setProjectRoleSet.js: -------------------------------------------------------------------------------- 1 | function setProjectRoleSet(state, payload) { 2 | state.isDirty = true 3 | const roleSet = state.allRoleSets.find(rs => rs.name === payload) 4 | state.roleSet = roleSet 5 | } 6 | 7 | export default setProjectRoleSet; 8 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/toggleIgnoreRole.js: -------------------------------------------------------------------------------- 1 | function toggleIgnoreRole(state, payload) { 2 | state.isDirty = true 3 | const isIgnored = state.ignoredRoles.find(i => i.roleName === payload.role.roleName) 4 | 5 | state.ignoredRoles = isIgnored ? state.ignoredRoles.filter(i => i.roleName !== payload.role.roleName) : [...state.ignoredRoles, payload.role] 6 | } 7 | 8 | export default toggleIgnoreRole; 9 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/toggleIndexForDrop.js: -------------------------------------------------------------------------------- 1 | import evaluateAll from './evaluate/evaluateAll' 2 | 3 | function toggleIndexForDrop(state, payload) { 4 | if (payload.value === true && !state.indicesToDrop[payload.item.id]) { // add the index 5 | const indexId = payload.item.id 6 | state.indicesToDrop = { 7 | ...state.indicesToDrop, 8 | [indexId]: payload.item 9 | } 10 | } else if (payload.value === false) { 11 | state.indicesToDrop = Object.keys(state.indicesToDrop) 12 | .filter(k => k !== payload.item.id) 13 | .reduce( 14 | (all, k) => { 15 | return { 16 | ...all, 17 | [k]: state.indicesToDrop[k] 18 | } 19 | }, {} 20 | ) 21 | } 22 | 23 | evaluateAll(state) 24 | } 25 | 26 | export default toggleIndexForDrop; 27 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/updateDefaultRlsUsing.js: -------------------------------------------------------------------------------- 1 | function updateDefaultRlsUsing(state, payload) { 2 | state.isDirty = true 3 | state.defaultRlsUsing = payload.defaultRlsUsing; 4 | } 5 | 6 | module.exports = updateDefaultRlsUsing; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/mutations/updateTablePolicyTemplate.js: -------------------------------------------------------------------------------- 1 | function updateTablePolicyTemplate(state, payload) { 2 | state.isDirty = true 3 | state.tablePolicyTemplate = payload.tablePolicyTemplate; 4 | } 5 | 6 | export default updateTablePolicyTemplate; 7 | -------------------------------------------------------------------------------- /src/web-vue/src/store/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import createPersistedState from 'vuex-persistedstate'; 4 | import mutations from './mutations/mutations'; 5 | import actions from './actions'; 6 | import defaultState from './defaultState'; 7 | 8 | Vue.use(Vuex); 9 | 10 | export default new Vuex.Store({ 11 | plugins: [createPersistedState()], 12 | state: defaultState, 13 | mutations: mutations, 14 | actions: actions, 15 | }); 16 | -------------------------------------------------------------------------------- /src/web-vue/src/store/templates/policyFooterTemplate.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | 3 | --=================== END: {{schemaName}}.{{tableName}} =================== 4 | `; 5 | -------------------------------------------------------------------------------- /src/web-vue/src/store/templates/policyHeaderTemplate.js: -------------------------------------------------------------------------------- 1 | module.exports = ` 2 | --=================== BEGIN: {{schemaName}}.{{tableName}} =================== 3 | 4 | `; 5 | -------------------------------------------------------------------------------- /src/web-vue/src/store/templates/roleTableGrantTemplate.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphile-contrib/pgdbi/47d3b0454fde69836e99a388f88b00a8463f4285/src/web-vue/src/store/templates/roleTableGrantTemplate.js -------------------------------------------------------------------------------- /src/web-vue/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/web-vue/src/views/ForeignKeyIndexView.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /src/web-vue/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 37 | 38 | 41 | -------------------------------------------------------------------------------- /src/web-vue/src/views/Initialize.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 84 | 85 | 88 | -------------------------------------------------------------------------------- /src/web-vue/src/views/RoleManagerView.vue: -------------------------------------------------------------------------------- 1 | 2 | 53 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /src/web-vue/src/views/SearchView.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/web-vue/src/views/SqitchView.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/web-vue/src/views/TableSecurityProfileDefinitionView.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /src/web-vue/src/views/TableSecurityProfileView.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 63 | 64 | 67 | -------------------------------------------------------------------------------- /src/web-vue/src/views/WorkerView.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/web-vue/test/blah.spec.js: -------------------------------------------------------------------------------- 1 | // mutations.spec.js 2 | import { expect } from 'chai'; 3 | import { mutations } from './store'; 4 | 5 | // destructure assign `mutations` 6 | const { resetDefaultState } = mutations; 7 | 8 | describe('resetDefaultState', () => { 9 | const state = {}; 10 | 11 | resetDefaultState(state); 12 | 13 | expect(state).to.be.an('Object'); 14 | }); 15 | -------------------------------------------------------------------------------- /src/web-vue/tsconfigs.json: -------------------------------------------------------------------------------- 1 | // tsconfig.json 2 | { 3 | "compilerOptions": { 4 | // this aligns with Vue's browser support 5 | "target": "es5", 6 | // this enables stricter inference for data properties on `this` 7 | "strict": true, 8 | // if using webpack 2+ or rollup, to leverage tree shaking: 9 | "module": "es2015", 10 | "moduleResolution": "node", 11 | "allowJs": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/web-vue/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: '/pgdbi/', 3 | pluginOptions: { 4 | apollo: { 5 | enableMocks: false, 6 | enableEngine: false, 7 | }, 8 | }, 9 | devServer: { 10 | proxy: { 11 | '/pgdbi/': { 12 | target: 'http://localhost:5099', 13 | }, 14 | }, 15 | }, 16 | configureWebpack: { 17 | devtool: 'source-map', 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | // Target latest version of ECMAScript. 5 | "target": "esnext", 6 | // Search under node_modules for non-relative imports. 7 | "moduleResolution": "node", 8 | // Process & infer types from .js files. 9 | "allowJs": true, 10 | // Don't emit; allow Babel to transform files. 11 | "noEmit": true, 12 | // Enable strictest settings like strictNullChecks & noImplicitAny. 13 | "strict": true, 14 | // Disallow features that require cross-file information for emit. 15 | "isolatedModules": true, 16 | // Import non-ES modules as default imports. 17 | "esModuleInterop": true 18 | }, 19 | "include": [ 20 | "./src/**/*" 21 | ] 22 | } --------------------------------------------------------------------------------