insforge 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +58 -0
- package/.env.example +49 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
- package/.github/copilot-instructions.md +147 -0
- package/.github/workflows/build-image.yml +65 -0
- package/.github/workflows/ci-premerge-check.yml +24 -0
- package/.github/workflows/deploy-aws.yml +130 -0
- package/.github/workflows/lint-and-format.yml +33 -0
- package/.prettierignore +65 -0
- package/.prettierrc +9 -0
- package/CHANGELOG.md +3 -0
- package/CONTRIBUTING.md +126 -0
- package/Dockerfile +27 -0
- package/GITHUB_OAUTH_SETUP.md +49 -0
- package/GOOGLE_OAUTH_SETUP.md +148 -0
- package/LICENSE +201 -0
- package/README.md +134 -0
- package/assets/Dark.svg +23 -0
- package/assets/archDiagram.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/mcpInstallv2.png +0 -0
- package/assets/sampleResponse.png +0 -0
- package/assets/signin.png +0 -0
- package/assets/userflow.png +0 -0
- package/backend/migrations/000_create-base-tables.sql +142 -0
- package/backend/migrations/001_create-helper-functions.sql +41 -0
- package/backend/migrations/002_rename-auth-tables.sql +30 -0
- package/backend/migrations/003_create-users-table.sql +56 -0
- package/backend/migrations/004_add-reload-postgrest-func.sql +24 -0
- package/backend/migrations/005_enable-project-admin-modify-users.sql +30 -0
- package/backend/migrations/006_modify-ai-usage-table.sql +25 -0
- package/backend/migrations/007_drop-metadata-table.sql +2 -0
- package/backend/migrations/008_add-system-tables.sql +77 -0
- package/backend/migrations/009_add-function-secrets.sql +24 -0
- package/backend/migrations/010_modify-ai-config-modalities.sql +93 -0
- package/backend/migrations/011_refactor-secrets-table.sql +15 -0
- package/backend/migrations/012_add-storage-uploaded-by.sql +8 -0
- package/backend/package.json +75 -0
- package/backend/src/api/middleware/auth.ts +240 -0
- package/backend/src/api/middleware/error.ts +231 -0
- package/backend/src/api/middleware/upload.ts +59 -0
- package/backend/src/api/routes/agent.ts +29 -0
- package/backend/src/api/routes/ai.ts +472 -0
- package/backend/src/api/routes/auth.oauth.ts +482 -0
- package/backend/src/api/routes/auth.ts +386 -0
- package/backend/src/api/routes/database.advance.ts +275 -0
- package/backend/src/api/routes/database.records.ts +246 -0
- package/backend/src/api/routes/database.tables.ts +161 -0
- package/backend/src/api/routes/docs.ts +66 -0
- package/backend/src/api/routes/functions.ts +183 -0
- package/backend/src/api/routes/logs.ts +150 -0
- package/backend/src/api/routes/metadata.ts +160 -0
- package/backend/src/api/routes/openapi.ts +82 -0
- package/backend/src/api/routes/secrets.ts +199 -0
- package/backend/src/api/routes/storage.ts +547 -0
- package/backend/src/api/routes/usage.ts +96 -0
- package/backend/src/core/ai/chat.ts +207 -0
- package/backend/src/core/ai/client.ts +242 -0
- package/backend/src/core/ai/config.ts +187 -0
- package/backend/src/core/ai/image.ts +156 -0
- package/backend/src/core/ai/model.ts +117 -0
- package/backend/src/core/ai/usage.ts +290 -0
- package/backend/src/core/auth/auth.ts +781 -0
- package/backend/src/core/auth/oauth.ts +398 -0
- package/backend/src/core/database/advance.ts +1074 -0
- package/backend/src/core/database/manager.ts +178 -0
- package/backend/src/core/database/table.ts +772 -0
- package/backend/src/core/documentation/agent.ts +689 -0
- package/backend/src/core/documentation/openapi.ts +856 -0
- package/backend/src/core/functions/functions.ts +310 -0
- package/backend/src/core/logs/analytics.ts +76 -0
- package/backend/src/core/logs/audit.ts +255 -0
- package/backend/src/core/logs/providers/base.provider.ts +83 -0
- package/backend/src/core/logs/providers/cloudwatch.provider.ts +510 -0
- package/backend/src/core/logs/providers/localdb.provider.ts +246 -0
- package/backend/src/core/secrets/encryption.ts +58 -0
- package/backend/src/core/secrets/secrets.ts +410 -0
- package/backend/src/core/socket/socket.ts +388 -0
- package/backend/src/core/socket/types.ts +79 -0
- package/backend/src/core/storage/storage.ts +923 -0
- package/backend/src/server.ts +288 -0
- package/backend/src/types/ai.ts +46 -0
- package/backend/src/types/auth.ts +90 -0
- package/backend/src/types/database.ts +136 -0
- package/backend/src/types/error-constants.ts +86 -0
- package/backend/src/types/logs.ts +47 -0
- package/backend/src/types/profile.ts +55 -0
- package/backend/src/types/storage.ts +23 -0
- package/backend/src/utils/cloud-token.ts +39 -0
- package/backend/src/utils/constants.ts +1 -0
- package/backend/src/utils/environment.ts +35 -0
- package/backend/src/utils/helpers.ts +49 -0
- package/backend/src/utils/logger.ts +13 -0
- package/backend/src/utils/response.ts +62 -0
- package/backend/src/utils/seed.ts +205 -0
- package/backend/src/utils/sql-parser.ts +63 -0
- package/backend/src/utils/uuid.ts +9 -0
- package/backend/src/utils/validations.ts +129 -0
- package/backend/tests/README.md +134 -0
- package/backend/tests/cleanup-all-test-data.sh +231 -0
- package/backend/tests/cloud/test-s3-multitenant.sh +132 -0
- package/backend/tests/local/comprehensive-curl-tests.sh +156 -0
- package/backend/tests/local/test-auth-router.sh +144 -0
- package/backend/tests/local/test-database-router.sh +222 -0
- package/backend/tests/local/test-e2e.sh +241 -0
- package/backend/tests/local/test-fk-errors.sh +97 -0
- package/backend/tests/local/test-id-field.sh +201 -0
- package/backend/tests/local/test-public-bucket.sh +265 -0
- package/backend/tests/local/test-secrets.sh +248 -0
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -0
- package/backend/tests/local/test-traditional-rest.sh +209 -0
- package/backend/tests/manual/README.md +51 -0
- package/backend/tests/manual/create-large-table-simple.sql +11 -0
- package/backend/tests/manual/seed-large-table.sql +101 -0
- package/backend/tests/manual/setup-large-table-extras.sql +34 -0
- package/backend/tests/manual/test-better-auth.sh +303 -0
- package/backend/tests/manual/test-bulk-upsert.sh +410 -0
- package/backend/tests/manual/test-database-advance.sh +297 -0
- package/backend/tests/manual/test-postgrest-stability.sh +192 -0
- package/backend/tests/manual/test-rawsql-export-import.sh +412 -0
- package/backend/tests/manual/test-universal-storage.sh +264 -0
- package/backend/tests/manual/test-users.sql +18 -0
- package/backend/tests/run-all-tests.sh +140 -0
- package/backend/tests/setup.ts +22 -0
- package/backend/tests/test-config.sh +303 -0
- package/backend/tsconfig.json +23 -0
- package/backend/tsup.config.ts +18 -0
- package/backend/vitest.config.ts +22 -0
- package/docker-compose.prod.yml +145 -0
- package/docker-compose.yml +167 -0
- package/docker-init/db/db-init.sql +125 -0
- package/docker-init/db/jwt.sql +5 -0
- package/docker-init/db/logs.sql +9 -0
- package/docker-init/db/postgresql.conf +17 -0
- package/docs/deprecated/insforge-auth-api.md +215 -0
- package/docs/deprecated/insforge-auth-sdk.md +100 -0
- package/docs/deprecated/insforge-db-api.md +359 -0
- package/docs/deprecated/insforge-db-sdk.md +140 -0
- package/docs/deprecated/insforge-debug-sdk.md +157 -0
- package/docs/deprecated/insforge-debug.md +65 -0
- package/docs/deprecated/insforge-instructions.md +124 -0
- package/docs/deprecated/insforge-project.md +118 -0
- package/docs/deprecated/insforge-storage-api.md +279 -0
- package/docs/deprecated/insforge-storage-sdk.md +159 -0
- package/docs/insforge-instructions-sdk.md +407 -0
- package/eslint.config.js +317 -0
- package/examples/oauth/frontend-oauth-example.html +251 -0
- package/examples/response-examples.md +444 -0
- package/frontend/README.md +112 -0
- package/frontend/components.json +17 -0
- package/frontend/index.html +13 -0
- package/frontend/package.json +63 -0
- package/frontend/public/favicon.ico +0 -0
- package/frontend/src/App.tsx +106 -0
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -0
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -0
- package/frontend/src/assets/icons/checked.svg +3 -0
- package/frontend/src/assets/icons/error.svg +3 -0
- package/frontend/src/assets/icons/pencil.svg +4 -0
- package/frontend/src/assets/icons/refresh.svg +4 -0
- package/frontend/src/assets/icons/step_active.svg +3 -0
- package/frontend/src/assets/icons/step_inactive.svg +11 -0
- package/frontend/src/assets/icons/warning.svg +3 -0
- package/frontend/src/assets/logos/amazon.svg +1 -0
- package/frontend/src/assets/logos/claude_code.svg +3 -0
- package/frontend/src/assets/logos/cline.svg +6 -0
- package/frontend/src/assets/logos/cursor.svg +20 -0
- package/frontend/src/assets/logos/discord.svg +9 -0
- package/frontend/src/assets/logos/gemini.svg +19 -0
- package/frontend/src/assets/logos/github.svg +5 -0
- package/frontend/src/assets/logos/google.svg +13 -0
- package/frontend/src/assets/logos/grok.svg +10 -0
- package/frontend/src/assets/logos/insforge_dark.svg +15 -0
- package/frontend/src/assets/logos/insforge_light.svg +15 -0
- package/frontend/src/assets/logos/openai.svg +10 -0
- package/frontend/src/assets/logos/roo_code.svg +9 -0
- package/frontend/src/assets/logos/trae.svg +3 -0
- package/frontend/src/assets/logos/windsurf.svg +10 -0
- package/frontend/src/components/ButtonWithLoading.tsx +27 -0
- package/frontend/src/components/Checkbox.tsx +61 -0
- package/frontend/src/components/CodeBlock.tsx +32 -0
- package/frontend/src/components/ConfirmDialog.tsx +96 -0
- package/frontend/src/components/CopyButton.tsx +69 -0
- package/frontend/src/components/DeleteActionButton.tsx +42 -0
- package/frontend/src/components/EmptyState.tsx +41 -0
- package/frontend/src/components/ErrorState.tsx +35 -0
- package/frontend/src/components/FeatureSidebar.tsx +126 -0
- package/frontend/src/components/FeatureSidebarItem.tsx +101 -0
- package/frontend/src/components/JsonHighlight.tsx +61 -0
- package/frontend/src/components/LoadingState.tsx +16 -0
- package/frontend/src/components/PaginationControls.tsx +54 -0
- package/frontend/src/components/PromptDialog.tsx +68 -0
- package/frontend/src/components/SearchInput.tsx +90 -0
- package/frontend/src/components/SelectionClearButton.tsx +26 -0
- package/frontend/src/components/Stepper.tsx +139 -0
- package/frontend/src/components/ThemeToggle.tsx +58 -0
- package/frontend/src/components/TypeBadge.tsx +20 -0
- package/frontend/src/components/datagrid/DataGrid.tsx +264 -0
- package/frontend/src/components/datagrid/DefaultCellRenderer.tsx +114 -0
- package/frontend/src/components/datagrid/IdCell.tsx +44 -0
- package/frontend/src/components/datagrid/SortableHeader.tsx +74 -0
- package/frontend/src/components/datagrid/cell-editors/BooleanCellEditor.tsx +54 -0
- package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +483 -0
- package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +362 -0
- package/frontend/src/components/datagrid/cell-editors/TextCellEditor.tsx +38 -0
- package/frontend/src/components/datagrid/cell-editors/index.ts +14 -0
- package/frontend/src/components/datagrid/cell-editors/types.ts +43 -0
- package/frontend/src/components/datagrid/datagridTypes.tsx +72 -0
- package/frontend/src/components/datagrid/index.tsx +20 -0
- package/frontend/src/components/index.ts +39 -0
- package/frontend/src/components/layout/AppHeader.tsx +146 -0
- package/frontend/src/components/layout/AppSidebar.tsx +190 -0
- package/frontend/src/components/layout/CloudLayout.tsx +95 -0
- package/frontend/src/components/layout/Layout.tsx +43 -0
- package/frontend/src/components/radix/Alert.tsx +45 -0
- package/frontend/src/components/radix/AlertDialog.tsx +115 -0
- package/frontend/src/components/radix/Avatar.tsx +45 -0
- package/frontend/src/components/radix/Badge.tsx +33 -0
- package/frontend/src/components/radix/Button.tsx +50 -0
- package/frontend/src/components/radix/Card.tsx +58 -0
- package/frontend/src/components/radix/Dialog.tsx +98 -0
- package/frontend/src/components/radix/DropdownMenu.tsx +185 -0
- package/frontend/src/components/radix/Form.tsx +167 -0
- package/frontend/src/components/radix/Input.tsx +22 -0
- package/frontend/src/components/radix/Label.tsx +19 -0
- package/frontend/src/components/radix/Popover.tsx +29 -0
- package/frontend/src/components/radix/ScrollArea.tsx +44 -0
- package/frontend/src/components/radix/Select.tsx +151 -0
- package/frontend/src/components/radix/Separator.tsx +26 -0
- package/frontend/src/components/radix/Sheet.tsx +119 -0
- package/frontend/src/components/radix/Skeleton.tsx +7 -0
- package/frontend/src/components/radix/Switch.tsx +29 -0
- package/frontend/src/components/radix/Tabs.tsx +50 -0
- package/frontend/src/components/radix/Textarea.tsx +21 -0
- package/frontend/src/components/radix/Tooltip.tsx +28 -0
- package/frontend/src/features/ai/components/AIConfigCard.tsx +154 -0
- package/frontend/src/features/ai/components/AIConfigDialog.tsx +76 -0
- package/frontend/src/features/ai/components/AIConfigForm.tsx +222 -0
- package/frontend/src/features/ai/components/AIEmptyState.tsx +18 -0
- package/frontend/src/features/ai/components/fields/ModalityField.tsx +87 -0
- package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +134 -0
- package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +33 -0
- package/frontend/src/features/ai/helpers.ts +155 -0
- package/frontend/src/features/ai/hooks/useAIConfigs.ts +221 -0
- package/frontend/src/features/ai/hooks/useAIUsage.ts +77 -0
- package/frontend/src/features/ai/page/AIPage.tsx +178 -0
- package/frontend/src/features/ai/services/ai.service.ts +148 -0
- package/frontend/src/features/auth/components/AddOAuthDialog.tsx +106 -0
- package/frontend/src/features/auth/components/AuthMethodTab.tsx +238 -0
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +303 -0
- package/frontend/src/features/auth/components/OAuthEmptyState.tsx +15 -0
- package/frontend/src/features/auth/components/UserFormDialog.tsx +248 -0
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +183 -0
- package/frontend/src/features/auth/components/UsersTab.tsx +114 -0
- package/frontend/src/features/auth/hooks/useOAuthConfig.ts +129 -0
- package/frontend/src/features/auth/hooks/useUsers.ts +57 -0
- package/frontend/src/features/auth/index.ts +9 -0
- package/frontend/src/features/auth/page/AuthenticationPage.tsx +169 -0
- package/frontend/src/features/auth/services/auth.service.ts +112 -0
- package/frontend/src/features/auth/services/oauth.service.ts +49 -0
- package/frontend/src/features/dashboard/page/DashboardPage.tsx +194 -0
- package/frontend/src/features/database/components/ColumnTypeSelect.tsx +64 -0
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +282 -0
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +187 -0
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +378 -0
- package/frontend/src/features/database/components/LinkRecordModal.tsx +288 -0
- package/frontend/src/features/database/components/RecordFormDialog.tsx +164 -0
- package/frontend/src/features/database/components/RecordFormField.tsx +568 -0
- package/frontend/src/features/database/components/TableEmptyState.tsx +21 -0
- package/frontend/src/features/database/components/TableForm.tsx +656 -0
- package/frontend/src/features/database/components/TableFormColumn.tsx +137 -0
- package/frontend/src/features/database/components/TableListSkeleton.tsx +9 -0
- package/frontend/src/features/database/components/TableSidebar.tsx +47 -0
- package/frontend/src/features/database/constants.ts +26 -0
- package/frontend/src/features/database/helpers.ts +125 -0
- package/frontend/src/features/database/hooks/UseLinkModal.tsx +78 -0
- package/frontend/src/features/database/index.ts +12 -0
- package/frontend/src/features/database/page/DatabasePage.tsx +626 -0
- package/frontend/src/features/database/schema.ts +25 -0
- package/frontend/src/features/database/services/database.service.ts +216 -0
- package/frontend/src/features/functions/components/FunctionEmptyState.tsx +15 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +71 -0
- package/frontend/src/features/functions/components/FunctionViewer.tsx +46 -0
- package/frontend/src/features/functions/components/FunctionsContent.tsx +88 -0
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -0
- package/frontend/src/features/functions/components/SecretEmptyState.tsx +23 -0
- package/frontend/src/features/functions/components/SecretRow.tsx +68 -0
- package/frontend/src/features/functions/components/SecretsContent.tsx +120 -0
- package/frontend/src/features/functions/hooks/useFunctions.ts +106 -0
- package/frontend/src/features/functions/page/FunctionsPage.tsx +28 -0
- package/frontend/src/features/functions/services/functions.service.ts +48 -0
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +87 -0
- package/frontend/src/features/login/components/PrivateRoute.tsx +24 -0
- package/frontend/src/features/login/page/CloudLoginPage.tsx +93 -0
- package/frontend/src/features/login/page/LoginPage.tsx +174 -0
- package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +313 -0
- package/frontend/src/features/logs/components/LogsTable.tsx +199 -0
- package/frontend/src/features/logs/hooks/useAuditLogs.ts +39 -0
- package/frontend/src/features/logs/index.ts +5 -0
- package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +530 -0
- package/frontend/src/features/logs/page/AuditsPage.tsx +192 -0
- package/frontend/src/features/logs/services/log.service.ts +171 -0
- package/frontend/src/features/metadata/hooks/useMetadata.ts +53 -0
- package/frontend/src/features/metadata/index.ts +0 -0
- package/frontend/src/features/metadata/page/MetadataPage.tsx +136 -0
- package/frontend/src/features/metadata/services/metadata.service.ts +17 -0
- package/frontend/src/features/onboard/components/CompletionCard.tsx +41 -0
- package/frontend/src/features/onboard/components/OnboardButton.tsx +84 -0
- package/frontend/src/features/onboard/components/StepContent.tsx +91 -0
- package/frontend/src/features/onboard/components/TestConnectionStep.tsx +53 -0
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +35 -0
- package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +144 -0
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -0
- package/frontend/src/features/onboard/components/mcp/mcp-helper.tsx +98 -0
- package/frontend/src/features/onboard/index.ts +3 -0
- package/frontend/src/features/onboard/page/OnBoardPage.tsx +104 -0
- package/frontend/src/features/onboard/types.ts +8 -0
- package/frontend/src/features/secrets/hooks/useSecrets.ts +139 -0
- package/frontend/src/features/secrets/services/secrets.service.ts +57 -0
- package/frontend/src/features/storage/components/BucketEmptyState.tsx +19 -0
- package/frontend/src/features/storage/components/BucketFormDialog.tsx +194 -0
- package/frontend/src/features/storage/components/BucketListSkeleton.tsx +17 -0
- package/frontend/src/features/storage/components/FilePreviewDialog.tsx +287 -0
- package/frontend/src/features/storage/components/StorageDataGrid.tsx +239 -0
- package/frontend/src/features/storage/components/StorageManager.tsx +236 -0
- package/frontend/src/features/storage/components/StorageSidebar.tsx +44 -0
- package/frontend/src/features/storage/components/UploadToast.tsx +46 -0
- package/frontend/src/features/storage/index.ts +3 -0
- package/frontend/src/features/storage/page/StoragePage.tsx +553 -0
- package/frontend/src/features/storage/services/storage.service.ts +144 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +107 -0
- package/frontend/src/features/visualizer/components/BucketNode.tsx +34 -0
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +359 -0
- package/frontend/src/features/visualizer/components/TableNode.tsx +152 -0
- package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +24 -0
- package/frontend/src/features/visualizer/components/index.ts +5 -0
- package/frontend/src/features/visualizer/page/VisualizerPage.tsx +127 -0
- package/frontend/src/index.css +248 -0
- package/frontend/src/lib/api/client.ts +163 -0
- package/frontend/src/lib/contexts/AuthContext.tsx +157 -0
- package/frontend/src/lib/contexts/OnboardStepContext.tsx +68 -0
- package/frontend/src/lib/contexts/SocketContext.tsx +303 -0
- package/frontend/src/lib/contexts/ThemeContext.tsx +125 -0
- package/frontend/src/lib/hooks/useAuth.ts +4 -0
- package/frontend/src/lib/hooks/useConfirm.ts +55 -0
- package/frontend/src/lib/hooks/useInterval.ts +27 -0
- package/frontend/src/lib/hooks/useMediaQuery.ts +59 -0
- package/frontend/src/lib/hooks/useOnboardingCompletion.ts +29 -0
- package/frontend/src/lib/hooks/usePagination.ts +27 -0
- package/frontend/src/lib/hooks/useTimeout.ts +27 -0
- package/frontend/src/lib/hooks/useToast.tsx +229 -0
- package/frontend/src/lib/utils/constants.ts +38 -0
- package/frontend/src/lib/utils/utils.ts +165 -0
- package/frontend/src/lib/utils/validation-schemas.ts +126 -0
- package/frontend/src/main.tsx +16 -0
- package/frontend/src/rdg.css +194 -0
- package/frontend/src/vite-env.d.ts +12 -0
- package/frontend/tailwind.config.js +97 -0
- package/frontend/tsconfig.json +26 -0
- package/frontend/tsconfig.node.json +10 -0
- package/frontend/vite.config.ts +37 -0
- package/frontend/vitest.config.ts +36 -0
- package/functions/deno.json +25 -0
- package/functions/server.ts +290 -0
- package/functions/worker-template.js +126 -0
- package/openapi/ai.yaml +689 -0
- package/openapi/auth.yaml +563 -0
- package/openapi/functions.yaml +476 -0
- package/openapi/health.yaml +30 -0
- package/openapi/logs.yaml +224 -0
- package/openapi/metadata.yaml +178 -0
- package/openapi/records.yaml +382 -0
- package/openapi/secrets.yaml +371 -0
- package/openapi/storage.yaml +876 -0
- package/openapi/tables.yaml +464 -0
- package/package.json +88 -0
- package/shared-schemas/package.json +31 -0
- package/shared-schemas/src/ai-api.schema.ts +167 -0
- package/shared-schemas/src/ai.schema.ts +54 -0
- package/shared-schemas/src/auth-api.schema.ts +193 -0
- package/shared-schemas/src/auth.schema.ts +94 -0
- package/shared-schemas/src/database-api.schema.ts +259 -0
- package/shared-schemas/src/database.schema.ts +69 -0
- package/shared-schemas/src/functions-api.schema.ts +25 -0
- package/shared-schemas/src/functions.schema.ts +16 -0
- package/shared-schemas/src/index.ts +13 -0
- package/shared-schemas/src/logs-api.schema.ts +49 -0
- package/shared-schemas/src/logs.schema.ts +14 -0
- package/shared-schemas/src/metadata.schema.ts +56 -0
- package/shared-schemas/src/storage-api.schema.ts +65 -0
- package/shared-schemas/src/storage.schema.ts +19 -0
- package/shared-schemas/tsconfig.json +21 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Bulk Upsert Feature Test Script
|
|
4
|
+
# Tests CSV/JSON bulk imports with various edge cases and upsert scenarios
|
|
5
|
+
|
|
6
|
+
# Get the directory where this script is located
|
|
7
|
+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
8
|
+
|
|
9
|
+
# Source the test configuration
|
|
10
|
+
source "$SCRIPT_DIR/../test-config.sh"
|
|
11
|
+
|
|
12
|
+
echo "🧪 Testing bulk upsert feature..."
|
|
13
|
+
echo "================================"
|
|
14
|
+
|
|
15
|
+
# Configuration
|
|
16
|
+
# Remove /api if it's already included in TEST_API_BASE
|
|
17
|
+
if [[ "$TEST_API_BASE" == */api ]]; then
|
|
18
|
+
API_BASE="$TEST_API_BASE"
|
|
19
|
+
else
|
|
20
|
+
API_BASE="${TEST_API_BASE}/api"
|
|
21
|
+
fi
|
|
22
|
+
ADMIN_EMAIL="$TEST_ADMIN_EMAIL"
|
|
23
|
+
ADMIN_PASSWORD="$TEST_ADMIN_PASSWORD"
|
|
24
|
+
AUTH_TOKEN=""
|
|
25
|
+
|
|
26
|
+
# Dynamic table name to avoid conflicts
|
|
27
|
+
TEST_TABLE="test_bulk_upsert_$(date +%s)"
|
|
28
|
+
DATA_DIR="$SCRIPT_DIR/test-data/bulk-upsert"
|
|
29
|
+
|
|
30
|
+
# Create test data directory
|
|
31
|
+
mkdir -p "$DATA_DIR"
|
|
32
|
+
|
|
33
|
+
# Helper function to create test files
|
|
34
|
+
create_test_files() {
|
|
35
|
+
echo "📁 Creating test data files..."
|
|
36
|
+
|
|
37
|
+
# 1. Basic CSV file
|
|
38
|
+
cat > "$DATA_DIR/products.csv" << 'EOF'
|
|
39
|
+
sku,name,price,quantity,active
|
|
40
|
+
PROD-001,Laptop Computer,1299.99,50,true
|
|
41
|
+
PROD-002,Wireless Mouse,29.99,200,true
|
|
42
|
+
PROD-003,USB-C Cable,19.99,500,false
|
|
43
|
+
PROD-004,Monitor Stand,79.99,100,true
|
|
44
|
+
PROD-005,Keyboard,89.99,150,true
|
|
45
|
+
EOF
|
|
46
|
+
|
|
47
|
+
# 2. CSV with special characters
|
|
48
|
+
cat > "$DATA_DIR/special-chars.csv" << 'EOF'
|
|
49
|
+
sku,name,description,price
|
|
50
|
+
SPEC-001,"Product with ""quotes""","Description with ""quoted text""",99.99
|
|
51
|
+
SPEC-002,"Product, with comma","Has a comma, in the name",149.99
|
|
52
|
+
SPEC-003,"Multi-line
|
|
53
|
+
Product","Description
|
|
54
|
+
spans multiple
|
|
55
|
+
lines",199.99
|
|
56
|
+
SPEC-004,"Special & < > chars","Contains & < > $ % characters",49.99
|
|
57
|
+
EOF
|
|
58
|
+
|
|
59
|
+
# 3. CSV for upsert testing (contains duplicates)
|
|
60
|
+
cat > "$DATA_DIR/upsert-test.csv" << 'EOF'
|
|
61
|
+
sku,name,price,quantity,active
|
|
62
|
+
PROD-001,Updated Laptop,1399.99,45,true
|
|
63
|
+
PROD-002,Updated Mouse,34.99,180,false
|
|
64
|
+
PROD-006,New Headphones,149.99,75,true
|
|
65
|
+
EOF
|
|
66
|
+
|
|
67
|
+
# 4. JSON array file
|
|
68
|
+
cat > "$DATA_DIR/products.json" << 'EOF'
|
|
69
|
+
[
|
|
70
|
+
{
|
|
71
|
+
"sku": "JSON-001",
|
|
72
|
+
"name": "Smart Watch",
|
|
73
|
+
"price": 299.99,
|
|
74
|
+
"quantity": 30,
|
|
75
|
+
"active": true,
|
|
76
|
+
"metadata": {
|
|
77
|
+
"brand": "TechCo",
|
|
78
|
+
"warranty": "2 years"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"sku": "JSON-002",
|
|
83
|
+
"name": "Bluetooth Speaker",
|
|
84
|
+
"price": 89.99,
|
|
85
|
+
"quantity": 100,
|
|
86
|
+
"active": true,
|
|
87
|
+
"metadata": {
|
|
88
|
+
"color": "black",
|
|
89
|
+
"waterproof": true
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"sku": "JSON-003",
|
|
94
|
+
"name": "Phone Case",
|
|
95
|
+
"price": 24.99,
|
|
96
|
+
"quantity": 250,
|
|
97
|
+
"active": false,
|
|
98
|
+
"metadata": null
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
EOF
|
|
102
|
+
|
|
103
|
+
# 5. Single JSON object
|
|
104
|
+
cat > "$DATA_DIR/single-product.json" << 'EOF'
|
|
105
|
+
{
|
|
106
|
+
"sku": "SINGLE-001",
|
|
107
|
+
"name": "Premium Subscription",
|
|
108
|
+
"price": 99.99,
|
|
109
|
+
"quantity": 999,
|
|
110
|
+
"active": true,
|
|
111
|
+
"metadata": {
|
|
112
|
+
"type": "subscription",
|
|
113
|
+
"duration": "annual"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
EOF
|
|
117
|
+
|
|
118
|
+
# 6. CSV with NULL values
|
|
119
|
+
cat > "$DATA_DIR/null-values.csv" << 'EOF'
|
|
120
|
+
sku,name,price,quantity,active
|
|
121
|
+
NULL-001,,99.99,,true
|
|
122
|
+
NULL-002,Product with nulls,,,false
|
|
123
|
+
NULL-003,Only SKU and Name,,,
|
|
124
|
+
NULL-004,Complete Product,49.99,25,true
|
|
125
|
+
EOF
|
|
126
|
+
|
|
127
|
+
# 7. Large CSV file (1000 rows)
|
|
128
|
+
echo "sku,name,price,quantity,active" > "$DATA_DIR/large-dataset.csv"
|
|
129
|
+
for i in $(seq 1 1000); do
|
|
130
|
+
echo "LARGE-$(printf %04d $i),Product $i,$(echo "scale=2; $RANDOM/100" | bc),$(($RANDOM % 1000)),true" >> "$DATA_DIR/large-dataset.csv"
|
|
131
|
+
done
|
|
132
|
+
|
|
133
|
+
# 8. CSV with Unicode/Emoji
|
|
134
|
+
cat > "$DATA_DIR/unicode.csv" << 'EOF'
|
|
135
|
+
sku,name,price,quantity,description
|
|
136
|
+
UNI-001,Café ☕ Français,15.99,100,Délicieux café
|
|
137
|
+
UNI-002,寿司 🍣 セット,35.99,50,新鮮な魚
|
|
138
|
+
UNI-003,Москва 🇷🇺 Souvenir,25.99,75,Русский сувенир
|
|
139
|
+
UNI-004,🚀 Rocket Toy,19.99,200,Fun emoji product 🎉
|
|
140
|
+
EOF
|
|
141
|
+
|
|
142
|
+
# 9. Invalid CSV (for error testing)
|
|
143
|
+
cat > "$DATA_DIR/invalid.csv" << 'EOF'
|
|
144
|
+
sku,name,price
|
|
145
|
+
INV-001,Product 1,99.99,Extra Column
|
|
146
|
+
INV-002,Missing Price
|
|
147
|
+
INV-003
|
|
148
|
+
EOF
|
|
149
|
+
|
|
150
|
+
# 10. Empty files
|
|
151
|
+
touch "$DATA_DIR/empty.csv"
|
|
152
|
+
echo "[]" > "$DATA_DIR/empty.json"
|
|
153
|
+
|
|
154
|
+
echo "✅ Test files created"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Function to login as admin
|
|
158
|
+
login_admin() {
|
|
159
|
+
echo "🔐 Logging in as admin..."
|
|
160
|
+
|
|
161
|
+
# First check if backend is running
|
|
162
|
+
if ! curl -s "$API_BASE/health" > /dev/null 2>&1; then
|
|
163
|
+
echo "❌ Backend server is not running!"
|
|
164
|
+
echo " Please start the backend first:"
|
|
165
|
+
echo " cd backend && npm run dev"
|
|
166
|
+
exit 1
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
local response=$(curl -s -X POST "$API_BASE/auth/admin/sessions" \
|
|
170
|
+
-H "Content-Type: application/json" \
|
|
171
|
+
-d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}")
|
|
172
|
+
|
|
173
|
+
AUTH_TOKEN=$(echo "$response" | grep -o '"accessToken":"[^"]*' | cut -d'"' -f4)
|
|
174
|
+
|
|
175
|
+
if [ -z "$AUTH_TOKEN" ]; then
|
|
176
|
+
echo "❌ Failed to login as admin"
|
|
177
|
+
echo " Response: $response"
|
|
178
|
+
echo ""
|
|
179
|
+
echo " Make sure you have the correct admin credentials:"
|
|
180
|
+
echo " Email: $ADMIN_EMAIL"
|
|
181
|
+
echo " Password: $ADMIN_PASSWORD"
|
|
182
|
+
echo ""
|
|
183
|
+
echo " You can set these with environment variables:"
|
|
184
|
+
echo " TEST_ADMIN_EMAIL=your@email.com TEST_ADMIN_PASSWORD=yourpassword ./test-bulk-upsert.sh"
|
|
185
|
+
exit 1
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
echo "✅ Admin login successful"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# Function to create test table
|
|
192
|
+
create_test_table() {
|
|
193
|
+
echo "📊 Creating test table: $TEST_TABLE"
|
|
194
|
+
|
|
195
|
+
local response=$(curl -s -X POST "$API_BASE/database/advance/rawsql" \
|
|
196
|
+
-H "Authorization: Bearer $AUTH_TOKEN" \
|
|
197
|
+
-H "Content-Type: application/json" \
|
|
198
|
+
-d "{\"query\": \"CREATE TABLE $TEST_TABLE (id SERIAL PRIMARY KEY, sku VARCHAR(50) UNIQUE, name VARCHAR(255), description TEXT, price DECIMAL(10,2), quantity INTEGER, active BOOLEAN, metadata JSONB)\"}")
|
|
199
|
+
|
|
200
|
+
if echo "$response" | grep -q "error"; then
|
|
201
|
+
echo "❌ Failed to create table: $response"
|
|
202
|
+
exit 1
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
echo "✅ Table created successfully"
|
|
206
|
+
|
|
207
|
+
# Register table for cleanup
|
|
208
|
+
register_test_table "$TEST_TABLE"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Function to test bulk upsert
|
|
212
|
+
test_bulk_upsert() {
|
|
213
|
+
local file_name=$1
|
|
214
|
+
local table=$2
|
|
215
|
+
local upsert_key=$3
|
|
216
|
+
local description=$4
|
|
217
|
+
local expect_failure=${5:-false}
|
|
218
|
+
|
|
219
|
+
if [ "$expect_failure" != "true" ]; then
|
|
220
|
+
echo ""
|
|
221
|
+
echo "🧪 Test: $description"
|
|
222
|
+
echo " File: $file_name"
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Build form data
|
|
226
|
+
local curl_cmd="curl -s -X POST \"$API_BASE/database/advance/bulk-upsert\" \
|
|
227
|
+
-H \"Authorization: Bearer $AUTH_TOKEN\" \
|
|
228
|
+
-F \"file=@$DATA_DIR/$file_name\" \
|
|
229
|
+
-F \"table=$table\""
|
|
230
|
+
|
|
231
|
+
if [ ! -z "$upsert_key" ]; then
|
|
232
|
+
curl_cmd="$curl_cmd -F \"upsertKey=$upsert_key\""
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
local response=$(eval $curl_cmd)
|
|
236
|
+
|
|
237
|
+
if echo "$response" | grep -q "\"success\":true"; then
|
|
238
|
+
local rows=$(echo "$response" | grep -o '"rowsAffected":[0-9]*' | cut -d':' -f2)
|
|
239
|
+
local total=$(echo "$response" | grep -o '"totalRecords":[0-9]*' | cut -d':' -f2)
|
|
240
|
+
if [ "$expect_failure" != "true" ]; then
|
|
241
|
+
echo " ✅ Success: $rows/$total rows inserted"
|
|
242
|
+
fi
|
|
243
|
+
return 0
|
|
244
|
+
else
|
|
245
|
+
local error=$(echo "$response" | grep -o '"message":"[^"]*' | cut -d'"' -f4)
|
|
246
|
+
if [ "$expect_failure" != "true" ]; then
|
|
247
|
+
echo " ⚠️ Expected error: $error"
|
|
248
|
+
fi
|
|
249
|
+
return 1
|
|
250
|
+
fi
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# Function to verify data
|
|
254
|
+
verify_data() {
|
|
255
|
+
local expected_count=$1
|
|
256
|
+
local description=$2
|
|
257
|
+
|
|
258
|
+
echo ""
|
|
259
|
+
echo "🔍 Verifying: $description"
|
|
260
|
+
|
|
261
|
+
local response=$(curl -s -X POST "$API_BASE/database/advance/rawsql" \
|
|
262
|
+
-H "Authorization: Bearer $AUTH_TOKEN" \
|
|
263
|
+
-H "Content-Type: application/json" \
|
|
264
|
+
-d "{\"query\": \"SELECT COUNT(*) as count FROM $TEST_TABLE\"}")
|
|
265
|
+
|
|
266
|
+
local actual_count=$(echo "$response" | grep -o '"count":"[0-9]*' | cut -d'"' -f4)
|
|
267
|
+
|
|
268
|
+
if [ "$actual_count" = "$expected_count" ]; then
|
|
269
|
+
echo " ✅ Correct: $actual_count rows in table"
|
|
270
|
+
else
|
|
271
|
+
echo " ❌ Mismatch: Expected $expected_count, got $actual_count"
|
|
272
|
+
return 1
|
|
273
|
+
fi
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
# Function to check specific data
|
|
277
|
+
check_data() {
|
|
278
|
+
local query=$1
|
|
279
|
+
local expected=$2
|
|
280
|
+
local description=$3
|
|
281
|
+
|
|
282
|
+
echo " 🔍 $description"
|
|
283
|
+
|
|
284
|
+
local response=$(curl -s -X POST "$API_BASE/database/advance/rawsql" \
|
|
285
|
+
-H "Authorization: Bearer $AUTH_TOKEN" \
|
|
286
|
+
-H "Content-Type: application/json" \
|
|
287
|
+
-d "{\"query\": \"$query\"}")
|
|
288
|
+
|
|
289
|
+
if echo "$response" | grep -q "$expected"; then
|
|
290
|
+
echo " ✅ Found: $expected"
|
|
291
|
+
else
|
|
292
|
+
echo " ❌ Not found: $expected"
|
|
293
|
+
echo " Response: $response"
|
|
294
|
+
fi
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# Cleanup function
|
|
298
|
+
cleanup() {
|
|
299
|
+
echo ""
|
|
300
|
+
echo "🧹 Cleaning up..."
|
|
301
|
+
|
|
302
|
+
# Drop test table
|
|
303
|
+
curl -s -X POST "$API_BASE/database/advance/rawsql" \
|
|
304
|
+
-H "Authorization: Bearer $AUTH_TOKEN" \
|
|
305
|
+
-H "Content-Type: application/json" \
|
|
306
|
+
-d "{\"query\": \"DROP TABLE IF EXISTS $TEST_TABLE CASCADE\"}" > /dev/null
|
|
307
|
+
|
|
308
|
+
# Remove test data directory
|
|
309
|
+
rm -rf "$DATA_DIR"
|
|
310
|
+
|
|
311
|
+
echo "✅ Cleanup complete"
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# Main test execution
|
|
315
|
+
main() {
|
|
316
|
+
# Setup
|
|
317
|
+
create_test_files
|
|
318
|
+
login_admin
|
|
319
|
+
create_test_table
|
|
320
|
+
|
|
321
|
+
echo ""
|
|
322
|
+
echo "="
|
|
323
|
+
echo "🚀 RUNNING BULK UPSERT TESTS"
|
|
324
|
+
echo "="
|
|
325
|
+
|
|
326
|
+
# Test 1: Basic CSV import
|
|
327
|
+
test_bulk_upsert "products.csv" "$TEST_TABLE" "" "Basic CSV Import"
|
|
328
|
+
verify_data 5 "5 products imported"
|
|
329
|
+
|
|
330
|
+
# Test 2: JSON array import
|
|
331
|
+
test_bulk_upsert "products.json" "$TEST_TABLE" "sku" "JSON Array Import (with upsert)"
|
|
332
|
+
verify_data 8 "3 new products added"
|
|
333
|
+
|
|
334
|
+
# Test 3: Single JSON object
|
|
335
|
+
test_bulk_upsert "single-product.json" "$TEST_TABLE" "sku" "Single JSON Object"
|
|
336
|
+
verify_data 9 "1 product added"
|
|
337
|
+
|
|
338
|
+
# Test 4: CSV with special characters
|
|
339
|
+
test_bulk_upsert "special-chars.csv" "$TEST_TABLE" "sku" "Special Characters in CSV"
|
|
340
|
+
verify_data 13 "4 products with special chars"
|
|
341
|
+
|
|
342
|
+
# Test 5: Upsert test (update existing)
|
|
343
|
+
test_bulk_upsert "upsert-test.csv" "$TEST_TABLE" "sku" "Upsert - Update Existing"
|
|
344
|
+
verify_data 14 "1 new product, 2 updated"
|
|
345
|
+
check_data "SELECT name, price FROM $TEST_TABLE WHERE sku='PROD-001'" "Updated Laptop" "PROD-001 was updated"
|
|
346
|
+
|
|
347
|
+
# Test 6: NULL values handling
|
|
348
|
+
test_bulk_upsert "null-values.csv" "$TEST_TABLE" "sku" "NULL Values in CSV"
|
|
349
|
+
verify_data 18 "4 products with nulls"
|
|
350
|
+
|
|
351
|
+
# Test 7: Unicode/Emoji support
|
|
352
|
+
test_bulk_upsert "unicode.csv" "$TEST_TABLE" "sku" "Unicode and Emoji Support"
|
|
353
|
+
verify_data 22 "4 unicode products"
|
|
354
|
+
check_data "SELECT name FROM $TEST_TABLE WHERE sku='UNI-004'" "🚀 Rocket Toy" "Emoji preserved"
|
|
355
|
+
|
|
356
|
+
# Test 8: Error handling - empty file
|
|
357
|
+
echo ""
|
|
358
|
+
echo "🧪 Test: Error Handling - Empty CSV"
|
|
359
|
+
echo " File: empty.csv"
|
|
360
|
+
if test_bulk_upsert "empty.csv" "$TEST_TABLE" "" "Empty CSV (should fail)" true; then
|
|
361
|
+
echo " ❌ ERROR: Empty file was accepted (should have been rejected)"
|
|
362
|
+
else
|
|
363
|
+
echo " ✅ Correctly rejected empty file (expected behavior)"
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
# Test 9: Error handling - invalid CSV
|
|
367
|
+
echo ""
|
|
368
|
+
echo "🧪 Test: Error Handling - Invalid CSV"
|
|
369
|
+
echo " File: invalid.csv"
|
|
370
|
+
if test_bulk_upsert "invalid.csv" "$TEST_TABLE" "" "Invalid CSV (should fail)" true; then
|
|
371
|
+
echo " ❌ ERROR: Invalid CSV was accepted (should have been rejected)"
|
|
372
|
+
else
|
|
373
|
+
echo " ✅ Correctly rejected invalid CSV (expected behavior)"
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
# Test 10: Performance test
|
|
377
|
+
echo ""
|
|
378
|
+
echo "🧪 Test: Large Dataset Performance"
|
|
379
|
+
START_TIME=$(date +%s%N)
|
|
380
|
+
test_bulk_upsert "large-dataset.csv" "$TEST_TABLE" "sku" "1000 rows bulk insert"
|
|
381
|
+
END_TIME=$(date +%s%N)
|
|
382
|
+
ELAPSED=$((($END_TIME - $START_TIME) / 1000000))
|
|
383
|
+
echo " ⏱️ Time: ${ELAPSED}ms ($(echo "scale=1; 1000000/$ELAPSED" | bc) rows/sec)"
|
|
384
|
+
|
|
385
|
+
echo ""
|
|
386
|
+
echo "="
|
|
387
|
+
echo "📊 TEST SUMMARY"
|
|
388
|
+
echo "="
|
|
389
|
+
|
|
390
|
+
# Final verification
|
|
391
|
+
local final_count=$(curl -s -X POST "$API_BASE/database/advance/rawsql" \
|
|
392
|
+
-H "Authorization: Bearer $AUTH_TOKEN" \
|
|
393
|
+
-H "Content-Type: application/json" \
|
|
394
|
+
-d "{\"query\": \"SELECT COUNT(*) as count FROM $TEST_TABLE\"}" | grep -o '"count":"[0-9]*' | cut -d'"' -f4)
|
|
395
|
+
|
|
396
|
+
echo "Total records in table: $final_count"
|
|
397
|
+
echo ""
|
|
398
|
+
|
|
399
|
+
# Cleanup
|
|
400
|
+
cleanup
|
|
401
|
+
|
|
402
|
+
echo ""
|
|
403
|
+
echo "✅ All bulk upsert tests completed!"
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
# Trap to ensure cleanup on exit
|
|
407
|
+
trap cleanup EXIT
|
|
408
|
+
|
|
409
|
+
# Run the tests
|
|
410
|
+
main
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Test script for database advance functionality
|
|
4
|
+
# Tests rawSQL, export, and import operations
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
BASE_URL="http://localhost:7130/api/database/advance"
|
|
8
|
+
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwicm9sZSI6InByb2plY3RfYWRtaW4iLCJpYXQiOjE3NTY0MDM2NTUsImV4cCI6MTc1NzAwODQ1NX0.UhLvS5f4vdzsR0bZLmHvQ-MX6WPoPieTZ4H7sxjRYGM"
|
|
9
|
+
|
|
10
|
+
# Colors for output
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
BLUE='\033[0;34m'
|
|
15
|
+
NC='\033[0m' # No Color
|
|
16
|
+
|
|
17
|
+
echo "========================================="
|
|
18
|
+
echo "Database Advance Operations Test Script"
|
|
19
|
+
echo "========================================="
|
|
20
|
+
echo "Base URL: $BASE_URL"
|
|
21
|
+
echo "Testing rawSQL, export, and import operations..."
|
|
22
|
+
echo "========================================="
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# Function to test rawSQL endpoint
|
|
26
|
+
test_rawsql() {
|
|
27
|
+
local test_name="$1"
|
|
28
|
+
local request_body="$2"
|
|
29
|
+
local description="$3"
|
|
30
|
+
|
|
31
|
+
echo -e "${BLUE}Test: $test_name${NC}"
|
|
32
|
+
echo -e "${YELLOW}Description: $description${NC}"
|
|
33
|
+
echo "Request body: $request_body"
|
|
34
|
+
echo ""
|
|
35
|
+
|
|
36
|
+
# Make the API request
|
|
37
|
+
RESPONSE=$(curl -s -w "\n:HTTP_CODE:%{http_code}" -X POST "$BASE_URL/rawsql" \
|
|
38
|
+
-H "Content-Type: application/json" \
|
|
39
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
40
|
+
-d "$request_body" 2>&1)
|
|
41
|
+
|
|
42
|
+
# Extract HTTP code and response body
|
|
43
|
+
HTTP_CODE=$(echo "$RESPONSE" | grep ":HTTP_CODE:" | cut -d: -f3)
|
|
44
|
+
RESPONSE_BODY=$(echo "$RESPONSE" | sed '/^:HTTP_CODE:/d')
|
|
45
|
+
|
|
46
|
+
echo -e "${BLUE}HTTP Status: $HTTP_CODE${NC}"
|
|
47
|
+
|
|
48
|
+
if [ "$HTTP_CODE" = "200" ]; then
|
|
49
|
+
echo -e "${GREEN}✓ Request successful${NC}"
|
|
50
|
+
echo ""
|
|
51
|
+
echo -e "${BLUE}Response:${NC}"
|
|
52
|
+
echo "$RESPONSE_BODY" | jq . 2>/dev/null || echo "$RESPONSE_BODY"
|
|
53
|
+
else
|
|
54
|
+
echo -e "${RED}✗ Request failed${NC}"
|
|
55
|
+
echo ""
|
|
56
|
+
echo -e "${RED}Response:${NC}"
|
|
57
|
+
echo "$RESPONSE_BODY"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo ""
|
|
61
|
+
echo "----------------------------------------"
|
|
62
|
+
echo ""
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Function to make API request and show results
|
|
66
|
+
test_export() {
|
|
67
|
+
local test_name="$1"
|
|
68
|
+
local request_body="$2"
|
|
69
|
+
local description="$3"
|
|
70
|
+
|
|
71
|
+
echo -e "${BLUE}Test: $test_name${NC}"
|
|
72
|
+
echo -e "${YELLOW}Description: $description${NC}"
|
|
73
|
+
echo "Request body: $request_body"
|
|
74
|
+
echo ""
|
|
75
|
+
|
|
76
|
+
# Make the API request
|
|
77
|
+
RESPONSE=$(curl -s -w "\n:HTTP_CODE:%{http_code}" -X POST "$BASE_URL/export" \
|
|
78
|
+
-H "Content-Type: application/json" \
|
|
79
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
80
|
+
-d "$request_body" 2>&1)
|
|
81
|
+
|
|
82
|
+
# Extract HTTP code and response body
|
|
83
|
+
HTTP_CODE=$(echo "$RESPONSE" | grep ":HTTP_CODE:" | cut -d: -f3)
|
|
84
|
+
RESPONSE_BODY=$(echo "$RESPONSE" | sed '/^:HTTP_CODE:/d')
|
|
85
|
+
|
|
86
|
+
echo -e "${BLUE}HTTP Status: $HTTP_CODE${NC}"
|
|
87
|
+
|
|
88
|
+
if [ "$HTTP_CODE" = "200" ]; then
|
|
89
|
+
echo -e "${GREEN}✓ Request successful${NC}"
|
|
90
|
+
echo ""
|
|
91
|
+
echo -e "${BLUE}Response:${NC}"
|
|
92
|
+
echo "$RESPONSE_BODY" | jq . 2>/dev/null || echo "$RESPONSE_BODY"
|
|
93
|
+
else
|
|
94
|
+
echo -e "${RED}✗ Request failed${NC}"
|
|
95
|
+
echo ""
|
|
96
|
+
echo -e "${RED}Response:${NC}"
|
|
97
|
+
echo "$RESPONSE_BODY"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
echo ""
|
|
101
|
+
echo "----------------------------------------"
|
|
102
|
+
echo ""
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Function to test import endpoint with file upload
|
|
106
|
+
test_import() {
|
|
107
|
+
local test_name="$1"
|
|
108
|
+
local file_path="$2"
|
|
109
|
+
local truncate_option="$3"
|
|
110
|
+
local description="$4"
|
|
111
|
+
|
|
112
|
+
echo -e "${BLUE}Test: $test_name${NC}"
|
|
113
|
+
echo -e "${YELLOW}Description: $description${NC}"
|
|
114
|
+
echo "File: $file_path"
|
|
115
|
+
echo "Truncate: $truncate_option"
|
|
116
|
+
echo ""
|
|
117
|
+
|
|
118
|
+
# Check if file exists
|
|
119
|
+
if [ ! -f "$file_path" ]; then
|
|
120
|
+
echo -e "${RED}✗ File not found: $file_path${NC}"
|
|
121
|
+
echo ""
|
|
122
|
+
echo "----------------------------------------"
|
|
123
|
+
echo ""
|
|
124
|
+
return 1
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
# Make the API request with file upload
|
|
128
|
+
RESPONSE=$(curl -s -w "\n:HTTP_CODE:%{http_code}" -X POST "$BASE_URL/import" \
|
|
129
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
130
|
+
-F "file=@$file_path" \
|
|
131
|
+
-F "truncate=$truncate_option" 2>&1)
|
|
132
|
+
|
|
133
|
+
# Extract HTTP code and response body
|
|
134
|
+
HTTP_CODE=$(echo "$RESPONSE" | grep ":HTTP_CODE:" | cut -d: -f3)
|
|
135
|
+
RESPONSE_BODY=$(echo "$RESPONSE" | sed '/^:HTTP_CODE:/d')
|
|
136
|
+
|
|
137
|
+
echo -e "${BLUE}HTTP Status: $HTTP_CODE${NC}"
|
|
138
|
+
|
|
139
|
+
if [ "$HTTP_CODE" = "200" ]; then
|
|
140
|
+
echo -e "${GREEN}✓ Request successful${NC}"
|
|
141
|
+
echo ""
|
|
142
|
+
echo -e "${BLUE}Response:${NC}"
|
|
143
|
+
echo "$RESPONSE_BODY" | jq . 2>/dev/null || echo "$RESPONSE_BODY"
|
|
144
|
+
else
|
|
145
|
+
echo -e "${RED}✗ Request failed${NC}"
|
|
146
|
+
echo ""
|
|
147
|
+
echo -e "${RED}Response:${NC}"
|
|
148
|
+
echo "$RESPONSE_BODY"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
echo ""
|
|
152
|
+
echo "----------------------------------------"
|
|
153
|
+
echo ""
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# ===========================================
|
|
157
|
+
# RAW SQL TESTS
|
|
158
|
+
# ===========================================
|
|
159
|
+
|
|
160
|
+
echo -e "${GREEN}=== RAW SQL TESTS ===${NC}"
|
|
161
|
+
echo ""
|
|
162
|
+
|
|
163
|
+
# Test 1: Check if posts table exists
|
|
164
|
+
test_rawsql \
|
|
165
|
+
"Check Posts Table Existence" \
|
|
166
|
+
'{"query": "SELECT tablename FROM pg_tables WHERE schemaname = '\''public'\'' AND tablename = '\''posts'\'';"}' \
|
|
167
|
+
"Verify that the posts table exists before creating index"
|
|
168
|
+
|
|
169
|
+
# Test 2: Check existing indexes on posts table
|
|
170
|
+
test_rawsql \
|
|
171
|
+
"Check Existing Indexes on Posts" \
|
|
172
|
+
'{"query": "SELECT indexname, indexdef FROM pg_indexes WHERE tablename = '\''posts'\'';"}' \
|
|
173
|
+
"List all existing indexes on the posts table"
|
|
174
|
+
|
|
175
|
+
# Test 3: Create index on posts.title column
|
|
176
|
+
test_rawsql \
|
|
177
|
+
"Create Title Index on Posts" \
|
|
178
|
+
'{"query": "CREATE INDEX IF NOT EXISTS idx_posts_title ON posts(title);"}' \
|
|
179
|
+
"Create an index on the title column of the posts table for better query performance"
|
|
180
|
+
|
|
181
|
+
# Test 4: Verify the index was created
|
|
182
|
+
test_rawsql \
|
|
183
|
+
"Verify Title Index Creation" \
|
|
184
|
+
'{"query": "SELECT indexname, indexdef FROM pg_indexes WHERE tablename = '\''posts'\'' AND indexname = '\''idx_posts_title'\'';"}' \
|
|
185
|
+
"Confirm that the title index was successfully created"
|
|
186
|
+
|
|
187
|
+
# Test 5: Test a simple SELECT query
|
|
188
|
+
test_rawsql \
|
|
189
|
+
"Simple Select Query" \
|
|
190
|
+
'{"query": "SELECT COUNT(*) as total_posts FROM posts;"}' \
|
|
191
|
+
"Count total number of posts in the table"
|
|
192
|
+
|
|
193
|
+
echo -e "${GREEN}=== EXPORT TESTS ===${NC}"
|
|
194
|
+
echo ""
|
|
195
|
+
|
|
196
|
+
# Test 6: Export users table in SQL format with data
|
|
197
|
+
test_export \
|
|
198
|
+
"Users Table - SQL with Data" \
|
|
199
|
+
'{"tables": ["users"], "format": "sql", "includeData": true}' \
|
|
200
|
+
"Export users table as SQL with both schema and data"
|
|
201
|
+
|
|
202
|
+
# Test 7: Export users table in SQL format without data (schema only)
|
|
203
|
+
test_export \
|
|
204
|
+
"Users Table - SQL Schema Only" \
|
|
205
|
+
'{"tables": ["users"], "format": "sql", "includeData": false}' \
|
|
206
|
+
"Export users table as SQL with schema only, no data"
|
|
207
|
+
|
|
208
|
+
# Test 8: Export users table in JSON format with data
|
|
209
|
+
test_export \
|
|
210
|
+
"Users Table - JSON with Data" \
|
|
211
|
+
'{"tables": ["users"], "format": "json", "includeData": true}' \
|
|
212
|
+
"Export users table as JSON with both schema and data"
|
|
213
|
+
|
|
214
|
+
# Test 9: Export users table in JSON format without data (schema only)
|
|
215
|
+
test_export \
|
|
216
|
+
"Users Table - JSON Schema Only" \
|
|
217
|
+
'{"tables": ["users"], "format": "json", "includeData": false}' \
|
|
218
|
+
"Export users table as JSON with schema only, no data"
|
|
219
|
+
|
|
220
|
+
# Test 10: Export all tables in SQL format (default behavior)
|
|
221
|
+
test_export \
|
|
222
|
+
"All Tables - SQL Format" \
|
|
223
|
+
'{"format": "sql"}' \
|
|
224
|
+
"Export all tables as SQL with default settings"
|
|
225
|
+
|
|
226
|
+
# Test 11: Test with invalid table name
|
|
227
|
+
test_export \
|
|
228
|
+
"Invalid Table Name" \
|
|
229
|
+
'{"tables": ["nonexistent_table"], "format": "sql"}' \
|
|
230
|
+
"Test error handling with non-existent table"
|
|
231
|
+
|
|
232
|
+
# Test 12: Test with invalid format
|
|
233
|
+
test_export \
|
|
234
|
+
"Invalid Format" \
|
|
235
|
+
'{"tables": ["users"], "format": "xml"}' \
|
|
236
|
+
"Test validation with invalid format"
|
|
237
|
+
|
|
238
|
+
# Test 12.5: Export posts table in SQL format with data
|
|
239
|
+
test_export \
|
|
240
|
+
"All Tables - SQL with Data" \
|
|
241
|
+
'{"format": "sql", "includeData": false}' \
|
|
242
|
+
"Export all tables as SQL with both schema and data"
|
|
243
|
+
|
|
244
|
+
echo -e "${GREEN}=== IMPORT TESTS ===${NC}"
|
|
245
|
+
echo ""
|
|
246
|
+
|
|
247
|
+
# Define the path to the SQL file
|
|
248
|
+
SQL_FILE_PATH="$(dirname "$0")/test-users.sql"
|
|
249
|
+
|
|
250
|
+
# Test 13: Import users.sql without truncate
|
|
251
|
+
test_import \
|
|
252
|
+
"Import Users SQL - No Truncate" \
|
|
253
|
+
"$SQL_FILE_PATH" \
|
|
254
|
+
"false" \
|
|
255
|
+
"Import users table structure from SQL file without truncating existing data"
|
|
256
|
+
|
|
257
|
+
# Test 14: Import users.sql with truncate
|
|
258
|
+
test_import \
|
|
259
|
+
"Import Users SQL - With Truncate" \
|
|
260
|
+
"$SQL_FILE_PATH" \
|
|
261
|
+
"true" \
|
|
262
|
+
"Import users table structure from SQL file with truncating existing data"
|
|
263
|
+
|
|
264
|
+
# Test 15: Test with non-existent file
|
|
265
|
+
test_import \
|
|
266
|
+
"Import Non-existent File" \
|
|
267
|
+
"$(dirname "$0")/nonexistent.sql" \
|
|
268
|
+
"false" \
|
|
269
|
+
"Test error handling with non-existent SQL file"
|
|
270
|
+
|
|
271
|
+
echo "========================================="
|
|
272
|
+
echo "Database Advance Tests Complete"
|
|
273
|
+
echo "========================================="
|
|
274
|
+
echo ""
|
|
275
|
+
echo -e "${GREEN}All tests have been executed.${NC}"
|
|
276
|
+
echo "Check the responses above to verify all functionality."
|
|
277
|
+
echo ""
|
|
278
|
+
echo "Key things to verify:"
|
|
279
|
+
echo ""
|
|
280
|
+
echo -e "${BLUE}Raw SQL Tests:${NC}"
|
|
281
|
+
echo "- Posts table existence check"
|
|
282
|
+
echo "- Index creation and verification"
|
|
283
|
+
echo "- SQL execution with proper responses"
|
|
284
|
+
echo ""
|
|
285
|
+
echo -e "${BLUE}Export Tests:${NC}"
|
|
286
|
+
echo "- SQL exports should contain CREATE TABLE statements"
|
|
287
|
+
echo "- When includeData=true, INSERT statements should be present"
|
|
288
|
+
echo "- When includeData=false, only schema should be exported"
|
|
289
|
+
echo "- JSON exports should have 'schema' and 'rows' properties"
|
|
290
|
+
echo "- Invalid requests should return appropriate error messages"
|
|
291
|
+
echo ""
|
|
292
|
+
echo -e "${BLUE}Import Tests:${NC}"
|
|
293
|
+
echo "- File uploads should be processed correctly"
|
|
294
|
+
echo "- SQL files should be executed and tables created"
|
|
295
|
+
echo "- Truncate option should control data preservation"
|
|
296
|
+
echo "- Error handling should work for missing files"
|
|
297
|
+
echo "- Response should include import statistics"
|