sovrium 0.0.2
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/CHANGELOG.md +3497 -0
- package/LICENSE.md +147 -0
- package/LICENSE_EE.md +297 -0
- package/README.md +321 -0
- package/drizzle/0000_melted_kabuki.sql +163 -0
- package/drizzle/meta/0000_snapshot.json +1216 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +167 -0
- package/schemas/0.0.1/app.openapi.json +70 -0
- package/schemas/0.0.1/app.schema.json +7961 -0
- package/schemas/0.0.2/app.openapi.json +80 -0
- package/schemas/0.0.2/app.schema.json +8829 -0
- package/schemas/development/app.openapi.json +70 -0
- package/schemas/development/app.schema.json +7456 -0
- package/src/application/errors/app-validation-error.ts +14 -0
- package/src/application/errors/static-generation-error.ts +16 -0
- package/src/application/metadata/favicon-transformer.ts +127 -0
- package/src/application/models/server.ts +27 -0
- package/src/application/ports/models/user-metadata.ts +36 -0
- package/src/application/ports/models/user-session.ts +34 -0
- package/src/application/ports/repositories/activity-log-repository.ts +68 -0
- package/src/application/ports/repositories/activity-repository.ts +49 -0
- package/src/application/ports/repositories/analytics-repository.ts +164 -0
- package/src/application/ports/repositories/auth-repository.ts +33 -0
- package/src/application/ports/repositories/batch-repository.ts +86 -0
- package/src/application/ports/repositories/comment-repository.ts +150 -0
- package/src/application/ports/repositories/index.ts +41 -0
- package/src/application/ports/repositories/table-repository.ts +139 -0
- package/src/application/ports/services/css-compiler.ts +55 -0
- package/src/application/ports/services/index.ts +16 -0
- package/src/application/ports/services/page-renderer.ts +79 -0
- package/src/application/ports/services/server-factory.ts +80 -0
- package/src/application/ports/services/static-site-generator.ts +82 -0
- package/src/application/use-cases/activity/programs.ts +66 -0
- package/src/application/use-cases/analytics/collect-page-view.ts +114 -0
- package/src/application/use-cases/analytics/purge-old-data.ts +40 -0
- package/src/application/use-cases/analytics/query-campaigns.ts +43 -0
- package/src/application/use-cases/analytics/query-devices.ts +36 -0
- package/src/application/use-cases/analytics/query-overview.ts +50 -0
- package/src/application/use-cases/analytics/query-pages.ts +40 -0
- package/src/application/use-cases/analytics/query-referrers.ts +43 -0
- package/src/application/use-cases/analytics/ua-parser.ts +89 -0
- package/src/application/use-cases/analytics/visitor-hash.ts +77 -0
- package/src/application/use-cases/auth/bootstrap-admin.ts +270 -0
- package/src/application/use-cases/list-activity-logs.ts +123 -0
- package/src/application/use-cases/server/generate-static-helpers.ts +374 -0
- package/src/application/use-cases/server/generate-static.ts +287 -0
- package/src/application/use-cases/server/start-server.ts +118 -0
- package/src/application/use-cases/server/startup-error-handler.ts +69 -0
- package/src/application/use-cases/server/static-content-generators.ts +182 -0
- package/src/application/use-cases/server/static-language-generators.ts +181 -0
- package/src/application/use-cases/server/static-url-rewriter.ts +237 -0
- package/src/application/use-cases/server/translation-replacer.ts +164 -0
- package/src/application/use-cases/tables/activity-programs.ts +93 -0
- package/src/application/use-cases/tables/batch-operations.ts +156 -0
- package/src/application/use-cases/tables/comment-programs.ts +436 -0
- package/src/application/use-cases/tables/permissions/permissions.ts +25 -0
- package/src/application/use-cases/tables/programs.ts +435 -0
- package/src/application/use-cases/tables/table-operations.ts +412 -0
- package/src/application/use-cases/tables/user-role.ts +52 -0
- package/src/application/use-cases/tables/utils/display-formatter.ts +471 -0
- package/src/application/use-cases/tables/utils/field-read-filter.ts +189 -0
- package/src/application/use-cases/tables/utils/list-helpers.ts +122 -0
- package/src/application/use-cases/tables/utils/record-transformer.ts +319 -0
- package/src/cli.ts +370 -0
- package/src/domain/errors/create-tagged-error.ts +36 -0
- package/src/domain/errors/index.ts +78 -0
- package/src/domain/models/api/analytics.ts +179 -0
- package/src/domain/models/api/auth.ts +231 -0
- package/src/domain/models/api/common.ts +60 -0
- package/src/domain/models/api/error.ts +89 -0
- package/src/domain/models/api/health.ts +38 -0
- package/src/domain/models/api/index.ts +42 -0
- package/src/domain/models/api/request.ts +132 -0
- package/src/domain/models/api/tables.ts +444 -0
- package/src/domain/models/app/analytics/index.ts +129 -0
- package/src/domain/models/app/auth/config.ts +116 -0
- package/src/domain/models/app/auth/index.ts +230 -0
- package/src/domain/models/app/auth/methods/email-and-password.ts +67 -0
- package/src/domain/models/app/auth/methods/index.ts +11 -0
- package/src/domain/models/app/auth/methods/magic-link.ts +54 -0
- package/src/domain/models/app/auth/oauth/index.ts +8 -0
- package/src/domain/models/app/auth/oauth/providers.ts +105 -0
- package/src/domain/models/app/auth/plugins/admin.ts +130 -0
- package/src/domain/models/app/auth/plugins/index.ts +74 -0
- package/src/domain/models/app/auth/plugins/two-factor.ts +63 -0
- package/src/domain/models/app/auth/roles.ts +179 -0
- package/src/domain/models/app/auth/strategies.ts +191 -0
- package/src/domain/models/app/auth/validation.ts +127 -0
- package/src/domain/models/app/common/branded-ids.ts +200 -0
- package/src/domain/models/app/common/definitions.ts +187 -0
- package/src/domain/models/app/component/common/component-children.ts +119 -0
- package/src/domain/models/app/component/common/component-props.ts +89 -0
- package/src/domain/models/app/component/common/component-reference.ts +170 -0
- package/src/domain/models/app/component/component.ts +81 -0
- package/src/domain/models/app/components.ts +65 -0
- package/src/domain/models/app/description.ts +83 -0
- package/src/domain/models/app/index.ts +258 -0
- package/src/domain/models/app/language/language-config.ts +200 -0
- package/src/domain/models/app/languages.ts +205 -0
- package/src/domain/models/app/name.ts +66 -0
- package/src/domain/models/app/page/common/interactions/click-interaction.ts +116 -0
- package/src/domain/models/app/page/common/interactions/entrance-animation.ts +84 -0
- package/src/domain/models/app/page/common/interactions/hover-interaction.ts +144 -0
- package/src/domain/models/app/page/common/interactions/interactions.ts +64 -0
- package/src/domain/models/app/page/common/interactions/scroll-interaction.ts +93 -0
- package/src/domain/models/app/page/common/responsive.ts +114 -0
- package/src/domain/models/app/page/common/url.ts +35 -0
- package/src/domain/models/app/page/common/variable-reference.ts +53 -0
- package/src/domain/models/app/page/id.ts +44 -0
- package/src/domain/models/app/page/index.ts +270 -0
- package/src/domain/models/app/page/meta/analytics.ts +248 -0
- package/src/domain/models/app/page/meta/custom-elements.ts +180 -0
- package/src/domain/models/app/page/meta/dns-prefetch.ts +77 -0
- package/src/domain/models/app/page/meta/favicon-set.ts +203 -0
- package/src/domain/models/app/page/meta/favicon.ts +50 -0
- package/src/domain/models/app/page/meta/favicons-config.ts +73 -0
- package/src/domain/models/app/page/meta/index.ts +278 -0
- package/src/domain/models/app/page/meta/open-graph.ts +166 -0
- package/src/domain/models/app/page/meta/preload.ts +190 -0
- package/src/domain/models/app/page/meta/structured-data/article.ts +211 -0
- package/src/domain/models/app/page/meta/structured-data/breadcrumb.ts +115 -0
- package/src/domain/models/app/page/meta/structured-data/common-fields.ts +201 -0
- package/src/domain/models/app/page/meta/structured-data/education-event.ts +256 -0
- package/src/domain/models/app/page/meta/structured-data/faq-page.ts +127 -0
- package/src/domain/models/app/page/meta/structured-data/index.ts +95 -0
- package/src/domain/models/app/page/meta/structured-data/local-business.ts +247 -0
- package/src/domain/models/app/page/meta/structured-data/organization.ts +171 -0
- package/src/domain/models/app/page/meta/structured-data/person.ts +138 -0
- package/src/domain/models/app/page/meta/structured-data/postal-address.ts +106 -0
- package/src/domain/models/app/page/meta/structured-data/product.ts +214 -0
- package/src/domain/models/app/page/meta/twitter-card.ts +217 -0
- package/src/domain/models/app/page/name.ts +38 -0
- package/src/domain/models/app/page/path.ts +21 -0
- package/src/domain/models/app/page/scripts/external-scripts.ts +163 -0
- package/src/domain/models/app/page/scripts/features.ts +135 -0
- package/src/domain/models/app/page/scripts/inline-scripts.ts +114 -0
- package/src/domain/models/app/page/scripts/scripts.ts +102 -0
- package/src/domain/models/app/page/sections.ts +298 -0
- package/src/domain/models/app/pages.ts +61 -0
- package/src/domain/models/app/permissions/index.ts +61 -0
- package/src/domain/models/app/permissions/resource-action.ts +114 -0
- package/src/domain/models/app/permissions/roles.ts +120 -0
- package/src/domain/models/app/table/check-constraints.ts +105 -0
- package/src/domain/models/app/table/cycle-detection.ts +124 -0
- package/src/domain/models/app/table/database-identifier.ts +153 -0
- package/src/domain/models/app/table/field-name.ts +36 -0
- package/src/domain/models/app/table/field-types/advanced/array-field.ts +33 -0
- package/src/domain/models/app/table/field-types/advanced/autonumber-field.ts +54 -0
- package/src/domain/models/app/table/field-types/advanced/button-field.ts +56 -0
- package/src/domain/models/app/table/field-types/advanced/color-field.ts +57 -0
- package/src/domain/models/app/table/field-types/advanced/count-field.ts +54 -0
- package/src/domain/models/app/table/field-types/advanced/formula-field.ts +58 -0
- package/src/domain/models/app/table/field-types/advanced/geolocation-field.ts +49 -0
- package/src/domain/models/app/table/field-types/advanced/index.ts +16 -0
- package/src/domain/models/app/table/field-types/advanced/json-field.ts +25 -0
- package/src/domain/models/app/table/field-types/advanced/unknown-field.ts +85 -0
- package/src/domain/models/app/table/field-types/base-field.ts +42 -0
- package/src/domain/models/app/table/field-types/date-time/created-at-field.ts +49 -0
- package/src/domain/models/app/table/field-types/date-time/date-field.ts +95 -0
- package/src/domain/models/app/table/field-types/date-time/deleted-at-field.ts +56 -0
- package/src/domain/models/app/table/field-types/date-time/duration-field.ts +73 -0
- package/src/domain/models/app/table/field-types/date-time/index.ts +12 -0
- package/src/domain/models/app/table/field-types/date-time/updated-at-field.ts +50 -0
- package/src/domain/models/app/table/field-types/index.ts +19 -0
- package/src/domain/models/app/table/field-types/media/barcode-field.ts +58 -0
- package/src/domain/models/app/table/field-types/media/index.ts +10 -0
- package/src/domain/models/app/table/field-types/media/multiple-attachments-field.ts +80 -0
- package/src/domain/models/app/table/field-types/media/single-attachment-field.ts +81 -0
- package/src/domain/models/app/table/field-types/numeric/currency-field.ts +144 -0
- package/src/domain/models/app/table/field-types/numeric/decimal-field.ts +113 -0
- package/src/domain/models/app/table/field-types/numeric/index.ts +13 -0
- package/src/domain/models/app/table/field-types/numeric/integer-field.ts +98 -0
- package/src/domain/models/app/table/field-types/numeric/percentage-field.ts +115 -0
- package/src/domain/models/app/table/field-types/numeric/progress-field.ts +71 -0
- package/src/domain/models/app/table/field-types/numeric/rating-field.ts +74 -0
- package/src/domain/models/app/table/field-types/relational/index.ts +10 -0
- package/src/domain/models/app/table/field-types/relational/lookup-field.ts +46 -0
- package/src/domain/models/app/table/field-types/relational/relationship-field.ts +112 -0
- package/src/domain/models/app/table/field-types/relational/rollup-field.ts +58 -0
- package/src/domain/models/app/table/field-types/selection/checkbox-field.ts +51 -0
- package/src/domain/models/app/table/field-types/selection/index.ts +11 -0
- package/src/domain/models/app/table/field-types/selection/multi-select-field.ts +68 -0
- package/src/domain/models/app/table/field-types/selection/single-select-field.ts +54 -0
- package/src/domain/models/app/table/field-types/selection/status-field.ts +37 -0
- package/src/domain/models/app/table/field-types/text/email-field.ts +80 -0
- package/src/domain/models/app/table/field-types/text/index.ts +13 -0
- package/src/domain/models/app/table/field-types/text/long-text-field.ts +77 -0
- package/src/domain/models/app/table/field-types/text/phone-number-field.ts +82 -0
- package/src/domain/models/app/table/field-types/text/rich-text-field.ts +66 -0
- package/src/domain/models/app/table/field-types/text/single-line-text-field.ts +79 -0
- package/src/domain/models/app/table/field-types/text/url-field.ts +81 -0
- package/src/domain/models/app/table/field-types/user/created-by-field.ts +50 -0
- package/src/domain/models/app/table/field-types/user/deleted-by-field.ts +57 -0
- package/src/domain/models/app/table/field-types/user/index.ts +11 -0
- package/src/domain/models/app/table/field-types/user/updated-by-field.ts +51 -0
- package/src/domain/models/app/table/field-types/user/user-field.ts +52 -0
- package/src/domain/models/app/table/field-types/validation-utils.ts +166 -0
- package/src/domain/models/app/table/fields.ts +216 -0
- package/src/domain/models/app/table/foreign-keys.ts +111 -0
- package/src/domain/models/app/table/formula-keywords.ts +326 -0
- package/src/domain/models/app/table/id.ts +31 -0
- package/src/domain/models/app/table/index.ts +290 -0
- package/src/domain/models/app/table/indexes.ts +80 -0
- package/src/domain/models/app/table/name.ts +37 -0
- package/src/domain/models/app/table/permissions/field-permission.ts +83 -0
- package/src/domain/models/app/table/permissions/index.ts +167 -0
- package/src/domain/models/app/table/permissions/permission-evaluator.ts +372 -0
- package/src/domain/models/app/table/permissions/permission.ts +49 -0
- package/src/domain/models/app/table/primary-key.ts +62 -0
- package/src/domain/models/app/table/table-formula-validation.ts +168 -0
- package/src/domain/models/app/table/table-indexes-validation.ts +38 -0
- package/src/domain/models/app/table/table-permissions-validation.ts +77 -0
- package/src/domain/models/app/table/table-primary-key-validation.ts +49 -0
- package/src/domain/models/app/table/table-views-validation.ts +408 -0
- package/src/domain/models/app/table/unique-constraints.ts +79 -0
- package/src/domain/models/app/table/views/fields.ts +28 -0
- package/src/domain/models/app/table/views/filters.ts +162 -0
- package/src/domain/models/app/table/views/group-by.ts +32 -0
- package/src/domain/models/app/table/views/id.ts +50 -0
- package/src/domain/models/app/table/views/index.ts +177 -0
- package/src/domain/models/app/table/views/name.ts +32 -0
- package/src/domain/models/app/table/views/permissions.ts +98 -0
- package/src/domain/models/app/table/views/sorts.ts +31 -0
- package/src/domain/models/app/tables.ts +695 -0
- package/src/domain/models/app/theme/animations.ts +208 -0
- package/src/domain/models/app/theme/border-radius.ts +58 -0
- package/src/domain/models/app/theme/breakpoints.ts +62 -0
- package/src/domain/models/app/theme/colors.ts +110 -0
- package/src/domain/models/app/theme/fonts.ts +164 -0
- package/src/domain/models/app/theme/shadows.ts +61 -0
- package/src/domain/models/app/theme/spacing.ts +115 -0
- package/src/domain/models/app/theme.ts +66 -0
- package/src/domain/models/app/version.ts +87 -0
- package/src/domain/models/record-comment.ts +91 -0
- package/src/domain/utils/content-parsing.ts +49 -0
- package/src/domain/utils/format-detection.ts +69 -0
- package/src/domain/utils/index.ts +9 -0
- package/src/domain/utils/route-matcher.ts +184 -0
- package/src/domain/utils/translation-resolver.ts +170 -0
- package/src/index.ts +208 -0
- package/src/infrastructure/analytics/tracking-script.ts +48 -0
- package/src/infrastructure/auth/better-auth/auth.ts +216 -0
- package/src/infrastructure/auth/better-auth/email-handlers.ts +162 -0
- package/src/infrastructure/auth/better-auth/index.ts +16 -0
- package/src/infrastructure/auth/better-auth/layer.ts +97 -0
- package/src/infrastructure/auth/better-auth/plugins/admin.ts +56 -0
- package/src/infrastructure/auth/better-auth/plugins/magic-link.ts +31 -0
- package/src/infrastructure/auth/better-auth/plugins/two-factor.ts +19 -0
- package/src/infrastructure/auth/better-auth/schema.ts +152 -0
- package/src/infrastructure/auth/index.ts +27 -0
- package/src/infrastructure/css/cache/css-cache-service.ts +130 -0
- package/src/infrastructure/css/compiler.ts +210 -0
- package/src/infrastructure/css/css-compiler-live.ts +20 -0
- package/src/infrastructure/css/index.ts +25 -0
- package/src/infrastructure/css/styles/animation-styles-generator.ts +177 -0
- package/src/infrastructure/css/styles/click-animations.ts +147 -0
- package/src/infrastructure/css/styles/component-layer-generators.ts +147 -0
- package/src/infrastructure/css/theme/theme-generators.ts +130 -0
- package/src/infrastructure/css/theme/theme-layer-generators.ts +219 -0
- package/src/infrastructure/css/theme/theme-token-resolver.ts +76 -0
- package/src/infrastructure/database/activity-queries.ts +111 -0
- package/src/infrastructure/database/auth/auth-validation.ts +101 -0
- package/src/infrastructure/database/drizzle/db-bun.ts +17 -0
- package/src/infrastructure/database/drizzle/db.ts +17 -0
- package/src/infrastructure/database/drizzle/index.ts +16 -0
- package/src/infrastructure/database/drizzle/layer.ts +34 -0
- package/src/infrastructure/database/drizzle/migrate.ts +77 -0
- package/src/infrastructure/database/drizzle/schema/activity-log.ts +111 -0
- package/src/infrastructure/database/drizzle/schema/analytics-page-views.ts +116 -0
- package/src/infrastructure/database/drizzle/schema/migration-audit.ts +68 -0
- package/src/infrastructure/database/drizzle/schema/record-comments.ts +79 -0
- package/src/infrastructure/database/drizzle/schema.ts +12 -0
- package/src/infrastructure/database/field-utils.ts +87 -0
- package/src/infrastructure/database/filter-operators.ts +136 -0
- package/src/infrastructure/database/formula/formula-trigger-generators.ts +114 -0
- package/src/infrastructure/database/formula/formula-utils.ts +440 -0
- package/src/infrastructure/database/generators/index-generators.ts +152 -0
- package/src/infrastructure/database/generators/trigger-generators.ts +154 -0
- package/src/infrastructure/database/index.ts +35 -0
- package/src/infrastructure/database/lookup/lookup-expression-generators.ts +356 -0
- package/src/infrastructure/database/lookup/lookup-expressions.ts +116 -0
- package/src/infrastructure/database/lookup/lookup-view-generators.ts +403 -0
- package/src/infrastructure/database/lookup/lookup-view-helpers.ts +65 -0
- package/src/infrastructure/database/lookup/lookup-view-triggers.ts +121 -0
- package/src/infrastructure/database/migration-audit-trail.ts +375 -0
- package/src/infrastructure/database/repositories/activity-log-repository-live.ts +99 -0
- package/src/infrastructure/database/repositories/activity-repository-live.ts +21 -0
- package/src/infrastructure/database/repositories/analytics-repository-live.ts +316 -0
- package/src/infrastructure/database/repositories/auth-repository-live.ts +42 -0
- package/src/infrastructure/database/repositories/batch-repository-live.ts +29 -0
- package/src/infrastructure/database/repositories/comment-repository-live.ts +39 -0
- package/src/infrastructure/database/repositories/table-repository-live.ts +38 -0
- package/src/infrastructure/database/schema/schema-dependency-sorting.ts +142 -0
- package/src/infrastructure/database/schema/schema-initializer.ts +598 -0
- package/src/infrastructure/database/schema-migration/column-detection.ts +286 -0
- package/src/infrastructure/database/schema-migration/constants.ts +31 -0
- package/src/infrastructure/database/schema-migration/constraint-sync.ts +288 -0
- package/src/infrastructure/database/schema-migration/index-sync.ts +108 -0
- package/src/infrastructure/database/schema-migration/index.ts +66 -0
- package/src/infrastructure/database/schema-migration/migration-statements.ts +106 -0
- package/src/infrastructure/database/schema-migration/rename-detection.ts +87 -0
- package/src/infrastructure/database/schema-migration/table-operations.ts +65 -0
- package/src/infrastructure/database/schema-migration/type-utils.ts +98 -0
- package/src/infrastructure/database/schema-migration/types.ts +14 -0
- package/src/infrastructure/database/schema-migration-helpers.ts +53 -0
- package/src/infrastructure/database/session-context.ts +20 -0
- package/src/infrastructure/database/sql/sql-check-constraints.ts +252 -0
- package/src/infrastructure/database/sql/sql-column-generators.ts +174 -0
- package/src/infrastructure/database/sql/sql-execution.ts +245 -0
- package/src/infrastructure/database/sql/sql-field-predicates.ts +81 -0
- package/src/infrastructure/database/sql/sql-generators.ts +91 -0
- package/src/infrastructure/database/sql/sql-junction-tables.ts +79 -0
- package/src/infrastructure/database/sql/sql-key-constraints.ts +210 -0
- package/src/infrastructure/database/sql/sql-type-mappings.ts +106 -0
- package/src/infrastructure/database/sql/sql-utils.ts +53 -0
- package/src/infrastructure/database/table-live-layers.ts +30 -0
- package/src/infrastructure/database/table-operations/column-generators.ts +82 -0
- package/src/infrastructure/database/table-operations/create-table-sql.ts +81 -0
- package/src/infrastructure/database/table-operations/index.ts +55 -0
- package/src/infrastructure/database/table-operations/migration-utils.ts +157 -0
- package/src/infrastructure/database/table-operations/table-effects.ts +234 -0
- package/src/infrastructure/database/table-operations/table-features.ts +96 -0
- package/src/infrastructure/database/table-operations/type-compatibility.ts +58 -0
- package/src/infrastructure/database/table-operations.ts +47 -0
- package/src/infrastructure/database/table-queries/batch/batch-create.ts +80 -0
- package/src/infrastructure/database/table-queries/batch/batch-delete.ts +212 -0
- package/src/infrastructure/database/table-queries/batch/batch-helpers.ts +124 -0
- package/src/infrastructure/database/table-queries/batch/batch-restore.ts +161 -0
- package/src/infrastructure/database/table-queries/batch/batch-update.ts +146 -0
- package/src/infrastructure/database/table-queries/batch/batch-upsert.ts +357 -0
- package/src/infrastructure/database/table-queries/batch/batch.ts +14 -0
- package/src/infrastructure/database/table-queries/crud/crud-read.ts +351 -0
- package/src/infrastructure/database/table-queries/crud/crud-write.ts +399 -0
- package/src/infrastructure/database/table-queries/crud/crud.ts +16 -0
- package/src/infrastructure/database/table-queries/index.ts +11 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/authorship-helpers.ts +152 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/create-record-helpers.ts +90 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/delete-helpers.ts +163 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/record-fetch-helpers.ts +79 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/update-helpers.ts +74 -0
- package/src/infrastructure/database/table-queries/query-helpers/activity-log-helpers.ts +53 -0
- package/src/infrastructure/database/table-queries/query-helpers/activity-queries.ts +106 -0
- package/src/infrastructure/database/table-queries/query-helpers/aggregation-helpers.ts +314 -0
- package/src/infrastructure/database/table-queries/query-helpers/comment-queries.ts +414 -0
- package/src/infrastructure/database/table-queries/query-helpers/record-validation-queries.ts +126 -0
- package/src/infrastructure/database/table-queries/query-helpers/trash-helpers.ts +58 -0
- package/src/infrastructure/database/table-queries/shared/error-handling.ts +47 -0
- package/src/infrastructure/database/table-queries/shared/typed-execute.ts +27 -0
- package/src/infrastructure/database/table-queries/shared/user-join-helpers.ts +38 -0
- package/src/infrastructure/database/table-queries/shared/validation.ts +39 -0
- package/src/infrastructure/database/views/view-generators.ts +258 -0
- package/src/infrastructure/devtools/devtools-layer.ts +43 -0
- package/src/infrastructure/devtools/index.ts +8 -0
- package/src/infrastructure/email/email-config.ts +103 -0
- package/src/infrastructure/email/email-service.ts +152 -0
- package/src/infrastructure/email/index.ts +107 -0
- package/src/infrastructure/email/nodemailer.ts +125 -0
- package/src/infrastructure/email/templates.ts +244 -0
- package/src/infrastructure/errors/auth-config-required-error.ts +21 -0
- package/src/infrastructure/errors/auth-error.ts +16 -0
- package/src/infrastructure/errors/css-compilation-error.ts +14 -0
- package/src/infrastructure/errors/index.ts +26 -0
- package/src/infrastructure/errors/schema-initialization-error.ts +19 -0
- package/src/infrastructure/errors/server-creation-error.ts +14 -0
- package/src/infrastructure/filesystem/copy-directory.ts +136 -0
- package/src/infrastructure/layers/app-layer.ts +61 -0
- package/src/infrastructure/layers/page-renderer-layer.ts +41 -0
- package/src/infrastructure/logging/index.ts +8 -0
- package/src/infrastructure/logging/logger.ts +204 -0
- package/src/infrastructure/schema/file-loader.ts +53 -0
- package/src/infrastructure/schema/index.ts +15 -0
- package/src/infrastructure/schema/remote-loader.ts +48 -0
- package/src/infrastructure/server/index.ts +26 -0
- package/src/infrastructure/server/language-detection.ts +87 -0
- package/src/infrastructure/server/lifecycle.ts +67 -0
- package/src/infrastructure/server/route-setup/api-routes.ts +310 -0
- package/src/infrastructure/server/route-setup/auth-route-utils.ts +399 -0
- package/src/infrastructure/server/route-setup/auth-routes.ts +245 -0
- package/src/infrastructure/server/route-setup/openapi-routes.ts +45 -0
- package/src/infrastructure/server/route-setup/openapi-schema.ts +120 -0
- package/src/infrastructure/server/route-setup/page-routes.ts +219 -0
- package/src/infrastructure/server/route-setup/static-assets.ts +191 -0
- package/src/infrastructure/server/server-factory-live.ts +45 -0
- package/src/infrastructure/server/server.ts +275 -0
- package/src/infrastructure/server/ssg-adapter.ts +196 -0
- package/src/infrastructure/server/static-site-generator-live.ts +20 -0
- package/src/infrastructure/utils/accept-language-parser.ts +106 -0
- package/src/infrastructure/utils/glob-matcher.ts +50 -0
- package/src/presentation/api/client.ts +114 -0
- package/src/presentation/api/middleware/auth.ts +233 -0
- package/src/presentation/api/middleware/table.ts +155 -0
- package/src/presentation/api/middleware/validation.ts +88 -0
- package/src/presentation/api/routes/activity/get-activity-by-id-handler.ts +77 -0
- package/src/presentation/api/routes/activity/index.ts +28 -0
- package/src/presentation/api/routes/activity.ts +339 -0
- package/src/presentation/api/routes/analytics.ts +328 -0
- package/src/presentation/api/routes/auth.ts +169 -0
- package/src/presentation/api/routes/index.ts +11 -0
- package/src/presentation/api/routes/tables/activity-handlers.ts +57 -0
- package/src/presentation/api/routes/tables/batch-permission-helpers.ts +163 -0
- package/src/presentation/api/routes/tables/batch-routes.ts +355 -0
- package/src/presentation/api/routes/tables/comment-handlers.ts +377 -0
- package/src/presentation/api/routes/tables/create-record-helpers.ts +179 -0
- package/src/presentation/api/routes/tables/effect-runner.ts +58 -0
- package/src/presentation/api/routes/tables/error-handlers.ts +53 -0
- package/src/presentation/api/routes/tables/field-permission-validation.ts +167 -0
- package/src/presentation/api/routes/tables/filter-parser.ts +75 -0
- package/src/presentation/api/routes/tables/formula-parser.ts +118 -0
- package/src/presentation/api/routes/tables/index.ts +113 -0
- package/src/presentation/api/routes/tables/list-records-filter.ts +54 -0
- package/src/presentation/api/routes/tables/param-parsers.ts +59 -0
- package/src/presentation/api/routes/tables/record-handlers.ts +484 -0
- package/src/presentation/api/routes/tables/record-routes.ts +53 -0
- package/src/presentation/api/routes/tables/record-update-handler.ts +200 -0
- package/src/presentation/api/routes/tables/sort-validation.ts +85 -0
- package/src/presentation/api/routes/tables/table-routes.ts +76 -0
- package/src/presentation/api/routes/tables/timezone-validation.ts +41 -0
- package/src/presentation/api/routes/tables/upsert-helpers.ts +471 -0
- package/src/presentation/api/routes/tables/utils.ts +159 -0
- package/src/presentation/api/routes/tables/view-routes.ts +51 -0
- package/src/presentation/api/routes/tables.ts +9 -0
- package/src/presentation/api/utils/context-helpers.ts +43 -0
- package/src/presentation/api/utils/error-sanitizer.ts +235 -0
- package/src/presentation/api/utils/field-permission-validator.ts +53 -0
- package/src/presentation/api/utils/filter-field-validator.ts +90 -0
- package/src/presentation/api/utils/index.ts +13 -0
- package/src/presentation/api/utils/run-effect.ts +94 -0
- package/src/presentation/api/utils/validate-request.ts +89 -0
- package/src/presentation/api/validation/index.ts +29 -0
- package/src/presentation/api/validation/rules/field-rules.ts +158 -0
- package/src/presentation/api/validation/rules/record-rules.ts +73 -0
- package/src/presentation/cli/index.ts +19 -0
- package/src/presentation/cli/schema-loader.ts +172 -0
- package/src/presentation/hooks/use-breakpoint.ts +155 -0
- package/src/presentation/rendering/render-error-pages.tsx +60 -0
- package/src/presentation/rendering/render-homepage.tsx +137 -0
- package/src/presentation/scripts/script-renderers.ts +112 -0
- package/src/presentation/styling/animation-composer.ts +117 -0
- package/src/presentation/styling/index.ts +13 -0
- package/src/presentation/styling/parse-style.ts +243 -0
- package/src/presentation/styling/style-utils.ts +50 -0
- package/src/presentation/styling/theme-colors.ts +53 -0
- package/src/presentation/translations/component-utils.ts +54 -0
- package/src/presentation/translations/index.ts +16 -0
- package/src/presentation/translations/translation-resolver.ts +22 -0
- package/src/presentation/ui/languages/language-switcher.tsx +119 -0
- package/src/presentation/ui/metadata/analytics-builders.tsx +174 -0
- package/src/presentation/ui/metadata/analytics-head.tsx +39 -0
- package/src/presentation/ui/metadata/custom-elements-builders.tsx +157 -0
- package/src/presentation/ui/metadata/extract-component-meta.ts +108 -0
- package/src/presentation/ui/metadata/head-elements.tsx +164 -0
- package/src/presentation/ui/metadata/index.tsx +35 -0
- package/src/presentation/ui/metadata/meta-utils.tsx +42 -0
- package/src/presentation/ui/metadata/open-graph-meta.tsx +57 -0
- package/src/presentation/ui/metadata/structured-data-from-component.tsx +134 -0
- package/src/presentation/ui/metadata/structured-data.tsx +88 -0
- package/src/presentation/ui/metadata/twitter-card-meta.tsx +80 -0
- package/src/presentation/ui/pages/DefaultHomePage.tsx +43 -0
- package/src/presentation/ui/pages/DefaultPageConfigs.ts +220 -0
- package/src/presentation/ui/pages/DynamicPage.tsx +307 -0
- package/src/presentation/ui/pages/ErrorPage.tsx +25 -0
- package/src/presentation/ui/pages/NotFoundPage.tsx +25 -0
- package/src/presentation/ui/pages/PageBodyScripts.tsx +242 -0
- package/src/presentation/ui/pages/PageBodyStyles.ts +52 -0
- package/src/presentation/ui/pages/PageHead.tsx +380 -0
- package/src/presentation/ui/pages/PageLangResolver.ts +58 -0
- package/src/presentation/ui/pages/PageMain.tsx +58 -0
- package/src/presentation/ui/pages/PageMetadata.ts +168 -0
- package/src/presentation/ui/pages/PageMetadataI18n.ts +169 -0
- package/src/presentation/ui/pages/PageScripts.ts +78 -0
- package/src/presentation/ui/pages/SectionRenderer.tsx +67 -0
- package/src/presentation/ui/pages/SectionSpacing.tsx +131 -0
- package/src/presentation/ui/sections/component-renderer.tsx +426 -0
- package/src/presentation/ui/sections/component-renderer.types.ts +33 -0
- package/src/presentation/ui/sections/components/component-reference-handler.tsx +74 -0
- package/src/presentation/ui/sections/components/component-resolution.ts +65 -0
- package/src/presentation/ui/sections/components/index.ts +9 -0
- package/src/presentation/ui/sections/hero.tsx +394 -0
- package/src/presentation/ui/sections/props/component-builder.ts +183 -0
- package/src/presentation/ui/sections/props/element-props.ts +179 -0
- package/src/presentation/ui/sections/props/index.ts +9 -0
- package/src/presentation/ui/sections/props/prop-conversion.ts +171 -0
- package/src/presentation/ui/sections/props/props-builder-config.ts +42 -0
- package/src/presentation/ui/sections/props/props-builder.ts +296 -0
- package/src/presentation/ui/sections/renderers/element-renderers/html-element-renderer.tsx +124 -0
- package/src/presentation/ui/sections/renderers/element-renderers/index.ts +59 -0
- package/src/presentation/ui/sections/renderers/element-renderers/interactive-renderers.tsx +231 -0
- package/src/presentation/ui/sections/renderers/element-renderers/media-renderers.tsx +102 -0
- package/src/presentation/ui/sections/renderers/element-renderers/text-content-renderers.tsx +42 -0
- package/src/presentation/ui/sections/renderers/element-renderers.ts +53 -0
- package/src/presentation/ui/sections/renderers/html-element-helpers.ts +100 -0
- package/src/presentation/ui/sections/renderers/specialized-renderers.tsx +212 -0
- package/src/presentation/ui/sections/rendering/component-dispatch-config.ts +31 -0
- package/src/presentation/ui/sections/rendering/component-registry/index.ts +39 -0
- package/src/presentation/ui/sections/rendering/component-registry/interactive-components.ts +54 -0
- package/src/presentation/ui/sections/rendering/component-registry/media-components.ts +36 -0
- package/src/presentation/ui/sections/rendering/component-registry/special-components.tsx +153 -0
- package/src/presentation/ui/sections/rendering/component-registry/structural-components.ts +215 -0
- package/src/presentation/ui/sections/rendering/component-registry/text-components.ts +57 -0
- package/src/presentation/ui/sections/rendering/component-registry-helpers.tsx +29 -0
- package/src/presentation/ui/sections/rendering/component-registry.tsx +21 -0
- package/src/presentation/ui/sections/rendering/component-type-dispatcher.tsx +33 -0
- package/src/presentation/ui/sections/rendering/index.ts +9 -0
- package/src/presentation/ui/sections/responsive/responsive-children-builder.tsx +96 -0
- package/src/presentation/ui/sections/responsive/responsive-content-builder.tsx +95 -0
- package/src/presentation/ui/sections/responsive/responsive-props-merger.ts +195 -0
- package/src/presentation/ui/sections/responsive/responsive-resolver.ts +213 -0
- package/src/presentation/ui/sections/styling/animation-composer-wrapper.ts +65 -0
- package/src/presentation/ui/sections/styling/class-builders.ts +45 -0
- package/src/presentation/ui/sections/styling/color-resolver.ts +43 -0
- package/src/presentation/ui/sections/styling/hover-interaction-handler.ts +107 -0
- package/src/presentation/ui/sections/styling/index.ts +9 -0
- package/src/presentation/ui/sections/styling/interaction-props-builder.ts +55 -0
- package/src/presentation/ui/sections/styling/shadow-resolver.ts +83 -0
- package/src/presentation/ui/sections/styling/spacing-resolver.ts +104 -0
- package/src/presentation/ui/sections/styling/style-processor.ts +170 -0
- package/src/presentation/ui/sections/styling/theme-tokens.ts +184 -0
- package/src/presentation/ui/sections/translations/i18n-content-resolver.ts +198 -0
- package/src/presentation/ui/sections/translations/index.ts +9 -0
- package/src/presentation/ui/sections/translations/translation-handler.ts +143 -0
- package/src/presentation/ui/sections/translations/variable-substitution.ts +225 -0
- package/src/presentation/ui/sections/utils/time-parser.ts +82 -0
- package/src/presentation/utils/link-attributes.ts +50 -0
- package/src/presentation/utils/string-utils.ts +58 -0
- package/src/presentation/utils/styles.ts +50 -0
- package/tsconfig.json +46 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if field is a user reference field (created-by, updated-by, deleted-by)
|
|
12
|
+
* Used to determine if Better Auth users table is required
|
|
13
|
+
* Exported for use in schema-initializer
|
|
14
|
+
*/
|
|
15
|
+
export const isUserReferenceField = (field: Fields[number]): boolean =>
|
|
16
|
+
field.type === 'created-by' || field.type === 'updated-by' || field.type === 'deleted-by'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check if field is an auto-populated user reference field (created-by only)
|
|
20
|
+
* created-by is always NOT NULL because it's auto-populated on creation
|
|
21
|
+
* Note: updated-by is NOT included because it's only set during update (nullable until first update)
|
|
22
|
+
* Note: deleted-by is NOT included because it's only set during soft-delete (nullable)
|
|
23
|
+
*/
|
|
24
|
+
export const isAutoPopulatedUserField = (field: Fields[number]): boolean =>
|
|
25
|
+
field.type === 'created-by'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if field is a user field (type: 'user')
|
|
29
|
+
* Used to generate FOREIGN KEY constraints to users table
|
|
30
|
+
* Exported for use in schema-initializer
|
|
31
|
+
*/
|
|
32
|
+
export const isUserField = (field: Fields[number]): boolean => field.type === 'user'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if field is a relationship field (type: 'relationship')
|
|
36
|
+
* Used to generate FOREIGN KEY constraints to related tables
|
|
37
|
+
*/
|
|
38
|
+
export const isRelationshipField = (
|
|
39
|
+
field: Fields[number]
|
|
40
|
+
): field is Fields[number] & { type: 'relationship'; relatedTable: string } =>
|
|
41
|
+
field.type === 'relationship' && 'relatedTable' in field && typeof field.relatedTable === 'string'
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if field is an auto-timestamp field (created-at, updated-at)
|
|
45
|
+
*/
|
|
46
|
+
export const isAutoTimestampField = (field: Fields[number]): boolean =>
|
|
47
|
+
field.type === 'created-at' || field.type === 'updated-at'
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Check if field should use SERIAL type
|
|
51
|
+
*/
|
|
52
|
+
export const shouldUseSerial = (field: Fields[number], isPrimaryKey: boolean): boolean =>
|
|
53
|
+
field.type === 'autonumber' || (field.type === 'integer' && isPrimaryKey)
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if field should be NOT NULL
|
|
57
|
+
* Auto-managed fields (created-at, updated-at, created-by) and required fields are NOT NULL
|
|
58
|
+
* Note: When hasAuthConfig is false, created-by becomes NULLABLE (NULL when no auth)
|
|
59
|
+
* Note: updated-by is always nullable because it's only set during update (NULL until first update)
|
|
60
|
+
* Note: deleted-by is always nullable because it's only set during soft-delete
|
|
61
|
+
* Exported for use in schema-migration-helpers for nullability change detection
|
|
62
|
+
*
|
|
63
|
+
* @param hasAuthConfig - Whether auth is configured (default true). When false, auto-populated
|
|
64
|
+
* user fields (created-by) become nullable to support apps without authentication.
|
|
65
|
+
*/
|
|
66
|
+
export const isFieldNotNull = (
|
|
67
|
+
field: Fields[number],
|
|
68
|
+
isPrimaryKey: boolean,
|
|
69
|
+
hasAuthConfig: boolean = true
|
|
70
|
+
): boolean => {
|
|
71
|
+
// Auto-managed timestamp fields are always NOT NULL (created-at, updated-at)
|
|
72
|
+
if (isAutoTimestampField(field)) return true
|
|
73
|
+
// Auto-populated user fields (created-by) are NOT NULL only when auth is configured
|
|
74
|
+
// updated-by is excluded because it's only set during update (nullable until first update)
|
|
75
|
+
// deleted-by is excluded because it's only populated during soft-delete
|
|
76
|
+
if (isAutoPopulatedUserField(field)) return hasAuthConfig
|
|
77
|
+
// Primary key fields are always NOT NULL
|
|
78
|
+
if (isPrimaryKey) return true
|
|
79
|
+
// Check required property
|
|
80
|
+
return 'required' in field && field.required === true
|
|
81
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SQL Generators - PostgreSQL DDL Generation for Sovrium Tables
|
|
10
|
+
*
|
|
11
|
+
* This module coordinates SQL generation for table creation, constraints, and relationships.
|
|
12
|
+
* Implementation is split across focused modules:
|
|
13
|
+
* - sql-type-mappings.ts: Field type → PostgreSQL type conversions
|
|
14
|
+
* - sql-field-predicates.ts: Field type checking functions
|
|
15
|
+
* - sql-column-generators.ts: Column definition generation
|
|
16
|
+
* - sql-check-constraints.ts: CHECK constraint generation
|
|
17
|
+
* - sql-key-constraints.ts: UNIQUE, FOREIGN KEY, PRIMARY KEY constraints
|
|
18
|
+
* - sql-junction-tables.ts: Many-to-many relationship tables
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
generateArrayConstraints,
|
|
23
|
+
generateBarcodeConstraints,
|
|
24
|
+
generateColorConstraints,
|
|
25
|
+
generateCustomCheckConstraints,
|
|
26
|
+
generateEnumConstraints,
|
|
27
|
+
generateMultiSelectConstraints,
|
|
28
|
+
generateMultipleAttachmentsConstraints,
|
|
29
|
+
generateNumericConstraints,
|
|
30
|
+
generateProgressConstraints,
|
|
31
|
+
generateRichTextConstraints,
|
|
32
|
+
generateStatusConstraints,
|
|
33
|
+
} from './sql-check-constraints'
|
|
34
|
+
import {
|
|
35
|
+
generateCompositeUniqueConstraints,
|
|
36
|
+
generateForeignKeyConstraints,
|
|
37
|
+
generatePrimaryKeyConstraint,
|
|
38
|
+
generateUniqueConstraints,
|
|
39
|
+
} from './sql-key-constraints'
|
|
40
|
+
import type { Table } from '@/domain/models/app/table'
|
|
41
|
+
|
|
42
|
+
// Re-export from sql-type-mappings
|
|
43
|
+
export { mapFieldTypeToPostgres } from './sql-type-mappings'
|
|
44
|
+
|
|
45
|
+
// Re-export from sql-field-predicates
|
|
46
|
+
export {
|
|
47
|
+
isFieldNotNull,
|
|
48
|
+
isRelationshipField,
|
|
49
|
+
isUserField,
|
|
50
|
+
isUserReferenceField,
|
|
51
|
+
} from './sql-field-predicates'
|
|
52
|
+
|
|
53
|
+
// Re-export from sql-column-generators
|
|
54
|
+
export { generateColumnDefinition } from './sql-column-generators'
|
|
55
|
+
|
|
56
|
+
// Re-export from sql-key-constraints
|
|
57
|
+
export { generateForeignKeyConstraints, generateUniqueConstraints } from './sql-key-constraints'
|
|
58
|
+
|
|
59
|
+
// Re-export from sql-junction-tables
|
|
60
|
+
export {
|
|
61
|
+
generateJunctionTableDDL,
|
|
62
|
+
generateJunctionTableName,
|
|
63
|
+
toSingular,
|
|
64
|
+
} from './sql-junction-tables'
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generate table constraints (CHECK constraints, UNIQUE constraints, FOREIGN KEY, primary key, etc.)
|
|
68
|
+
*/
|
|
69
|
+
export const generateTableConstraints = (
|
|
70
|
+
table: Table,
|
|
71
|
+
tableUsesView?: ReadonlyMap<string, boolean>,
|
|
72
|
+
skipForeignKeys?: boolean
|
|
73
|
+
): readonly string[] => [
|
|
74
|
+
...generateArrayConstraints(table.fields),
|
|
75
|
+
...generateMultipleAttachmentsConstraints(table.fields),
|
|
76
|
+
...generateNumericConstraints(table.fields),
|
|
77
|
+
...generateProgressConstraints(table.fields),
|
|
78
|
+
...generateEnumConstraints(table.fields),
|
|
79
|
+
...generateMultiSelectConstraints(table.fields),
|
|
80
|
+
...generateStatusConstraints(table.fields),
|
|
81
|
+
...generateRichTextConstraints(table.fields),
|
|
82
|
+
...generateBarcodeConstraints(table.fields),
|
|
83
|
+
...generateColorConstraints(table.fields),
|
|
84
|
+
...generateCustomCheckConstraints(table.constraints),
|
|
85
|
+
...generatePrimaryKeyConstraint(table),
|
|
86
|
+
...generateUniqueConstraints(table.name, table.fields),
|
|
87
|
+
...generateCompositeUniqueConstraints(table),
|
|
88
|
+
...(skipForeignKeys
|
|
89
|
+
? []
|
|
90
|
+
: generateForeignKeyConstraints(table.name, table.fields, tableUsesView, table.foreignKeys)),
|
|
91
|
+
]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generate junction table name for many-to-many relationship
|
|
10
|
+
* Format: {table1}_{table2} (source table first, related table second)
|
|
11
|
+
*/
|
|
12
|
+
export const generateJunctionTableName = (sourceTable: string, relatedTable: string): string =>
|
|
13
|
+
`${sourceTable}_${relatedTable}`
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Common irregular plural to singular mappings for table naming
|
|
17
|
+
* Used by toSingular() to handle irregular English plurals
|
|
18
|
+
*/
|
|
19
|
+
const IRREGULAR_PLURALS: Readonly<Record<string, string>> = {
|
|
20
|
+
people: 'person',
|
|
21
|
+
children: 'child',
|
|
22
|
+
men: 'man',
|
|
23
|
+
women: 'woman',
|
|
24
|
+
teeth: 'tooth',
|
|
25
|
+
feet: 'foot',
|
|
26
|
+
geese: 'goose',
|
|
27
|
+
mice: 'mouse',
|
|
28
|
+
dice: 'die',
|
|
29
|
+
oxen: 'ox',
|
|
30
|
+
indices: 'index',
|
|
31
|
+
matrices: 'matrix',
|
|
32
|
+
vertices: 'vertex',
|
|
33
|
+
analyses: 'analysis',
|
|
34
|
+
criteria: 'criterion',
|
|
35
|
+
phenomena: 'phenomenon',
|
|
36
|
+
data: 'datum',
|
|
37
|
+
media: 'medium',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert table name to singular form for junction table column naming
|
|
42
|
+
* Uses irregular plural mapping with fallback to 's' removal heuristic
|
|
43
|
+
*/
|
|
44
|
+
export const toSingular = (tableName: string): string =>
|
|
45
|
+
IRREGULAR_PLURALS[tableName] ?? (tableName.endsWith('s') ? tableName.slice(0, -1) : tableName)
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generate CREATE TABLE statement for junction table (many-to-many relationship)
|
|
49
|
+
*
|
|
50
|
+
* Junction tables have:
|
|
51
|
+
* - Two foreign key columns: {sourceTable}_id, {relatedTable}_id (singular form)
|
|
52
|
+
* - Composite primary key on both columns
|
|
53
|
+
* - Foreign key constraints to both tables
|
|
54
|
+
*/
|
|
55
|
+
export const generateJunctionTableDDL = (
|
|
56
|
+
sourceTable: string,
|
|
57
|
+
relatedTable: string,
|
|
58
|
+
tableUsesView?: ReadonlyMap<string, boolean>
|
|
59
|
+
): string => {
|
|
60
|
+
const junctionTableName = generateJunctionTableName(sourceTable, relatedTable)
|
|
61
|
+
const sourceColumnName = `${toSingular(sourceTable)}_id`
|
|
62
|
+
const relatedColumnName = `${toSingular(relatedTable)}_id`
|
|
63
|
+
|
|
64
|
+
// Determine actual table names (base tables if using views)
|
|
65
|
+
const sourceTableName =
|
|
66
|
+
tableUsesView?.get(sourceTable) === true ? `${sourceTable}_base` : sourceTable
|
|
67
|
+
const relatedTableName =
|
|
68
|
+
tableUsesView?.get(relatedTable) === true ? `${relatedTable}_base` : relatedTable
|
|
69
|
+
|
|
70
|
+
const columns = [
|
|
71
|
+
`${sourceColumnName} INTEGER NOT NULL`,
|
|
72
|
+
`${relatedColumnName} INTEGER NOT NULL`,
|
|
73
|
+
`PRIMARY KEY (${sourceColumnName}, ${relatedColumnName})`,
|
|
74
|
+
`CONSTRAINT ${junctionTableName}_${sourceColumnName}_fkey FOREIGN KEY (${sourceColumnName}) REFERENCES ${sourceTableName}(id)`,
|
|
75
|
+
`CONSTRAINT ${junctionTableName}_${relatedColumnName}_fkey FOREIGN KEY (${relatedColumnName}) REFERENCES ${relatedTableName}(id)`,
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
return `CREATE TABLE IF NOT EXISTS ${junctionTableName} (\n ${columns.join(',\n ')}\n)`
|
|
79
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { isRelationshipField, isUserField, shouldUseSerial } from './sql-field-predicates'
|
|
9
|
+
import type { Table } from '@/domain/models/app/table'
|
|
10
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generate UNIQUE constraints for fields with unique property
|
|
14
|
+
* Uses PostgreSQL default naming convention: {table}_{column}_key
|
|
15
|
+
*
|
|
16
|
+
* NOTE: Geolocation fields are excluded because POINT type requires GiST index for UNIQUE,
|
|
17
|
+
* not btree. UNIQUE GiST indexes for geolocation fields are created separately in
|
|
18
|
+
* generateIndexStatements() in schema-initializer.ts
|
|
19
|
+
*/
|
|
20
|
+
export const generateUniqueConstraints = (
|
|
21
|
+
tableName: string,
|
|
22
|
+
fields: readonly Fields[number][]
|
|
23
|
+
): readonly string[] =>
|
|
24
|
+
fields
|
|
25
|
+
.filter(
|
|
26
|
+
(field): field is Fields[number] & { unique: true } =>
|
|
27
|
+
'unique' in field && !!field.unique && field.type !== 'geolocation'
|
|
28
|
+
)
|
|
29
|
+
.map((field) => `CONSTRAINT ${tableName}_${field.name}_key UNIQUE (${field.name})`)
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Map onDelete/onUpdate values to PostgreSQL referential actions
|
|
33
|
+
*
|
|
34
|
+
* @param action - The referential action (cascade, set-null, restrict, etc.)
|
|
35
|
+
* @param clauseType - The type of clause (delete or update)
|
|
36
|
+
* @returns PostgreSQL referential action clause (e.g., " ON DELETE CASCADE")
|
|
37
|
+
*/
|
|
38
|
+
const mapReferentialAction = (
|
|
39
|
+
action: string | undefined,
|
|
40
|
+
clauseType: 'delete' | 'update'
|
|
41
|
+
): string => {
|
|
42
|
+
if (!action) return ''
|
|
43
|
+
const upperAction = action.toUpperCase()
|
|
44
|
+
const validActions = ['CASCADE', 'SET NULL', 'SET DEFAULT', 'RESTRICT', 'NO ACTION']
|
|
45
|
+
|
|
46
|
+
// Map 'set-null' to 'SET NULL' for PostgreSQL compatibility
|
|
47
|
+
const normalizedAction = upperAction === 'SET-NULL' ? 'SET NULL' : upperAction
|
|
48
|
+
|
|
49
|
+
// Find matching PostgreSQL action
|
|
50
|
+
const postgresAction = validActions.find(
|
|
51
|
+
(valid) => valid.replace(' ', '-') === normalizedAction || valid === normalizedAction
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if (!postgresAction) return ''
|
|
55
|
+
|
|
56
|
+
const clausePrefix = clauseType === 'delete' ? 'ON DELETE' : 'ON UPDATE'
|
|
57
|
+
return ` ${clausePrefix} ${postgresAction}`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generate composite foreign key constraints from table.foreignKeys array
|
|
62
|
+
*/
|
|
63
|
+
const generateCompositeForeignKeyConstraints = (
|
|
64
|
+
compositeForeignKeys: readonly {
|
|
65
|
+
readonly name: string
|
|
66
|
+
readonly fields: readonly string[]
|
|
67
|
+
readonly referencedTable: string
|
|
68
|
+
readonly referencedFields: readonly string[]
|
|
69
|
+
readonly onDelete?: string
|
|
70
|
+
readonly onUpdate?: string
|
|
71
|
+
}[]
|
|
72
|
+
): readonly string[] =>
|
|
73
|
+
compositeForeignKeys.map((fk) => {
|
|
74
|
+
const localFields = fk.fields.join(', ')
|
|
75
|
+
const referencedFields = fk.referencedFields.join(', ')
|
|
76
|
+
const onDeleteClause = mapReferentialAction(fk.onDelete, 'delete')
|
|
77
|
+
const onUpdateClause = mapReferentialAction(fk.onUpdate, 'update')
|
|
78
|
+
|
|
79
|
+
return `CONSTRAINT ${fk.name} FOREIGN KEY (${localFields}) REFERENCES ${fk.referencedTable}(${referencedFields})${onDeleteClause}${onUpdateClause}`
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate FOREIGN KEY constraint for relationship field
|
|
84
|
+
*/
|
|
85
|
+
const generateRelationshipConstraint = (
|
|
86
|
+
tableName: string,
|
|
87
|
+
field: Fields[number] & { readonly type: 'relationship'; readonly relatedTable: string },
|
|
88
|
+
tableUsesView?: ReadonlyMap<string, boolean>
|
|
89
|
+
): string => {
|
|
90
|
+
const constraintName = `${tableName}_${field.name}_fkey`
|
|
91
|
+
// If the related table uses a VIEW (has lookup fields), reference the base table instead
|
|
92
|
+
const relatedTableName =
|
|
93
|
+
tableUsesView?.get(field.relatedTable) === true
|
|
94
|
+
? `${field.relatedTable}_base`
|
|
95
|
+
: field.relatedTable
|
|
96
|
+
|
|
97
|
+
// Build referential actions (ON DELETE, ON UPDATE)
|
|
98
|
+
const onDeleteClause =
|
|
99
|
+
'onDelete' in field ? mapReferentialAction(field.onDelete as string | undefined, 'delete') : ''
|
|
100
|
+
const onUpdateClause =
|
|
101
|
+
'onUpdate' in field ? mapReferentialAction(field.onUpdate as string | undefined, 'update') : ''
|
|
102
|
+
|
|
103
|
+
// Use relatedField if specified, otherwise default to 'id'
|
|
104
|
+
const referencedColumn = 'relatedField' in field && field.relatedField ? field.relatedField : 'id'
|
|
105
|
+
|
|
106
|
+
return `CONSTRAINT ${constraintName} FOREIGN KEY (${field.name}) REFERENCES ${relatedTableName}(${referencedColumn})${onDeleteClause}${onUpdateClause}`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Generate FOREIGN KEY constraints for user fields, relationship fields, and composite foreign keys
|
|
111
|
+
* Exported for use in migration system to sync FK constraints
|
|
112
|
+
*/
|
|
113
|
+
export const generateForeignKeyConstraints = (
|
|
114
|
+
tableName: string,
|
|
115
|
+
fields: readonly Fields[number][],
|
|
116
|
+
tableUsesView?: ReadonlyMap<string, boolean>,
|
|
117
|
+
compositeForeignKeys?: readonly {
|
|
118
|
+
readonly name: string
|
|
119
|
+
readonly fields: readonly string[]
|
|
120
|
+
readonly referencedTable: string
|
|
121
|
+
readonly referencedFields: readonly string[]
|
|
122
|
+
readonly onDelete?: string
|
|
123
|
+
readonly onUpdate?: string
|
|
124
|
+
}[]
|
|
125
|
+
): readonly string[] => {
|
|
126
|
+
// Generate foreign keys for user fields (type: 'user')
|
|
127
|
+
// References auth.user table (Better Auth users in dedicated auth schema)
|
|
128
|
+
const userFieldConstraints = fields.filter(isUserField).map((field) => {
|
|
129
|
+
const constraintName = `${tableName}_${field.name}_fkey`
|
|
130
|
+
return `CONSTRAINT ${constraintName} FOREIGN KEY (${field.name}) REFERENCES auth.user(id)`
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
// Generate foreign keys for relationship fields (type: 'relationship')
|
|
134
|
+
// Exclude one-to-many and many-to-many relationships as they don't create FK constraints on the parent side
|
|
135
|
+
const relationshipFieldConstraints = fields
|
|
136
|
+
.filter(isRelationshipField)
|
|
137
|
+
.filter((field) => {
|
|
138
|
+
// Only create FK for many-to-one relationships or relationships without explicit relationType
|
|
139
|
+
// Exclude one-to-many (FK in related table) and many-to-many (uses junction table)
|
|
140
|
+
return (
|
|
141
|
+
!('relationType' in field) ||
|
|
142
|
+
(field.relationType !== 'one-to-many' && field.relationType !== 'many-to-many')
|
|
143
|
+
)
|
|
144
|
+
})
|
|
145
|
+
.map((field) => generateRelationshipConstraint(tableName, field, tableUsesView))
|
|
146
|
+
|
|
147
|
+
// Foreign keys disabled for created-by/updated-by fields
|
|
148
|
+
// Blocked by: https://github.com/sovrium/sovrium/issues/3980
|
|
149
|
+
// Infrastructure ready - uncomment lines below when issue is resolved
|
|
150
|
+
const userReferenceConstraints: readonly string[] = []
|
|
151
|
+
// const userReferenceConstraints = fields
|
|
152
|
+
// .filter(isUserReferenceField)
|
|
153
|
+
// .map((field) => {
|
|
154
|
+
// const constraintName = `${tableName}_${field.name}_fkey`
|
|
155
|
+
// return `CONSTRAINT ${constraintName} FOREIGN KEY (${field.name}) REFERENCES auth.user(id)`
|
|
156
|
+
// })
|
|
157
|
+
|
|
158
|
+
// Generate composite foreign key constraints
|
|
159
|
+
const compositeFKs = generateCompositeForeignKeyConstraints(compositeForeignKeys ?? [])
|
|
160
|
+
|
|
161
|
+
return [
|
|
162
|
+
...userFieldConstraints,
|
|
163
|
+
...relationshipFieldConstraints,
|
|
164
|
+
...userReferenceConstraints,
|
|
165
|
+
...compositeFKs,
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generate primary key constraint if defined
|
|
171
|
+
* Skips single-field composite keys when the field is SERIAL (PRIMARY KEY is already inline)
|
|
172
|
+
* Note: Special field 'id' is automatically SERIAL, so PRIMARY KEY is inline
|
|
173
|
+
*/
|
|
174
|
+
export const generatePrimaryKeyConstraint = (table: Table): readonly string[] => {
|
|
175
|
+
if (table.primaryKey?.type === 'composite' && table.primaryKey.fields) {
|
|
176
|
+
// For single-field composite keys, check if the field is SERIAL (PRIMARY KEY already inline)
|
|
177
|
+
if (table.primaryKey.fields.length === 1) {
|
|
178
|
+
const pkFieldName = table.primaryKey.fields[0]
|
|
179
|
+
const pkField = table.fields.find((f) => f.name === pkFieldName)
|
|
180
|
+
|
|
181
|
+
// Special case: 'id' field is automatically SERIAL, PRIMARY KEY is inline
|
|
182
|
+
if (pkFieldName === 'id' && !pkField) {
|
|
183
|
+
// PRIMARY KEY is already inline in the automatic id column definition
|
|
184
|
+
return []
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (pkField && shouldUseSerial(pkField, true)) {
|
|
188
|
+
// PRIMARY KEY is already inline in the SERIAL column definition
|
|
189
|
+
return []
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return [`PRIMARY KEY (${table.primaryKey.fields.join(', ')})`]
|
|
193
|
+
}
|
|
194
|
+
return []
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Generate composite UNIQUE constraints from table.uniqueConstraints
|
|
199
|
+
* These are multi-column unique constraints (e.g., UNIQUE (email, tenant_id))
|
|
200
|
+
*/
|
|
201
|
+
export const generateCompositeUniqueConstraints = (table: Table): readonly string[] => {
|
|
202
|
+
if (!table.uniqueConstraints || table.uniqueConstraints.length === 0) {
|
|
203
|
+
return []
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return table.uniqueConstraints.map((constraint) => {
|
|
207
|
+
const fields = constraint.fields.join(', ')
|
|
208
|
+
return `CONSTRAINT ${constraint.name} UNIQUE (${fields})`
|
|
209
|
+
})
|
|
210
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Field type to PostgreSQL type mapping
|
|
12
|
+
* Note: button field type is included for type safety but should not create database columns
|
|
13
|
+
*/
|
|
14
|
+
export const fieldTypeToPostgresMap: Record<string, string> = {
|
|
15
|
+
integer: 'INTEGER',
|
|
16
|
+
autonumber: 'INTEGER',
|
|
17
|
+
decimal: 'DECIMAL',
|
|
18
|
+
'single-line-text': 'VARCHAR(255)',
|
|
19
|
+
'long-text': 'TEXT',
|
|
20
|
+
email: 'VARCHAR(255)',
|
|
21
|
+
url: 'VARCHAR(255)',
|
|
22
|
+
'phone-number': 'VARCHAR(255)',
|
|
23
|
+
'rich-text': 'TEXT',
|
|
24
|
+
checkbox: 'BOOLEAN',
|
|
25
|
+
boolean: 'BOOLEAN', // Alias for checkbox (used in tests)
|
|
26
|
+
date: 'DATE',
|
|
27
|
+
datetime: 'TIMESTAMPTZ',
|
|
28
|
+
time: 'TIME',
|
|
29
|
+
'single-select': 'VARCHAR(255)',
|
|
30
|
+
status: 'VARCHAR(255)',
|
|
31
|
+
'multi-select': 'TEXT[]',
|
|
32
|
+
currency: 'DECIMAL',
|
|
33
|
+
percentage: 'DECIMAL',
|
|
34
|
+
rating: 'INTEGER',
|
|
35
|
+
duration: 'INTERVAL',
|
|
36
|
+
color: 'VARCHAR(7)',
|
|
37
|
+
progress: 'INTEGER',
|
|
38
|
+
json: 'JSONB',
|
|
39
|
+
geolocation: 'POINT',
|
|
40
|
+
barcode: 'VARCHAR(255)',
|
|
41
|
+
'single-attachment': 'VARCHAR(255)',
|
|
42
|
+
'multiple-attachments': 'JSONB',
|
|
43
|
+
relationship: 'INTEGER',
|
|
44
|
+
lookup: 'TEXT',
|
|
45
|
+
rollup: 'TEXT',
|
|
46
|
+
count: 'INTEGER',
|
|
47
|
+
formula: 'TEXT',
|
|
48
|
+
user: 'TEXT',
|
|
49
|
+
'created-by': 'TEXT',
|
|
50
|
+
'updated-by': 'TEXT',
|
|
51
|
+
'deleted-by': 'TEXT',
|
|
52
|
+
'created-at': 'TIMESTAMP',
|
|
53
|
+
'updated-at': 'TIMESTAMP',
|
|
54
|
+
'deleted-at': 'TIMESTAMP',
|
|
55
|
+
button: 'TEXT',
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Map formula resultType to PostgreSQL type
|
|
60
|
+
*/
|
|
61
|
+
const formulaResultTypeMap: Record<string, string> = {
|
|
62
|
+
decimal: 'DECIMAL',
|
|
63
|
+
number: 'DECIMAL',
|
|
64
|
+
numeric: 'DECIMAL',
|
|
65
|
+
integer: 'INTEGER',
|
|
66
|
+
int: 'INTEGER',
|
|
67
|
+
boolean: 'BOOLEAN',
|
|
68
|
+
bool: 'BOOLEAN',
|
|
69
|
+
text: 'TEXT',
|
|
70
|
+
string: 'TEXT',
|
|
71
|
+
'text[]': 'TEXT[]',
|
|
72
|
+
'string[]': 'TEXT[]',
|
|
73
|
+
date: 'DATE',
|
|
74
|
+
datetime: 'TIMESTAMPTZ',
|
|
75
|
+
timestamp: 'TIMESTAMPTZ',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const mapFormulaResultTypeToPostgres = (resultType: string | undefined): string => {
|
|
79
|
+
if (!resultType) return 'TEXT'
|
|
80
|
+
return formulaResultTypeMap[resultType.toLowerCase()] ?? 'TEXT'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Map field type to PostgreSQL column type
|
|
85
|
+
* Throws error if field type is not recognized
|
|
86
|
+
*/
|
|
87
|
+
export const mapFieldTypeToPostgres = (field: Fields[number]): string => {
|
|
88
|
+
if (field.type === 'array') {
|
|
89
|
+
const itemType = 'itemType' in field && field.itemType ? field.itemType : 'text'
|
|
90
|
+
return `${itemType.toUpperCase()}[]`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Handle decimal/currency/percentage with precision
|
|
94
|
+
const numericTypesWithPrecision = ['decimal', 'currency', 'percentage']
|
|
95
|
+
if (numericTypesWithPrecision.includes(field.type) && 'precision' in field && field.precision) {
|
|
96
|
+
return `NUMERIC(${field.precision},2)`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const postgresType = fieldTypeToPostgresMap[field.type]
|
|
100
|
+
if (!postgresType) {
|
|
101
|
+
// eslint-disable-next-line functional/no-throw-statements -- Error is caught by Effect.try in table-operations.ts
|
|
102
|
+
throw new Error(`Unknown field type: ${field.type}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return postgresType
|
|
106
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Escape single quotes in SQL string literals to prevent SQL injection
|
|
10
|
+
* PostgreSQL escapes single quotes by doubling them: ' becomes ''
|
|
11
|
+
*
|
|
12
|
+
* Used across all SQL generators (view-generators, lookup-view-generators, sql-generators)
|
|
13
|
+
*/
|
|
14
|
+
export const escapeSqlString = (value: string): string => value.replace(/'/g, "''")
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Format a value for SQL interpolation with proper escaping
|
|
18
|
+
* Strings are escaped and quoted, numbers/booleans are used directly
|
|
19
|
+
*/
|
|
20
|
+
export const formatSqlValue = (value: unknown): string => {
|
|
21
|
+
if (typeof value === 'string') {
|
|
22
|
+
return `'${escapeSqlString(value)}'`
|
|
23
|
+
}
|
|
24
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
25
|
+
return String(value)
|
|
26
|
+
}
|
|
27
|
+
if (value === null) {
|
|
28
|
+
return 'NULL'
|
|
29
|
+
}
|
|
30
|
+
// For other types (objects, arrays), convert to JSON string
|
|
31
|
+
return `'${escapeSqlString(JSON.stringify(value))}'`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Generate SQL LIKE pattern with wildcards for pattern matching operators
|
|
36
|
+
* Automatically escapes the value to prevent SQL injection
|
|
37
|
+
*/
|
|
38
|
+
export const formatLikePattern = (
|
|
39
|
+
value: unknown,
|
|
40
|
+
pattern: 'contains' | 'startsWith' | 'endsWith'
|
|
41
|
+
): string => {
|
|
42
|
+
const stringValue = typeof value === 'string' ? value : String(value)
|
|
43
|
+
const escaped = escapeSqlString(stringValue)
|
|
44
|
+
|
|
45
|
+
switch (pattern) {
|
|
46
|
+
case 'contains':
|
|
47
|
+
return `'%${escaped}%'`
|
|
48
|
+
case 'startsWith':
|
|
49
|
+
return `'${escaped}%'`
|
|
50
|
+
case 'endsWith':
|
|
51
|
+
return `'%${escaped}'`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Layer } from 'effect'
|
|
9
|
+
import { ActivityRepositoryLive } from './repositories/activity-repository-live'
|
|
10
|
+
import { BatchRepositoryLive } from './repositories/batch-repository-live'
|
|
11
|
+
import { CommentRepositoryLive } from './repositories/comment-repository-live'
|
|
12
|
+
import { TableRepositoryLive } from './repositories/table-repository-live'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Composite layer providing all table-related repository implementations
|
|
16
|
+
*
|
|
17
|
+
* Import this single layer in presentation routes to satisfy
|
|
18
|
+
* all table, batch, comment, and activity repository requirements.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* runEffect(c, program.pipe(Effect.provide(TableLive)), schema)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const TableLive = Layer.mergeAll(
|
|
26
|
+
TableRepositoryLive,
|
|
27
|
+
BatchRepositoryLive,
|
|
28
|
+
CommentRepositoryLive,
|
|
29
|
+
ActivityRepositoryLive
|
|
30
|
+
)
|