@rippling/rippling-sdk 0.2.0-alpha.85 → 0.2.0-alpha.87
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/client.d.mts +15 -0
- package/client.d.mts.map +1 -1
- package/client.d.ts +15 -0
- package/client.d.ts.map +1 -1
- package/client.js +15 -0
- package/client.js.map +1 -1
- package/client.mjs +15 -0
- package/client.mjs.map +1 -1
- package/core/platform/custom-objects/category.d.mts +125 -0
- package/core/platform/custom-objects/category.d.mts.map +1 -0
- package/core/platform/custom-objects/category.d.ts +125 -0
- package/core/platform/custom-objects/category.d.ts.map +1 -0
- package/core/platform/custom-objects/category.js +188 -0
- package/core/platform/custom-objects/category.js.map +1 -0
- package/core/platform/custom-objects/category.mjs +178 -0
- package/core/platform/custom-objects/category.mjs.map +1 -0
- package/core/platform/custom-objects/definition.d.mts +147 -0
- package/core/platform/custom-objects/definition.d.mts.map +1 -0
- package/core/platform/custom-objects/definition.d.ts +147 -0
- package/core/platform/custom-objects/definition.d.ts.map +1 -0
- package/core/platform/custom-objects/definition.js +200 -0
- package/core/platform/custom-objects/definition.js.map +1 -0
- package/core/platform/custom-objects/definition.mjs +190 -0
- package/core/platform/custom-objects/definition.mjs.map +1 -0
- package/core/platform/custom-objects/fields.d.mts +302 -0
- package/core/platform/custom-objects/fields.d.mts.map +1 -0
- package/core/platform/custom-objects/fields.d.ts +302 -0
- package/core/platform/custom-objects/fields.d.ts.map +1 -0
- package/core/platform/custom-objects/fields.js +369 -0
- package/core/platform/custom-objects/fields.js.map +1 -0
- package/core/platform/custom-objects/fields.mjs +347 -0
- package/core/platform/custom-objects/fields.mjs.map +1 -0
- package/core/platform/custom-objects/function-runtime.d.mts +42 -0
- package/core/platform/custom-objects/function-runtime.d.mts.map +1 -0
- package/core/platform/custom-objects/function-runtime.d.ts +42 -0
- package/core/platform/custom-objects/function-runtime.d.ts.map +1 -0
- package/core/platform/custom-objects/function-runtime.js +38 -0
- package/core/platform/custom-objects/function-runtime.js.map +1 -0
- package/core/platform/custom-objects/function-runtime.mjs +35 -0
- package/core/platform/custom-objects/function-runtime.mjs.map +1 -0
- package/core/platform/custom-objects/lifecycle.d.mts +83 -0
- package/core/platform/custom-objects/lifecycle.d.mts.map +1 -0
- package/core/platform/custom-objects/lifecycle.d.ts +83 -0
- package/core/platform/custom-objects/lifecycle.d.ts.map +1 -0
- package/core/platform/custom-objects/lifecycle.js +372 -0
- package/core/platform/custom-objects/lifecycle.js.map +1 -0
- package/core/platform/custom-objects/lifecycle.mjs +367 -0
- package/core/platform/custom-objects/lifecycle.mjs.map +1 -0
- package/core/platform/custom-objects/manager.d.mts +354 -0
- package/core/platform/custom-objects/manager.d.mts.map +1 -0
- package/core/platform/custom-objects/manager.d.ts +354 -0
- package/core/platform/custom-objects/manager.d.ts.map +1 -0
- package/core/platform/custom-objects/manager.js +646 -0
- package/core/platform/custom-objects/manager.js.map +1 -0
- package/core/platform/custom-objects/manager.mjs +637 -0
- package/core/platform/custom-objects/manager.mjs.map +1 -0
- package/core/platform/custom-objects/provisioning.d.mts +138 -0
- package/core/platform/custom-objects/provisioning.d.mts.map +1 -0
- package/core/platform/custom-objects/provisioning.d.ts +138 -0
- package/core/platform/custom-objects/provisioning.d.ts.map +1 -0
- package/core/platform/custom-objects/provisioning.js +455 -0
- package/core/platform/custom-objects/provisioning.js.map +1 -0
- package/core/platform/custom-objects/provisioning.mjs +447 -0
- package/core/platform/custom-objects/provisioning.mjs.map +1 -0
- package/core/platform/custom-objects/rql.d.mts +122 -0
- package/core/platform/custom-objects/rql.d.mts.map +1 -0
- package/core/platform/custom-objects/rql.d.ts +122 -0
- package/core/platform/custom-objects/rql.d.ts.map +1 -0
- package/core/platform/custom-objects/rql.js +225 -0
- package/core/platform/custom-objects/rql.js.map +1 -0
- package/core/platform/custom-objects/rql.mjs +222 -0
- package/core/platform/custom-objects/rql.mjs.map +1 -0
- package/core/platform/custom-objects/schema-manager.d.mts +203 -0
- package/core/platform/custom-objects/schema-manager.d.mts.map +1 -0
- package/core/platform/custom-objects/schema-manager.d.ts +203 -0
- package/core/platform/custom-objects/schema-manager.d.ts.map +1 -0
- package/core/platform/custom-objects/schema-manager.js +256 -0
- package/core/platform/custom-objects/schema-manager.js.map +1 -0
- package/core/platform/custom-objects/schema-manager.mjs +249 -0
- package/core/platform/custom-objects/schema-manager.mjs.map +1 -0
- package/core/platform/custom-objects/typed-rql.d.mts +157 -0
- package/core/platform/custom-objects/typed-rql.d.mts.map +1 -0
- package/core/platform/custom-objects/typed-rql.d.ts +157 -0
- package/core/platform/custom-objects/typed-rql.d.ts.map +1 -0
- package/core/platform/custom-objects/typed-rql.js +583 -0
- package/core/platform/custom-objects/typed-rql.js.map +1 -0
- package/core/platform/custom-objects/typed-rql.mjs +580 -0
- package/core/platform/custom-objects/typed-rql.mjs.map +1 -0
- package/core/platform/custom-objects/types.d.mts +549 -0
- package/core/platform/custom-objects/types.d.mts.map +1 -0
- package/core/platform/custom-objects/types.d.ts +549 -0
- package/core/platform/custom-objects/types.d.ts.map +1 -0
- package/core/platform/custom-objects/types.js +20 -0
- package/core/platform/custom-objects/types.js.map +1 -0
- package/core/platform/custom-objects/types.mjs +17 -0
- package/core/platform/custom-objects/types.mjs.map +1 -0
- package/core/platform/custom-objects/validation.d.mts +97 -0
- package/core/platform/custom-objects/validation.d.mts.map +1 -0
- package/core/platform/custom-objects/validation.d.ts +97 -0
- package/core/platform/custom-objects/validation.d.ts.map +1 -0
- package/core/platform/custom-objects/validation.js +477 -0
- package/core/platform/custom-objects/validation.js.map +1 -0
- package/core/platform/custom-objects/validation.mjs +465 -0
- package/core/platform/custom-objects/validation.mjs.map +1 -0
- package/core/platform/custom-objects.d.mts +67 -0
- package/core/platform/custom-objects.d.mts.map +1 -0
- package/core/platform/custom-objects.d.ts +67 -0
- package/core/platform/custom-objects.d.ts.map +1 -0
- package/core/platform/custom-objects.js +118 -0
- package/core/platform/custom-objects.js.map +1 -0
- package/core/platform/custom-objects.mjs +45 -0
- package/core/platform/custom-objects.mjs.map +1 -0
- package/lib/leave-programs/advanced.d.mts +5 -0
- package/lib/leave-programs/advanced.d.mts.map +1 -0
- package/lib/leave-programs/advanced.d.ts +5 -0
- package/lib/leave-programs/advanced.d.ts.map +1 -0
- package/lib/leave-programs/advanced.js +13 -0
- package/lib/leave-programs/advanced.js.map +1 -0
- package/lib/leave-programs/advanced.mjs +4 -0
- package/lib/leave-programs/advanced.mjs.map +1 -0
- package/lib/leave-programs/context.d.mts +3 -0
- package/lib/leave-programs/context.d.mts.map +1 -0
- package/lib/leave-programs/context.d.ts +3 -0
- package/lib/leave-programs/context.d.ts.map +1 -0
- package/lib/leave-programs/context.js +89 -0
- package/lib/leave-programs/context.js.map +1 -0
- package/lib/leave-programs/context.mjs +86 -0
- package/lib/leave-programs/context.mjs.map +1 -0
- package/lib/leave-programs/define-company-leave-program.d.mts +3 -0
- package/lib/leave-programs/define-company-leave-program.d.mts.map +1 -0
- package/lib/leave-programs/define-company-leave-program.d.ts +3 -0
- package/lib/leave-programs/define-company-leave-program.d.ts.map +1 -0
- package/lib/leave-programs/define-company-leave-program.js +47 -0
- package/lib/leave-programs/define-company-leave-program.js.map +1 -0
- package/lib/leave-programs/define-company-leave-program.mjs +44 -0
- package/lib/leave-programs/define-company-leave-program.mjs.map +1 -0
- package/lib/leave-programs/duration.d.mts +5 -0
- package/lib/leave-programs/duration.d.mts.map +1 -0
- package/lib/leave-programs/duration.d.ts +5 -0
- package/lib/leave-programs/duration.d.ts.map +1 -0
- package/lib/leave-programs/duration.js +21 -0
- package/lib/leave-programs/duration.js.map +1 -0
- package/lib/leave-programs/duration.mjs +16 -0
- package/lib/leave-programs/duration.mjs.map +1 -0
- package/lib/leave-programs/pay.d.mts +4 -0
- package/lib/leave-programs/pay.d.mts.map +1 -0
- package/lib/leave-programs/pay.d.ts +4 -0
- package/lib/leave-programs/pay.d.ts.map +1 -0
- package/lib/leave-programs/pay.js +20 -0
- package/lib/leave-programs/pay.js.map +1 -0
- package/lib/leave-programs/pay.mjs +16 -0
- package/lib/leave-programs/pay.mjs.map +1 -0
- package/lib/leave-programs/policy-builder.d.mts +20 -0
- package/lib/leave-programs/policy-builder.d.mts.map +1 -0
- package/lib/leave-programs/policy-builder.d.ts +20 -0
- package/lib/leave-programs/policy-builder.d.ts.map +1 -0
- package/lib/leave-programs/policy-builder.js +89 -0
- package/lib/leave-programs/policy-builder.js.map +1 -0
- package/lib/leave-programs/policy-builder.mjs +85 -0
- package/lib/leave-programs/policy-builder.mjs.map +1 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.d.mts +25 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.d.mts.map +1 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.d.ts +25 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.d.ts.map +1 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.js +56 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.js.map +1 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.mjs +53 -0
- package/lib/leave-programs/recipes/parental-top-up-policy.mjs.map +1 -0
- package/lib/leave-programs/testing.d.mts +8 -0
- package/lib/leave-programs/testing.d.mts.map +1 -0
- package/lib/leave-programs/testing.d.ts +8 -0
- package/lib/leave-programs/testing.d.ts.map +1 -0
- package/lib/leave-programs/testing.js +11 -0
- package/lib/leave-programs/testing.js.map +1 -0
- package/lib/leave-programs/testing.mjs +7 -0
- package/lib/leave-programs/testing.mjs.map +1 -0
- package/lib/leave-programs/types.d.mts +223 -0
- package/lib/leave-programs/types.d.mts.map +1 -0
- package/lib/leave-programs/types.d.ts +223 -0
- package/lib/leave-programs/types.d.ts.map +1 -0
- package/lib/leave-programs/types.js +10 -0
- package/lib/leave-programs/types.js.map +1 -0
- package/lib/leave-programs/types.mjs +7 -0
- package/lib/leave-programs/types.mjs.map +1 -0
- package/lib/leave-programs.d.mts +7 -0
- package/lib/leave-programs.d.mts.map +1 -0
- package/lib/leave-programs.d.ts +7 -0
- package/lib/leave-programs.d.ts.map +1 -0
- package/lib/leave-programs.js +19 -0
- package/lib/leave-programs.js.map +1 -0
- package/lib/leave-programs.mjs +7 -0
- package/lib/leave-programs.mjs.map +1 -0
- package/package.json +1 -1
- package/resources/agents/agents.d.mts +208 -0
- package/resources/agents/agents.d.mts.map +1 -0
- package/resources/agents/agents.d.ts +208 -0
- package/resources/agents/agents.d.ts.map +1 -0
- package/resources/agents/agents.js +64 -0
- package/resources/agents/agents.js.map +1 -0
- package/resources/agents/agents.mjs +59 -0
- package/resources/agents/agents.mjs.map +1 -0
- package/resources/agents/deployments.d.mts +180 -0
- package/resources/agents/deployments.d.mts.map +1 -0
- package/resources/agents/deployments.d.ts +180 -0
- package/resources/agents/deployments.d.ts.map +1 -0
- package/resources/agents/deployments.js +32 -0
- package/resources/agents/deployments.js.map +1 -0
- package/resources/agents/deployments.mjs +28 -0
- package/resources/agents/deployments.mjs.map +1 -0
- package/resources/agents/index.d.mts +5 -0
- package/resources/agents/index.d.mts.map +1 -0
- package/resources/agents/index.d.ts +5 -0
- package/resources/agents/index.d.ts.map +1 -0
- package/resources/agents/index.js +13 -0
- package/resources/agents/index.js.map +1 -0
- package/resources/agents/index.mjs +6 -0
- package/resources/agents/index.mjs.map +1 -0
- package/resources/agents/sessions/events.d.mts +80 -0
- package/resources/agents/sessions/events.d.mts.map +1 -0
- package/resources/agents/sessions/events.d.ts +80 -0
- package/resources/agents/sessions/events.d.ts.map +1 -0
- package/resources/agents/sessions/events.js +19 -0
- package/resources/agents/sessions/events.js.map +1 -0
- package/resources/agents/sessions/events.mjs +15 -0
- package/resources/agents/sessions/events.mjs.map +1 -0
- package/resources/agents/sessions/index.d.mts +3 -0
- package/resources/agents/sessions/index.d.mts.map +1 -0
- package/resources/agents/sessions/index.d.ts +3 -0
- package/resources/agents/sessions/index.d.ts.map +1 -0
- package/resources/agents/sessions/index.js +9 -0
- package/resources/agents/sessions/index.js.map +1 -0
- package/resources/agents/sessions/index.mjs +4 -0
- package/resources/agents/sessions/index.mjs.map +1 -0
- package/resources/agents/sessions/sessions.d.mts +153 -0
- package/resources/agents/sessions/sessions.d.mts.map +1 -0
- package/resources/agents/sessions/sessions.d.ts +153 -0
- package/resources/agents/sessions/sessions.d.ts.map +1 -0
- package/resources/agents/sessions/sessions.js +44 -0
- package/resources/agents/sessions/sessions.js.map +1 -0
- package/resources/agents/sessions/sessions.mjs +39 -0
- package/resources/agents/sessions/sessions.mjs.map +1 -0
- package/resources/agents/sessions.d.mts +2 -0
- package/resources/agents/sessions.d.mts.map +1 -0
- package/resources/agents/sessions.d.ts +2 -0
- package/resources/agents/sessions.d.ts.map +1 -0
- package/resources/agents/sessions.js +6 -0
- package/resources/agents/sessions.js.map +1 -0
- package/resources/agents/sessions.mjs +3 -0
- package/resources/agents/sessions.mjs.map +1 -0
- package/resources/agents/source-revisions.d.mts +195 -0
- package/resources/agents/source-revisions.d.mts.map +1 -0
- package/resources/agents/source-revisions.d.ts +195 -0
- package/resources/agents/source-revisions.d.ts.map +1 -0
- package/resources/agents/source-revisions.js +32 -0
- package/resources/agents/source-revisions.js.map +1 -0
- package/resources/agents/source-revisions.mjs +28 -0
- package/resources/agents/source-revisions.mjs.map +1 -0
- package/resources/agents.d.mts +2 -0
- package/resources/agents.d.mts.map +1 -0
- package/resources/agents.d.ts +2 -0
- package/resources/agents.d.ts.map +1 -0
- package/resources/agents.js +6 -0
- package/resources/agents.js.map +1 -0
- package/resources/agents.mjs +3 -0
- package/resources/agents.mjs.map +1 -0
- package/resources/break-policies.d.mts +1 -1
- package/resources/break-policies.d.ts +1 -1
- package/resources/break-policies.js +1 -1
- package/resources/break-policies.mjs +1 -1
- package/resources/break-types.d.mts +1 -1
- package/resources/break-types.d.ts +1 -1
- package/resources/break-types.js +1 -1
- package/resources/break-types.mjs +1 -1
- package/resources/business-structure-paths.d.mts +1 -1
- package/resources/business-structure-paths.d.ts +1 -1
- package/resources/business-structure-paths.js +1 -1
- package/resources/business-structure-paths.mjs +1 -1
- package/resources/candidate-applications.d.mts +1 -1
- package/resources/candidate-applications.d.ts +1 -1
- package/resources/candidate-applications.js +1 -1
- package/resources/candidate-applications.mjs +1 -1
- package/resources/candidates.d.mts +1 -1
- package/resources/candidates.d.ts +1 -1
- package/resources/candidates.js +1 -1
- package/resources/candidates.mjs +1 -1
- package/resources/company-legal-entities.d.mts +1 -1
- package/resources/company-legal-entities.d.ts +1 -1
- package/resources/company-legal-entities.js +1 -1
- package/resources/company-legal-entities.mjs +1 -1
- package/resources/company-legal-entity-workers.d.mts +1 -1
- package/resources/company-legal-entity-workers.d.ts +1 -1
- package/resources/company-legal-entity-workers.js +1 -1
- package/resources/company-legal-entity-workers.mjs +1 -1
- package/resources/compensation-bands-details.d.mts +1 -1
- package/resources/compensation-bands-details.d.ts +1 -1
- package/resources/compensation-bands-details.js +1 -1
- package/resources/compensation-bands-details.mjs +1 -1
- package/resources/compensations.d.mts +1 -1
- package/resources/compensations.d.ts +1 -1
- package/resources/compensations.js +1 -1
- package/resources/compensations.mjs +1 -1
- package/resources/custom-objects/custom-objects.d.mts +7 -0
- package/resources/custom-objects/custom-objects.d.mts.map +1 -1
- package/resources/custom-objects/custom-objects.d.ts +7 -0
- package/resources/custom-objects/custom-objects.d.ts.map +1 -1
- package/resources/custom-objects/custom-objects.js.map +1 -1
- package/resources/custom-objects/custom-objects.mjs.map +1 -1
- package/resources/custom-objects/fields.d.mts +129 -54
- package/resources/custom-objects/fields.d.mts.map +1 -1
- package/resources/custom-objects/fields.d.ts +129 -54
- package/resources/custom-objects/fields.d.ts.map +1 -1
- package/resources/device-orders.d.mts +1 -1
- package/resources/device-orders.d.ts +1 -1
- package/resources/device-orders.js +1 -1
- package/resources/device-orders.mjs +1 -1
- package/resources/devices.d.mts +1 -1
- package/resources/devices.d.ts +1 -1
- package/resources/devices.js +1 -1
- package/resources/devices.mjs +1 -1
- package/resources/functions/deployments.d.mts +2 -2
- package/resources/functions/deployments.d.ts +2 -2
- package/resources/functions/deployments.js +2 -2
- package/resources/functions/deployments.mjs +2 -2
- package/resources/functions/executions.d.mts +2 -2
- package/resources/functions/executions.d.ts +2 -2
- package/resources/functions/executions.js +2 -2
- package/resources/functions/executions.mjs +2 -2
- package/resources/functions/functions.d.mts +1 -1
- package/resources/functions/functions.d.ts +1 -1
- package/resources/functions/functions.js +1 -1
- package/resources/functions/functions.mjs +1 -1
- package/resources/headcount-positions.d.mts +1 -1
- package/resources/headcount-positions.d.ts +1 -1
- package/resources/headcount-positions.js +1 -1
- package/resources/headcount-positions.mjs +1 -1
- package/resources/headcount-priorities.d.mts +1 -1
- package/resources/headcount-priorities.d.ts +1 -1
- package/resources/headcount-priorities.js +1 -1
- package/resources/headcount-priorities.mjs +1 -1
- package/resources/index.d.mts +3 -0
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +3 -0
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +8 -2
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +3 -0
- package/resources/index.mjs.map +1 -1
- package/resources/job-assignments.d.mts +2 -2
- package/resources/job-assignments.d.ts +2 -2
- package/resources/job-assignments.js +2 -2
- package/resources/job-assignments.mjs +2 -2
- package/resources/job-codes.d.mts +2 -2
- package/resources/job-codes.d.ts +2 -2
- package/resources/job-codes.js +2 -2
- package/resources/job-codes.mjs +2 -2
- package/resources/job-dimensions.d.mts +1 -1
- package/resources/job-dimensions.d.ts +1 -1
- package/resources/job-dimensions.js +1 -1
- package/resources/job-dimensions.mjs +1 -1
- package/resources/job-pay-rate-exceptions.d.mts +2 -2
- package/resources/job-pay-rate-exceptions.d.ts +2 -2
- package/resources/job-pay-rate-exceptions.js +2 -2
- package/resources/job-pay-rate-exceptions.mjs +2 -2
- package/resources/job-requisitions.d.mts +1 -1
- package/resources/job-requisitions.d.ts +1 -1
- package/resources/job-requisitions.js +1 -1
- package/resources/job-requisitions.mjs +1 -1
- package/resources/kiosk-badges.d.mts +1 -1
- package/resources/kiosk-badges.d.ts +1 -1
- package/resources/kiosk-badges.js +1 -1
- package/resources/kiosk-badges.mjs +1 -1
- package/resources/leave-accruals.d.mts +1 -1
- package/resources/leave-accruals.d.ts +1 -1
- package/resources/leave-accruals.js +1 -1
- package/resources/leave-accruals.mjs +1 -1
- package/resources/leave-balances.d.mts +1 -1
- package/resources/leave-balances.d.ts +1 -1
- package/resources/leave-balances.js +1 -1
- package/resources/leave-balances.mjs +1 -1
- package/resources/leave-requests.d.mts +1 -1
- package/resources/leave-requests.d.ts +1 -1
- package/resources/leave-requests.js +1 -1
- package/resources/leave-requests.mjs +1 -1
- package/resources/leave-types.d.mts +1 -1
- package/resources/leave-types.d.ts +1 -1
- package/resources/leave-types.js +1 -1
- package/resources/leave-types.mjs +1 -1
- package/resources/legal-entities.d.mts +1 -1
- package/resources/legal-entities.d.ts +1 -1
- package/resources/legal-entities.js +1 -1
- package/resources/legal-entities.mjs +1 -1
- package/resources/levels.d.mts +26 -5
- package/resources/levels.d.mts.map +1 -1
- package/resources/levels.d.ts +26 -5
- package/resources/levels.d.ts.map +1 -1
- package/resources/levels.js +1 -1
- package/resources/levels.mjs +1 -1
- package/resources/location-factors.d.mts +1 -1
- package/resources/location-factors.d.ts +1 -1
- package/resources/location-factors.js +1 -1
- package/resources/location-factors.mjs +1 -1
- package/resources/packages/index.d.mts +3 -0
- package/resources/packages/index.d.mts.map +1 -0
- package/resources/packages/index.d.ts +3 -0
- package/resources/packages/index.d.ts.map +1 -0
- package/resources/packages/index.js +9 -0
- package/resources/packages/index.js.map +1 -0
- package/resources/packages/index.mjs +4 -0
- package/resources/packages/index.mjs.map +1 -0
- package/resources/packages/packages.d.mts +239 -0
- package/resources/packages/packages.d.mts.map +1 -0
- package/resources/packages/packages.d.ts +239 -0
- package/resources/packages/packages.d.ts.map +1 -0
- package/resources/packages/packages.js +60 -0
- package/resources/packages/packages.js.map +1 -0
- package/resources/packages/packages.mjs +55 -0
- package/resources/packages/packages.mjs.map +1 -0
- package/resources/packages/versions.d.mts +72 -0
- package/resources/packages/versions.d.mts.map +1 -0
- package/resources/packages/versions.d.ts +72 -0
- package/resources/packages/versions.d.ts.map +1 -0
- package/resources/packages/versions.js +19 -0
- package/resources/packages/versions.js.map +1 -0
- package/resources/packages/versions.mjs +15 -0
- package/resources/packages/versions.mjs.map +1 -0
- package/resources/packages.d.mts +2 -0
- package/resources/packages.d.mts.map +1 -0
- package/resources/packages.d.ts +2 -0
- package/resources/packages.d.ts.map +1 -0
- package/resources/packages.js +6 -0
- package/resources/packages.js.map +1 -0
- package/resources/packages.mjs +3 -0
- package/resources/packages.mjs.map +1 -0
- package/resources/scheduled-job-assignments.d.mts +1 -1
- package/resources/scheduled-job-assignments.d.ts +1 -1
- package/resources/scheduled-job-assignments.js +1 -1
- package/resources/scheduled-job-assignments.mjs +1 -1
- package/resources/schedules.d.mts +1 -1
- package/resources/schedules.d.ts +1 -1
- package/resources/schedules.js +1 -1
- package/resources/schedules.mjs +1 -1
- package/resources/shift-assignments.d.mts +1 -1
- package/resources/shift-assignments.d.ts +1 -1
- package/resources/shift-assignments.js +1 -1
- package/resources/shift-assignments.mjs +1 -1
- package/resources/shift-inputs.d.mts +1 -1
- package/resources/shift-inputs.d.ts +1 -1
- package/resources/shift-inputs.js +1 -1
- package/resources/shift-inputs.mjs +1 -1
- package/resources/shiftassignments.d.mts +1 -1
- package/resources/shiftassignments.d.ts +1 -1
- package/resources/shiftassignments.js +1 -1
- package/resources/shiftassignments.mjs +1 -1
- package/resources/sites.d.mts +572 -0
- package/resources/sites.d.mts.map +1 -0
- package/resources/sites.d.ts +572 -0
- package/resources/sites.d.ts.map +1 -0
- package/resources/sites.js +154 -0
- package/resources/sites.js.map +1 -0
- package/resources/sites.mjs +150 -0
- package/resources/sites.mjs.map +1 -0
- package/resources/software-deployments.d.mts +1 -1
- package/resources/software-deployments.d.ts +1 -1
- package/resources/software-deployments.js +1 -1
- package/resources/software-deployments.mjs +1 -1
- package/resources/time-cards.d.mts +1 -1
- package/resources/time-cards.d.ts +1 -1
- package/resources/time-cards.js +1 -1
- package/resources/time-cards.mjs +1 -1
- package/resources/time-entries.d.mts +1 -1
- package/resources/time-entries.d.ts +1 -1
- package/resources/time-entries.js +1 -1
- package/resources/time-entries.mjs +1 -1
- package/resources/tracks.d.mts +1 -1
- package/resources/tracks.d.ts +1 -1
- package/resources/tracks.js +1 -1
- package/resources/tracks.mjs +1 -1
- package/resources/unassigned-shifts.d.mts +2 -2
- package/resources/unassigned-shifts.d.ts +2 -2
- package/resources/unassigned-shifts.js +2 -2
- package/resources/unassigned-shifts.mjs +2 -2
- package/resources/unassignedshifts.d.mts +1 -1
- package/resources/unassignedshifts.d.ts +1 -1
- package/resources/unassignedshifts.js +1 -1
- package/resources/unassignedshifts.mjs +1 -1
- package/resources/worker-time-splits.d.mts +1 -1
- package/resources/worker-time-splits.d.ts +1 -1
- package/resources/worker-time-splits.js +1 -1
- package/resources/worker-time-splits.mjs +1 -1
- package/src/client.ts +91 -0
- package/src/core/platform/custom-objects/category.ts +294 -0
- package/src/core/platform/custom-objects/definition.ts +373 -0
- package/src/core/platform/custom-objects/fields.ts +653 -0
- package/src/core/platform/custom-objects/function-runtime.ts +76 -0
- package/src/core/platform/custom-objects/lifecycle.ts +557 -0
- package/src/core/platform/custom-objects/manager.ts +959 -0
- package/src/core/platform/custom-objects/provisioning.ts +672 -0
- package/src/core/platform/custom-objects/rql.ts +375 -0
- package/src/core/platform/custom-objects/schema-manager.ts +351 -0
- package/src/core/platform/custom-objects/typed-rql.ts +1273 -0
- package/src/core/platform/custom-objects/types.ts +753 -0
- package/src/core/platform/custom-objects/validation.ts +573 -0
- package/src/core/platform/custom-objects.ts +269 -0
- package/src/lib/leave-programs/README.md +160 -0
- package/src/lib/leave-programs/advanced.ts +11 -0
- package/src/lib/leave-programs/context.ts +101 -0
- package/src/lib/leave-programs/define-company-leave-program.ts +58 -0
- package/src/lib/leave-programs/duration.ts +20 -0
- package/src/lib/leave-programs/pay.ts +18 -0
- package/src/lib/leave-programs/policy-builder.ts +113 -0
- package/src/lib/leave-programs/recipes/parental-top-up-policy.ts +85 -0
- package/src/lib/leave-programs/testing.ts +16 -0
- package/src/lib/leave-programs/types.ts +274 -0
- package/src/lib/leave-programs.ts +35 -0
- package/src/resources/agents/agents.ts +340 -0
- package/src/resources/agents/deployments.ts +249 -0
- package/src/resources/agents/index.ts +40 -0
- package/src/resources/agents/sessions/events.ts +107 -0
- package/src/resources/agents/sessions/index.ts +12 -0
- package/src/resources/agents/sessions/sessions.ts +216 -0
- package/src/resources/agents/sessions.ts +3 -0
- package/src/resources/agents/source-revisions.ts +267 -0
- package/src/resources/agents.ts +3 -0
- package/src/resources/break-policies.ts +1 -1
- package/src/resources/break-types.ts +1 -1
- package/src/resources/business-structure-paths.ts +1 -1
- package/src/resources/candidate-applications.ts +1 -1
- package/src/resources/candidates.ts +1 -1
- package/src/resources/company-legal-entities.ts +1 -1
- package/src/resources/company-legal-entity-workers.ts +1 -1
- package/src/resources/compensation-bands-details.ts +1 -1
- package/src/resources/compensations.ts +1 -1
- package/src/resources/custom-objects/custom-objects.ts +8 -0
- package/src/resources/custom-objects/fields.ts +192 -59
- package/src/resources/device-orders.ts +1 -1
- package/src/resources/devices.ts +1 -1
- package/src/resources/functions/deployments.ts +2 -2
- package/src/resources/functions/executions.ts +2 -2
- package/src/resources/functions/functions.ts +1 -1
- package/src/resources/headcount-positions.ts +1 -1
- package/src/resources/headcount-priorities.ts +1 -1
- package/src/resources/index.ts +38 -0
- package/src/resources/job-assignments.ts +2 -2
- package/src/resources/job-codes.ts +2 -2
- package/src/resources/job-dimensions.ts +1 -1
- package/src/resources/job-pay-rate-exceptions.ts +2 -2
- package/src/resources/job-requisitions.ts +1 -1
- package/src/resources/kiosk-badges.ts +1 -1
- package/src/resources/leave-accruals.ts +1 -1
- package/src/resources/leave-balances.ts +1 -1
- package/src/resources/leave-requests.ts +1 -1
- package/src/resources/leave-types.ts +1 -1
- package/src/resources/legal-entities.ts +1 -1
- package/src/resources/levels.ts +29 -5
- package/src/resources/location-factors.ts +1 -1
- package/src/resources/packages/index.ts +14 -0
- package/src/resources/packages/packages.ts +329 -0
- package/src/resources/packages/versions.ts +98 -0
- package/src/resources/packages.ts +3 -0
- package/src/resources/scheduled-job-assignments.ts +1 -1
- package/src/resources/schedules.ts +1 -1
- package/src/resources/shift-assignments.ts +1 -1
- package/src/resources/shift-inputs.ts +1 -1
- package/src/resources/shiftassignments.ts +1 -1
- package/src/resources/sites.ts +736 -0
- package/src/resources/software-deployments.ts +1 -1
- package/src/resources/time-cards.ts +1 -1
- package/src/resources/time-entries.ts +1 -1
- package/src/resources/tracks.ts +1 -1
- package/src/resources/unassigned-shifts.ts +2 -2
- package/src/resources/unassignedshifts.ts +1 -1
- package/src/resources/worker-time-splits.ts +1 -1
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -0,0 +1,1273 @@
|
|
|
1
|
+
import type { AnyCustomObjectDefinition, FieldNames } from './types';
|
|
2
|
+
|
|
3
|
+
const STANDARD_TYPED_RQL_FIELDS = [
|
|
4
|
+
'id',
|
|
5
|
+
'name',
|
|
6
|
+
'created_at',
|
|
7
|
+
'updated_at',
|
|
8
|
+
'system_updated_at',
|
|
9
|
+
'external_id',
|
|
10
|
+
'owner_role',
|
|
11
|
+
'created_by',
|
|
12
|
+
'last_modified_by',
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
const STANDARD_LOOKUP_FIELDS = new Set(['owner_role', 'created_by', 'last_modified_by']);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Standard field-name strings accepted by the parsed RQL helper.
|
|
19
|
+
*
|
|
20
|
+
* @typeParam TDefinition - Object definition whose standard record fields should be exposed.
|
|
21
|
+
*/
|
|
22
|
+
export type ParsedRqlStandardFieldName<TDefinition extends AnyCustomObjectDefinition> =
|
|
23
|
+
(typeof STANDARD_TYPED_RQL_FIELDS)[number];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Field-name strings accepted by the parsed RQL helper.
|
|
27
|
+
*
|
|
28
|
+
* @typeParam TDefinition - Object definition whose field-name union should be exposed.
|
|
29
|
+
*/
|
|
30
|
+
export type ParsedRqlFieldName<TDefinition extends AnyCustomObjectDefinition> =
|
|
31
|
+
| ParsedRqlStandardFieldName<TDefinition>
|
|
32
|
+
| FieldNames<TDefinition>;
|
|
33
|
+
|
|
34
|
+
/** Whitespace characters trimmed by the type-level parsed RQL validator. */
|
|
35
|
+
type RqlWhitespace = ' ' | '\n' | '\t' | '\r';
|
|
36
|
+
|
|
37
|
+
/** Removes leading and trailing whitespace from a string literal. */
|
|
38
|
+
type TrimRql<T extends string> =
|
|
39
|
+
T extends `${RqlWhitespace}${infer Rest}` ? TrimRql<Rest>
|
|
40
|
+
: T extends `${infer Rest}${RqlWhitespace}` ? TrimRql<Rest>
|
|
41
|
+
: T;
|
|
42
|
+
|
|
43
|
+
/** Appends one value to a tuple used as a depth counter. */
|
|
44
|
+
type PushDepth<TDepth extends readonly unknown[]> = [...TDepth, 1];
|
|
45
|
+
|
|
46
|
+
/** Removes one value from a tuple used as a depth counter. */
|
|
47
|
+
type PopDepth<TDepth extends readonly unknown[]> = TDepth extends [...infer Rest, unknown] ? Rest : [];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when the outermost `(` and `)` pair actually wraps the full expression.
|
|
51
|
+
*
|
|
52
|
+
* This is stricter than a raw open/close count. For example, `(a) AND (b)` has
|
|
53
|
+
* balanced parentheses but is not globally wrapped by its first `(` and last `)`.
|
|
54
|
+
*/
|
|
55
|
+
type OuterParensWrapExpression<
|
|
56
|
+
TSource extends string,
|
|
57
|
+
TParenDepth extends readonly unknown[] = [1],
|
|
58
|
+
TBracketDepth extends readonly unknown[] = [],
|
|
59
|
+
TInString extends boolean = false,
|
|
60
|
+
> = TSource extends '' ?
|
|
61
|
+
TParenDepth['length'] extends 1 ?
|
|
62
|
+
true
|
|
63
|
+
: false
|
|
64
|
+
: TInString extends true ?
|
|
65
|
+
TSource extends `\\${infer _Escaped}${infer Rest}` ?
|
|
66
|
+
OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, true>
|
|
67
|
+
: TSource extends `'${infer Rest}` ? OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, false>
|
|
68
|
+
: TSource extends `${infer _Char}${infer Rest}` ?
|
|
69
|
+
OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, true>
|
|
70
|
+
: false
|
|
71
|
+
: TSource extends `'${infer Rest}` ? OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, true>
|
|
72
|
+
: TSource extends `[${infer Rest}` ?
|
|
73
|
+
OuterParensWrapExpression<Rest, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
74
|
+
: TSource extends `]${infer Rest}` ?
|
|
75
|
+
OuterParensWrapExpression<Rest, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
76
|
+
: TBracketDepth['length'] extends 0 ?
|
|
77
|
+
TSource extends `(${infer Rest}` ?
|
|
78
|
+
OuterParensWrapExpression<Rest, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
79
|
+
: TSource extends `)${infer Rest}` ?
|
|
80
|
+
TParenDepth['length'] extends 1 ?
|
|
81
|
+
false
|
|
82
|
+
: OuterParensWrapExpression<Rest, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
83
|
+
: TSource extends `${infer _Char}${infer Rest}` ?
|
|
84
|
+
OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, false>
|
|
85
|
+
: false
|
|
86
|
+
: TSource extends `(${infer Rest}` ? OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, false>
|
|
87
|
+
: TSource extends `)${infer Rest}` ? OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, false>
|
|
88
|
+
: TSource extends `${infer _Char}${infer Rest}` ?
|
|
89
|
+
OuterParensWrapExpression<Rest, TParenDepth, TBracketDepth, false>
|
|
90
|
+
: false;
|
|
91
|
+
|
|
92
|
+
/** Removes one pair of outer parentheses when they wrap the full expression. */
|
|
93
|
+
type StripOuterParens<T extends string> =
|
|
94
|
+
T extends `(${infer Inner})` ?
|
|
95
|
+
OuterParensWrapExpression<Inner> extends true ?
|
|
96
|
+
StripOuterParens<TrimRql<Inner>>
|
|
97
|
+
: T
|
|
98
|
+
: T;
|
|
99
|
+
|
|
100
|
+
/** Utility for splitting an expression by a top-level delimiter while respecting strings, brackets, and parentheses. */
|
|
101
|
+
type SplitTopLevel<
|
|
102
|
+
TSource extends string,
|
|
103
|
+
TDelimiter extends string,
|
|
104
|
+
TCurrent extends string = '',
|
|
105
|
+
TParts extends readonly string[] = [],
|
|
106
|
+
TParenDepth extends readonly unknown[] = [],
|
|
107
|
+
TBracketDepth extends readonly unknown[] = [],
|
|
108
|
+
TInString extends boolean = false,
|
|
109
|
+
> = TSource extends '' ? [...TParts, TrimRql<TCurrent>]
|
|
110
|
+
: TInString extends true ?
|
|
111
|
+
TSource extends `\\${infer Escaped}${infer Rest}` ?
|
|
112
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}\\${Escaped}`, TParts, TParenDepth, TBracketDepth, true>
|
|
113
|
+
: TSource extends `'${infer Rest}` ?
|
|
114
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, false>
|
|
115
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
116
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, true>
|
|
117
|
+
: [...TParts, TrimRql<TCurrent>]
|
|
118
|
+
: TParenDepth['length'] extends 0 ?
|
|
119
|
+
TBracketDepth['length'] extends 0 ?
|
|
120
|
+
TSource extends `${TDelimiter}${infer Rest}` ?
|
|
121
|
+
SplitTopLevel<Rest, TDelimiter, '', [...TParts, TrimRql<TCurrent>], TParenDepth, TBracketDepth, false>
|
|
122
|
+
: TSource extends `'${infer Rest}` ?
|
|
123
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
124
|
+
: TSource extends `(${infer Rest}` ?
|
|
125
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
126
|
+
: TSource extends `)${infer Rest}` ?
|
|
127
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
128
|
+
: TSource extends `[${infer Rest}` ?
|
|
129
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
130
|
+
: TSource extends `]${infer Rest}` ?
|
|
131
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
132
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
133
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
134
|
+
: [...TParts, TrimRql<TCurrent>]
|
|
135
|
+
: TSource extends `'${infer Rest}` ?
|
|
136
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
137
|
+
: TSource extends `(${infer Rest}` ?
|
|
138
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
139
|
+
: TSource extends `)${infer Rest}` ?
|
|
140
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
141
|
+
: TSource extends `[${infer Rest}` ?
|
|
142
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
143
|
+
: TSource extends `]${infer Rest}` ?
|
|
144
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
145
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
146
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
147
|
+
: [...TParts, TrimRql<TCurrent>]
|
|
148
|
+
: TSource extends `'${infer Rest}` ?
|
|
149
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
150
|
+
: TSource extends `(${infer Rest}` ?
|
|
151
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
152
|
+
: TSource extends `)${infer Rest}` ?
|
|
153
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
154
|
+
: TSource extends `[${infer Rest}` ?
|
|
155
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
156
|
+
: TSource extends `]${infer Rest}` ?
|
|
157
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
158
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
159
|
+
SplitTopLevel<Rest, TDelimiter, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
160
|
+
: [...TParts, TrimRql<TCurrent>];
|
|
161
|
+
|
|
162
|
+
/** Joins string parts using one delimiter. */
|
|
163
|
+
type JoinWithDelimiter<TParts extends readonly string[], TDelimiter extends string> = TParts extends [] ? ''
|
|
164
|
+
: TParts extends [infer TOnly extends string] ? TOnly
|
|
165
|
+
: TParts extends [infer THead extends string, ...infer TRest extends string[]] ?
|
|
166
|
+
`${THead}${TDelimiter}${JoinWithDelimiter<TRest, TDelimiter>}`
|
|
167
|
+
: string;
|
|
168
|
+
|
|
169
|
+
/** Parsed logical operator tokens recognized by the type-level validator. */
|
|
170
|
+
type ParsedRqlLogicalOperator = 'AND' | 'OR';
|
|
171
|
+
|
|
172
|
+
/** Parsed logical-expression pieces after one top-level scan. */
|
|
173
|
+
type ParsedLogicalMatch<
|
|
174
|
+
TOperator extends ParsedRqlLogicalOperator = ParsedRqlLogicalOperator,
|
|
175
|
+
TParts extends readonly string[] = readonly string[],
|
|
176
|
+
> = readonly [operator: TOperator, parts: TParts];
|
|
177
|
+
|
|
178
|
+
/** Attempts to parse one logical expression in a single top-level scan while preserving OR-before-AND splitting semantics. */
|
|
179
|
+
type ParseLogicalMatch<
|
|
180
|
+
TSource extends string,
|
|
181
|
+
TMode extends ParsedRqlLogicalOperator | 'none' = 'none',
|
|
182
|
+
TCurrent extends string = '',
|
|
183
|
+
TParts extends readonly string[] = [],
|
|
184
|
+
TParenDepth extends readonly unknown[] = [],
|
|
185
|
+
TBracketDepth extends readonly unknown[] = [],
|
|
186
|
+
TInString extends boolean = false,
|
|
187
|
+
> = TSource extends '' ?
|
|
188
|
+
TMode extends ParsedRqlLogicalOperator ?
|
|
189
|
+
ParsedLogicalMatch<TMode, [...TParts, TrimRql<TCurrent>]>
|
|
190
|
+
: never
|
|
191
|
+
: TInString extends true ?
|
|
192
|
+
TSource extends `\\${infer Escaped}${infer Rest}` ?
|
|
193
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}\\${Escaped}`, TParts, TParenDepth, TBracketDepth, true>
|
|
194
|
+
: TSource extends `'${infer Rest}` ?
|
|
195
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, false>
|
|
196
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
197
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, true>
|
|
198
|
+
: never
|
|
199
|
+
: TParenDepth['length'] extends 0 ?
|
|
200
|
+
TBracketDepth['length'] extends 0 ?
|
|
201
|
+
TSource extends ` OR ${infer Rest}` ?
|
|
202
|
+
TMode extends 'OR' ?
|
|
203
|
+
ParseLogicalMatch<Rest, 'OR', '', [...TParts, TrimRql<TCurrent>], TParenDepth, TBracketDepth, false>
|
|
204
|
+
: TMode extends 'AND' ?
|
|
205
|
+
ParseLogicalMatch<
|
|
206
|
+
Rest,
|
|
207
|
+
'OR',
|
|
208
|
+
'',
|
|
209
|
+
[JoinWithDelimiter<[...TParts, TrimRql<TCurrent>], ' AND '>],
|
|
210
|
+
TParenDepth,
|
|
211
|
+
TBracketDepth,
|
|
212
|
+
false
|
|
213
|
+
>
|
|
214
|
+
: ParseLogicalMatch<Rest, 'OR', '', [TrimRql<TCurrent>], TParenDepth, TBracketDepth, false>
|
|
215
|
+
: TSource extends ` AND ${infer Rest}` ?
|
|
216
|
+
TMode extends 'OR' ?
|
|
217
|
+
ParseLogicalMatch<Rest, 'OR', `${TCurrent} AND `, TParts, TParenDepth, TBracketDepth, false>
|
|
218
|
+
: TMode extends 'AND' ?
|
|
219
|
+
ParseLogicalMatch<Rest, 'AND', '', [...TParts, TrimRql<TCurrent>], TParenDepth, TBracketDepth, false>
|
|
220
|
+
: ParseLogicalMatch<Rest, 'AND', '', [TrimRql<TCurrent>], TParenDepth, TBracketDepth, false>
|
|
221
|
+
: TSource extends `'${infer Rest}` ?
|
|
222
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
223
|
+
: TSource extends `(${infer Rest}` ?
|
|
224
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
225
|
+
: TSource extends `)${infer Rest}` ?
|
|
226
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
227
|
+
: TSource extends `[${infer Rest}` ?
|
|
228
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
229
|
+
: TSource extends `]${infer Rest}` ?
|
|
230
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
231
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
232
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
233
|
+
: never
|
|
234
|
+
: TSource extends `'${infer Rest}` ?
|
|
235
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
236
|
+
: TSource extends `(${infer Rest}` ?
|
|
237
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
238
|
+
: TSource extends `)${infer Rest}` ?
|
|
239
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
240
|
+
: TSource extends `[${infer Rest}` ?
|
|
241
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
242
|
+
: TSource extends `]${infer Rest}` ?
|
|
243
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
244
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
245
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
246
|
+
: never
|
|
247
|
+
: TSource extends `'${infer Rest}` ?
|
|
248
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}'`, TParts, TParenDepth, TBracketDepth, true>
|
|
249
|
+
: TSource extends `(${infer Rest}` ?
|
|
250
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}(`, TParts, PushDepth<TParenDepth>, TBracketDepth, false>
|
|
251
|
+
: TSource extends `)${infer Rest}` ?
|
|
252
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent})`, TParts, PopDepth<TParenDepth>, TBracketDepth, false>
|
|
253
|
+
: TSource extends `[${infer Rest}` ?
|
|
254
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}[`, TParts, TParenDepth, PushDepth<TBracketDepth>, false>
|
|
255
|
+
: TSource extends `]${infer Rest}` ?
|
|
256
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}]`, TParts, TParenDepth, PopDepth<TBracketDepth>, false>
|
|
257
|
+
: TSource extends `${infer Char}${infer Rest}` ?
|
|
258
|
+
ParseLogicalMatch<Rest, TMode, `${TCurrent}${Char}`, TParts, TParenDepth, TBracketDepth, false>
|
|
259
|
+
: never;
|
|
260
|
+
|
|
261
|
+
/** Normalizes one candidate parsed-RQL expression before boolean/comparison validation. */
|
|
262
|
+
type NormalizeParsedRqlExpression<TExpression extends string> = StripOuterParens<TrimRql<TExpression>>;
|
|
263
|
+
|
|
264
|
+
/** Returns the first validation error from the provided expression parts. */
|
|
265
|
+
type ValidateEveryExpression<
|
|
266
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
267
|
+
TParts extends readonly string[],
|
|
268
|
+
> = TParts extends [infer Next extends string, ...infer Rest extends string[]] ?
|
|
269
|
+
ValidateParsedRqlExpression<TDefinition, Next> extends infer TResult ?
|
|
270
|
+
TResult extends true ?
|
|
271
|
+
ValidateEveryExpression<TDefinition, Rest>
|
|
272
|
+
: TResult
|
|
273
|
+
: never
|
|
274
|
+
: true;
|
|
275
|
+
|
|
276
|
+
/** Standard parsed-RQL field category. */
|
|
277
|
+
type StandardFieldCategory<TFieldName extends string> =
|
|
278
|
+
TFieldName extends 'owner_role' | 'created_by' | 'last_modified_by' ? 'lookup' : 'string';
|
|
279
|
+
|
|
280
|
+
/** Category lookup for one custom-field kind. */
|
|
281
|
+
type ParsedRqlCategoryByKind<TKind extends string> =
|
|
282
|
+
TKind extends (
|
|
283
|
+
| 'text'
|
|
284
|
+
| 'long-text'
|
|
285
|
+
| 'email'
|
|
286
|
+
| 'url'
|
|
287
|
+
| 'phone'
|
|
288
|
+
| 'date'
|
|
289
|
+
| 'datetime'
|
|
290
|
+
| 'time'
|
|
291
|
+
| 'radio'
|
|
292
|
+
| 'formula-text'
|
|
293
|
+
| 'formula-date'
|
|
294
|
+
| 'formula-url'
|
|
295
|
+
) ?
|
|
296
|
+
'string'
|
|
297
|
+
: TKind extends (
|
|
298
|
+
'number' | 'currency' | 'percentage' | 'formula-number' | 'formula-currency' | 'formula-percentage'
|
|
299
|
+
) ?
|
|
300
|
+
'number'
|
|
301
|
+
: TKind extends 'boolean' | 'formula-boolean' ? 'boolean'
|
|
302
|
+
: TKind extends 'lookup' | 'parent-child' ? 'lookup'
|
|
303
|
+
: 'unsupported';
|
|
304
|
+
|
|
305
|
+
/** Cached custom-field category map for one object definition. */
|
|
306
|
+
type ParsedRqlCustomFieldCategoryMap<TDefinition extends AnyCustomObjectDefinition> = {
|
|
307
|
+
readonly [K in FieldNames<TDefinition>]: TDefinition['fields'][K] extends (
|
|
308
|
+
{ kind: infer TKind extends string }
|
|
309
|
+
) ?
|
|
310
|
+
ParsedRqlCategoryByKind<TKind>
|
|
311
|
+
: 'unsupported';
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/** Cached full field-category map for one object definition. */
|
|
315
|
+
type ParsedRqlFieldCategoryMap<TDefinition extends AnyCustomObjectDefinition> = {
|
|
316
|
+
readonly [K in ParsedRqlStandardFieldName<TDefinition>]: StandardFieldCategory<K>;
|
|
317
|
+
} & ParsedRqlCustomFieldCategoryMap<TDefinition>;
|
|
318
|
+
|
|
319
|
+
/** Field category used for operator and literal validation. */
|
|
320
|
+
type ParsedRqlFieldCategory<
|
|
321
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
322
|
+
TFieldName extends string,
|
|
323
|
+
> = TFieldName extends keyof ParsedRqlFieldCategoryMap<TDefinition> ?
|
|
324
|
+
ParsedRqlFieldCategoryMap<TDefinition>[TFieldName]
|
|
325
|
+
: 'missing';
|
|
326
|
+
|
|
327
|
+
/** Human-readable field-category names used in compile-time diagnostics. */
|
|
328
|
+
type ParsedRqlFieldCategoryLabel<TCategory extends string> =
|
|
329
|
+
TCategory extends 'string' ? "a quoted string literal such as 'Ada'"
|
|
330
|
+
: TCategory extends 'number' ? 'a numeric literal such as 14'
|
|
331
|
+
: TCategory extends 'boolean' ? 'a boolean literal: True or False'
|
|
332
|
+
: TCategory extends 'lookup' ? "a quoted record-id string such as 'rec_123'"
|
|
333
|
+
: 'a supported literal value';
|
|
334
|
+
|
|
335
|
+
/** Formats a consistent compile-time error for one field/operator/literal mismatch. */
|
|
336
|
+
type ParsedRqlLiteralError<
|
|
337
|
+
TFieldName extends string,
|
|
338
|
+
TOperator extends string,
|
|
339
|
+
TCategory extends string,
|
|
340
|
+
TLiteral extends string,
|
|
341
|
+
> = `RQL field "${TFieldName}" with operator "${TOperator}" expects ${ParsedRqlFieldCategoryLabel<TCategory>}; received ${TLiteral}.`;
|
|
342
|
+
|
|
343
|
+
/** Formats a compile-time error for unsupported field categories. */
|
|
344
|
+
type ParsedRqlUnsupportedFieldError<
|
|
345
|
+
TFieldName extends string,
|
|
346
|
+
TCategory extends string,
|
|
347
|
+
> = `RQL field "${TFieldName}" uses an unsupported field category (${TCategory}) in typedRql(...).`;
|
|
348
|
+
|
|
349
|
+
/** Validates a quoted string literal. */
|
|
350
|
+
type ValidateStringLiteral<
|
|
351
|
+
TFieldName extends string,
|
|
352
|
+
TOperator extends string,
|
|
353
|
+
TCategory extends string,
|
|
354
|
+
TLiteral extends string,
|
|
355
|
+
> = TLiteral extends `'${string}'` ? true : ParsedRqlLiteralError<TFieldName, TOperator, TCategory, TLiteral>;
|
|
356
|
+
|
|
357
|
+
/** Validates a numeric literal. */
|
|
358
|
+
type ValidateNumberLiteral<
|
|
359
|
+
TFieldName extends string,
|
|
360
|
+
TOperator extends string,
|
|
361
|
+
TCategory extends string,
|
|
362
|
+
TLiteral extends string,
|
|
363
|
+
> = TLiteral extends `${number}` ? true : ParsedRqlLiteralError<TFieldName, TOperator, TCategory, TLiteral>;
|
|
364
|
+
|
|
365
|
+
/** Validates a boolean literal. */
|
|
366
|
+
type ValidateBooleanLiteral<
|
|
367
|
+
TFieldName extends string,
|
|
368
|
+
TOperator extends string,
|
|
369
|
+
TCategory extends string,
|
|
370
|
+
TLiteral extends string,
|
|
371
|
+
> = Lowercase<TLiteral> extends 'true' | 'false' ? true
|
|
372
|
+
: ParsedRqlLiteralError<TFieldName, TOperator, TCategory, TLiteral>;
|
|
373
|
+
|
|
374
|
+
/** Validates a null literal. */
|
|
375
|
+
type ValidateNullLiteral<TLiteral extends string> = Lowercase<TLiteral> extends 'null' ? true : false;
|
|
376
|
+
|
|
377
|
+
/** Validates one scalar literal against the target field category. */
|
|
378
|
+
type ValidateScalarLiteral<
|
|
379
|
+
TFieldName extends string,
|
|
380
|
+
TOperator extends string,
|
|
381
|
+
TCategory extends string,
|
|
382
|
+
TLiteral extends string,
|
|
383
|
+
TAllowNull extends boolean = true,
|
|
384
|
+
> = TAllowNull extends true ?
|
|
385
|
+
ValidateNullLiteral<TLiteral> extends true ?
|
|
386
|
+
true
|
|
387
|
+
: ValidateScalarLiteral<TFieldName, TOperator, TCategory, TLiteral, false>
|
|
388
|
+
: TCategory extends 'string' ? ValidateStringLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
389
|
+
: TCategory extends 'number' ? ValidateNumberLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
390
|
+
: TCategory extends 'boolean' ? ValidateBooleanLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
391
|
+
: TCategory extends 'lookup' ? ValidateStringLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
392
|
+
: ParsedRqlUnsupportedFieldError<TFieldName, TCategory>;
|
|
393
|
+
|
|
394
|
+
/** Validates one array literal against the target field category. */
|
|
395
|
+
type ValidateArrayLiteral<
|
|
396
|
+
TFieldName extends string,
|
|
397
|
+
TOperator extends string,
|
|
398
|
+
TCategory extends string,
|
|
399
|
+
TLiteral extends string,
|
|
400
|
+
> = TLiteral extends `[${infer Inner}]` ?
|
|
401
|
+
SplitTopLevel<TrimRql<Inner>, ', '> extends infer TParts extends string[] ?
|
|
402
|
+
TParts['length'] extends 0 ?
|
|
403
|
+
`RQL field "${TFieldName}" with operator "${TOperator}" requires a non-empty array literal such as ['value'].`
|
|
404
|
+
: ValidateEveryArrayElement<TFieldName, TOperator, TCategory, TParts>
|
|
405
|
+
: `RQL field "${TFieldName}" with operator "${TOperator}" has an array literal that could not be parsed.`
|
|
406
|
+
: `RQL field "${TFieldName}" with operator "${TOperator}" requires an array literal such as ['value']; received ${TLiteral}.`;
|
|
407
|
+
|
|
408
|
+
/** Returns the first invalid array element, if any. */
|
|
409
|
+
type ValidateEveryArrayElement<
|
|
410
|
+
TFieldName extends string,
|
|
411
|
+
TOperator extends string,
|
|
412
|
+
TCategory extends string,
|
|
413
|
+
TParts extends readonly string[],
|
|
414
|
+
> = TParts extends [infer Next extends string, ...infer Rest extends string[]] ?
|
|
415
|
+
ValidateScalarLiteral<TFieldName, TOperator, TCategory, Next, false> extends infer TResult ?
|
|
416
|
+
TResult extends true ?
|
|
417
|
+
ValidateEveryArrayElement<TFieldName, TOperator, TCategory, Rest>
|
|
418
|
+
: TResult
|
|
419
|
+
: never
|
|
420
|
+
: true;
|
|
421
|
+
|
|
422
|
+
/** Validates the operator/literal pairing for one field category. */
|
|
423
|
+
type ValidateComparisonLiteral<
|
|
424
|
+
TFieldName extends string,
|
|
425
|
+
TCategory extends string,
|
|
426
|
+
TOperator extends string,
|
|
427
|
+
TLiteral extends string,
|
|
428
|
+
> = TCategory extends 'unsupported' ? ParsedRqlUnsupportedFieldError<TFieldName, TCategory>
|
|
429
|
+
: TOperator extends '==' | '!=' ? ValidateScalarLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
430
|
+
: TOperator extends '<' | '<=' | '>' | '>=' ?
|
|
431
|
+
TCategory extends 'string' | 'number' ?
|
|
432
|
+
ValidateScalarLiteral<TFieldName, TOperator, TCategory, TLiteral, false>
|
|
433
|
+
: `RQL field "${TFieldName}" uses operator "${TOperator}", which is only valid for string or number fields; this field expects ${ParsedRqlFieldCategoryLabel<TCategory>}.`
|
|
434
|
+
: TOperator extends 'IN' | 'NOT_IN' ? ValidateArrayLiteral<TFieldName, TOperator, TCategory, TLiteral>
|
|
435
|
+
: `RQL field "${TFieldName}" uses unsupported operator "${TOperator}".`;
|
|
436
|
+
|
|
437
|
+
/** Validates one comparison clause once the field and operator have been identified. */
|
|
438
|
+
type ValidateParsedComparison<
|
|
439
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
440
|
+
TFieldName extends string,
|
|
441
|
+
TOperator extends string,
|
|
442
|
+
TLiteral extends string,
|
|
443
|
+
> = ParsedRqlFieldCategory<TDefinition, TFieldName> extends infer TCategory extends string ?
|
|
444
|
+
TCategory extends 'missing' ?
|
|
445
|
+
`Unknown RQL field "${TFieldName}". Use a logical field name from the object definition.`
|
|
446
|
+
: ValidateComparisonLiteral<TFieldName, TCategory, TOperator, TrimRql<TLiteral>>
|
|
447
|
+
: never;
|
|
448
|
+
|
|
449
|
+
/** Parsed comparison operator tokens recognized by the type-level validator. */
|
|
450
|
+
type ParsedRqlComparisonOperator = 'NOT_IN' | 'IN' | '==' | '!=' | '<=' | '>=' | '<' | '>';
|
|
451
|
+
|
|
452
|
+
/** Parsed comparison pieces once one operator match has been identified. */
|
|
453
|
+
type ParsedComparisonMatch<
|
|
454
|
+
TLeft extends string = string,
|
|
455
|
+
TOperator extends ParsedRqlComparisonOperator = ParsedRqlComparisonOperator,
|
|
456
|
+
TRight extends string = string,
|
|
457
|
+
> = readonly [left: TLeft, operator: TOperator, right: TRight];
|
|
458
|
+
|
|
459
|
+
/** Space-tokenized comparison tuple for one expression, respecting nested strings/brackets/parens. */
|
|
460
|
+
type ParsedComparisonTokens<TExpression extends string> = SplitTopLevel<TExpression, ' '>;
|
|
461
|
+
|
|
462
|
+
/** Attempts to parse one comparison expression from a token tuple. */
|
|
463
|
+
type ParseComparisonMatch<TExpression extends string> =
|
|
464
|
+
ParsedComparisonTokens<TExpression> extends (
|
|
465
|
+
[
|
|
466
|
+
infer TLeft extends string,
|
|
467
|
+
infer TOperator extends ParsedRqlComparisonOperator,
|
|
468
|
+
infer TRight extends string,
|
|
469
|
+
]
|
|
470
|
+
) ?
|
|
471
|
+
ParsedComparisonMatch<TrimRql<TLeft>, TOperator, TRight>
|
|
472
|
+
: never;
|
|
473
|
+
|
|
474
|
+
/** Tries operators in longest-first order so `NOT_IN` wins before `IN`. */
|
|
475
|
+
type ValidateParsedComparisonExpression<
|
|
476
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
477
|
+
TExpression extends string,
|
|
478
|
+
> = [ParseComparisonMatch<TExpression>] extends [never] ?
|
|
479
|
+
`Could not parse RQL comparison "${TExpression}". Use a supported form such as "field == 'value'", "field <= 14", or "field IN ['value']" with spaces around the operator.`
|
|
480
|
+
: ParseComparisonMatch<TExpression> extends (
|
|
481
|
+
ParsedComparisonMatch<
|
|
482
|
+
infer TFieldName extends string,
|
|
483
|
+
infer TOperator extends ParsedRqlComparisonOperator,
|
|
484
|
+
infer TLiteral extends string
|
|
485
|
+
>
|
|
486
|
+
) ?
|
|
487
|
+
ValidateParsedComparison<TDefinition, TFieldName, TOperator, TLiteral>
|
|
488
|
+
: `Could not parse RQL comparison "${TExpression}". Use a supported form such as "field == 'value'", "field <= 14", or "field IN ['value']" with spaces around the operator.`;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Validates one parsed-RQL expression string against the object definition.
|
|
492
|
+
*
|
|
493
|
+
* The supported subset matches the SDK's documented parsed-string custom-object
|
|
494
|
+
* RQL contract:
|
|
495
|
+
* - comparisons over standard fields and local custom-object fields
|
|
496
|
+
* - `==`, `!=`, `<`, `<=`, `>`, `>=`, `IN`, and `NOT_IN`
|
|
497
|
+
* - boolean composition via `AND`, `OR`, and `NOT`
|
|
498
|
+
* - parentheses / grouping
|
|
499
|
+
* - string / number / boolean / null / array literals
|
|
500
|
+
* - lookup equality against quoted ids such as `'role_123'`
|
|
501
|
+
*
|
|
502
|
+
* @typeParam TDefinition - Object definition whose field names and value types should be enforced.
|
|
503
|
+
* @typeParam TExpression - Candidate RQL expression string.
|
|
504
|
+
*/
|
|
505
|
+
type ValidateNormalizedParsedRqlExpression<
|
|
506
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
507
|
+
TNormalizedExpression extends string,
|
|
508
|
+
> = [ParseLogicalMatch<TNormalizedExpression>] extends [never] ?
|
|
509
|
+
TNormalizedExpression extends `NOT ${infer TInner}` ?
|
|
510
|
+
ValidateParsedRqlExpression<TDefinition, TInner>
|
|
511
|
+
: ValidateParsedComparisonExpression<TDefinition, TNormalizedExpression>
|
|
512
|
+
: ParseLogicalMatch<TNormalizedExpression> extends (
|
|
513
|
+
ParsedLogicalMatch<
|
|
514
|
+
infer _TOperator extends ParsedRqlLogicalOperator,
|
|
515
|
+
infer TParts extends readonly string[]
|
|
516
|
+
>
|
|
517
|
+
) ?
|
|
518
|
+
ValidateEveryExpression<TDefinition, TParts>
|
|
519
|
+
: TNormalizedExpression extends `NOT ${infer TInner}` ? ValidateParsedRqlExpression<TDefinition, TInner>
|
|
520
|
+
: ValidateParsedComparisonExpression<TDefinition, TNormalizedExpression>;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Validates one parsed-RQL expression string against the object definition.
|
|
524
|
+
*
|
|
525
|
+
* @typeParam TDefinition - Object definition whose field names and value types should be enforced.
|
|
526
|
+
* @typeParam TExpression - Candidate RQL expression string.
|
|
527
|
+
*/
|
|
528
|
+
export type ValidateParsedRqlExpression<
|
|
529
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
530
|
+
TExpression extends string,
|
|
531
|
+
> = NormalizeParsedRqlExpression<TExpression> extends infer TNormalizedExpression extends string ?
|
|
532
|
+
ValidateNormalizedParsedRqlExpression<TDefinition, TNormalizedExpression>
|
|
533
|
+
: never;
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Type-level gate used by {@link typedRql} to reject invalid parsed-RQL strings.
|
|
537
|
+
*
|
|
538
|
+
* @typeParam TDefinition - Object definition whose field names and value types should be enforced.
|
|
539
|
+
* @typeParam TExpression - Candidate RQL expression string.
|
|
540
|
+
*/
|
|
541
|
+
export type CheckedParsedRql<
|
|
542
|
+
TDefinition extends AnyCustomObjectDefinition,
|
|
543
|
+
TExpression extends string,
|
|
544
|
+
> = ValidateParsedRqlExpression<TDefinition, TExpression> extends true ? TExpression
|
|
545
|
+
: TExpression & {
|
|
546
|
+
readonly __parsedRqlError__: ValidateParsedRqlExpression<TDefinition, TExpression>;
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
/** Parsed scalar literal used by the runtime parser. */
|
|
550
|
+
interface ParsedRqlLiteralString {
|
|
551
|
+
readonly kind: 'string';
|
|
552
|
+
readonly value: string;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Parsed numeric literal used by the runtime parser. */
|
|
556
|
+
interface ParsedRqlLiteralNumber {
|
|
557
|
+
readonly kind: 'number';
|
|
558
|
+
readonly value: number;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** Parsed boolean literal used by the runtime parser. */
|
|
562
|
+
interface ParsedRqlLiteralBoolean {
|
|
563
|
+
readonly kind: 'boolean';
|
|
564
|
+
readonly value: boolean;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** Parsed null literal used by the runtime parser. */
|
|
568
|
+
interface ParsedRqlLiteralNull {
|
|
569
|
+
readonly kind: 'null';
|
|
570
|
+
readonly value: null;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/** Parsed array literal used by the runtime parser. */
|
|
574
|
+
interface ParsedRqlLiteralArray {
|
|
575
|
+
readonly kind: 'array';
|
|
576
|
+
readonly value: readonly ParsedRqlScalarLiteral[];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** Parsed scalar literal used by the runtime parser. */
|
|
580
|
+
type ParsedRqlScalarLiteral =
|
|
581
|
+
| ParsedRqlLiteralString
|
|
582
|
+
| ParsedRqlLiteralNumber
|
|
583
|
+
| ParsedRqlLiteralBoolean
|
|
584
|
+
| ParsedRqlLiteralNull;
|
|
585
|
+
|
|
586
|
+
/** Parsed literal used by the runtime parser. */
|
|
587
|
+
type ParsedRqlLiteral = ParsedRqlScalarLiteral | ParsedRqlLiteralArray;
|
|
588
|
+
|
|
589
|
+
/** Parsed comparison node in the runtime AST. */
|
|
590
|
+
interface ParsedRqlComparisonNode {
|
|
591
|
+
readonly kind: 'comparison';
|
|
592
|
+
readonly field: string;
|
|
593
|
+
readonly operator: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'IN' | 'NOT_IN';
|
|
594
|
+
readonly value: ParsedRqlLiteral;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/** Parsed boolean-composition node in the runtime AST. */
|
|
598
|
+
interface ParsedRqlLogicalNode {
|
|
599
|
+
readonly kind: 'logical';
|
|
600
|
+
readonly operator: 'AND' | 'OR';
|
|
601
|
+
readonly operands: readonly ParsedRqlExpressionNode[];
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/** Parsed negation node in the runtime AST. */
|
|
605
|
+
interface ParsedRqlNotNode {
|
|
606
|
+
readonly kind: 'not';
|
|
607
|
+
readonly operand: ParsedRqlExpressionNode;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/** Runtime AST node used by {@link typedRql}. */
|
|
611
|
+
type ParsedRqlExpressionNode = ParsedRqlComparisonNode | ParsedRqlLogicalNode | ParsedRqlNotNode;
|
|
612
|
+
|
|
613
|
+
/** Runtime field category used by parsed-RQL validation. */
|
|
614
|
+
type RuntimeFieldCategory = 'string' | 'number' | 'boolean' | 'lookup' | 'unsupported';
|
|
615
|
+
|
|
616
|
+
/** Runtime metadata needed to validate and render one parsed RQL field. */
|
|
617
|
+
interface RuntimeFieldMetadata {
|
|
618
|
+
/** Wire-level field API name used in rendered backend RQL. */
|
|
619
|
+
readonly apiName: string;
|
|
620
|
+
|
|
621
|
+
/** Runtime literal category used to validate operator and literal compatibility. */
|
|
622
|
+
readonly category: RuntimeFieldCategory;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/** Mutable parser cursor used by the runtime parsed-RQL scanner. */
|
|
626
|
+
interface RuntimeParsedRqlState {
|
|
627
|
+
/** Full source text being parsed. */
|
|
628
|
+
readonly text: string;
|
|
629
|
+
|
|
630
|
+
/** Zero-based cursor into {@link text}. */
|
|
631
|
+
index: number;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Returns whether one character should be treated as parser whitespace.
|
|
636
|
+
*
|
|
637
|
+
* @param char - Candidate source character.
|
|
638
|
+
* @returns Whether the parser should skip this character outside literals.
|
|
639
|
+
*/
|
|
640
|
+
function isWhitespace(char: string): boolean {
|
|
641
|
+
return char === ' ' || char === '\n' || char === '\t' || char === '\r';
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Advances the parser cursor past any contiguous whitespace.
|
|
646
|
+
*
|
|
647
|
+
* @param state - Mutable parser cursor to advance in place.
|
|
648
|
+
*/
|
|
649
|
+
function skipWhitespace(state: RuntimeParsedRqlState): void {
|
|
650
|
+
while (state.index < state.text.length && isWhitespace(state.text[state.index] as string)) {
|
|
651
|
+
state.index += 1;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Checks whether the parser cursor is currently positioned at one complete RQL keyword token.
|
|
657
|
+
*
|
|
658
|
+
* @param state - Mutable parser cursor whose current position should be checked.
|
|
659
|
+
* @param keyword - Uppercase keyword token to match, such as `AND`, `OR`, or `NULL`.
|
|
660
|
+
* @returns Whether the cursor is positioned at that complete keyword token.
|
|
661
|
+
*/
|
|
662
|
+
function startsWithKeyword(state: RuntimeParsedRqlState, keyword: string): boolean {
|
|
663
|
+
const source = state.text.slice(state.index, state.index + keyword.length);
|
|
664
|
+
if (source.toUpperCase() !== keyword) return false;
|
|
665
|
+
const next = state.text[state.index + keyword.length];
|
|
666
|
+
if (next == null) return true;
|
|
667
|
+
return isWhitespace(next) || next === ')' || next === ']' || next === ',';
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Consumes one keyword token when it is present at the current parser cursor.
|
|
672
|
+
*
|
|
673
|
+
* @param state - Mutable parser cursor to update in place.
|
|
674
|
+
* @param keyword - Uppercase keyword token to consume.
|
|
675
|
+
* @returns Whether the keyword was present and therefore consumed.
|
|
676
|
+
*/
|
|
677
|
+
function consumeKeyword(state: RuntimeParsedRqlState, keyword: string): boolean {
|
|
678
|
+
skipWhitespace(state);
|
|
679
|
+
if (!startsWithKeyword(state, keyword)) return false;
|
|
680
|
+
state.index += keyword.length;
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Consumes one specific punctuation character when it is present at the current parser cursor.
|
|
686
|
+
*
|
|
687
|
+
* @param state - Mutable parser cursor to update in place.
|
|
688
|
+
* @param char - Expected punctuation character, such as `(`, `)`, `[`, `]`, or `,`.
|
|
689
|
+
* @returns Whether the character was present and therefore consumed.
|
|
690
|
+
*/
|
|
691
|
+
function consumeCharacter(state: RuntimeParsedRqlState, char: string): boolean {
|
|
692
|
+
skipWhitespace(state);
|
|
693
|
+
if (state.text[state.index] !== char) return false;
|
|
694
|
+
state.index += 1;
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Requires one specific punctuation character at the current parser cursor.
|
|
700
|
+
*
|
|
701
|
+
* @param state - Mutable parser cursor to validate and update in place.
|
|
702
|
+
* @param char - Required punctuation character.
|
|
703
|
+
* @throws Error when the required character is not present.
|
|
704
|
+
*/
|
|
705
|
+
function expectCharacter(state: RuntimeParsedRqlState, char: string): void {
|
|
706
|
+
if (!consumeCharacter(state, char)) {
|
|
707
|
+
throw new Error(`Expected "${char}" at index ${state.index} while parsing RQL.`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Parses one field identifier token from the current parser cursor.
|
|
713
|
+
*
|
|
714
|
+
* @param state - Mutable parser cursor to read and update in place.
|
|
715
|
+
* @returns The parsed logical field name.
|
|
716
|
+
* @throws Error when no identifier is present at the current cursor.
|
|
717
|
+
*/
|
|
718
|
+
function parseIdentifier(state: RuntimeParsedRqlState): string {
|
|
719
|
+
skipWhitespace(state);
|
|
720
|
+
const start = state.index;
|
|
721
|
+
while (state.index < state.text.length) {
|
|
722
|
+
const char = state.text[state.index] as string;
|
|
723
|
+
if (!/[A-Za-z0-9_]/.test(char)) break;
|
|
724
|
+
state.index += 1;
|
|
725
|
+
}
|
|
726
|
+
if (state.index === start) {
|
|
727
|
+
throw new Error(`Expected a field name at index ${state.index} while parsing RQL.`);
|
|
728
|
+
}
|
|
729
|
+
return state.text.slice(start, state.index);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Parses one quoted string literal, including backslash escapes.
|
|
734
|
+
*
|
|
735
|
+
* @param state - Mutable parser cursor positioned at the opening single quote.
|
|
736
|
+
* @returns Parsed runtime string-literal node.
|
|
737
|
+
* @throws Error when the string literal is unterminated or contains an unterminated escape.
|
|
738
|
+
*/
|
|
739
|
+
function parseStringLiteral(state: RuntimeParsedRqlState): ParsedRqlLiteralString {
|
|
740
|
+
expectCharacter(state, "'");
|
|
741
|
+
let value = '';
|
|
742
|
+
while (state.index < state.text.length) {
|
|
743
|
+
const char = state.text[state.index] as string;
|
|
744
|
+
state.index += 1;
|
|
745
|
+
if (char === '\\') {
|
|
746
|
+
const next = state.text[state.index];
|
|
747
|
+
if (next == null) {
|
|
748
|
+
throw new Error('Unterminated escape sequence in RQL string literal.');
|
|
749
|
+
}
|
|
750
|
+
value += next;
|
|
751
|
+
state.index += 1;
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
if (char === "'") {
|
|
755
|
+
return { kind: 'string', value };
|
|
756
|
+
}
|
|
757
|
+
value += char;
|
|
758
|
+
}
|
|
759
|
+
throw new Error('Unterminated RQL string literal.');
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Parses one numeric literal from the current parser cursor.
|
|
764
|
+
*
|
|
765
|
+
* @param state - Mutable parser cursor to read and update in place.
|
|
766
|
+
* @returns Parsed runtime numeric-literal node.
|
|
767
|
+
* @throws Error when no supported numeric literal is present.
|
|
768
|
+
*/
|
|
769
|
+
function parseNumberLiteral(state: RuntimeParsedRqlState): ParsedRqlLiteralNumber {
|
|
770
|
+
skipWhitespace(state);
|
|
771
|
+
const remainder = state.text.slice(state.index);
|
|
772
|
+
const match = remainder.match(/^-?(?:\d*\.\d+|\d+)(?:[Ee][+-]?\d+)?/);
|
|
773
|
+
if (match == null) {
|
|
774
|
+
throw new Error(`Expected a numeric literal at index ${state.index} while parsing RQL.`);
|
|
775
|
+
}
|
|
776
|
+
state.index += match[0].length;
|
|
777
|
+
return { kind: 'number', value: Number(match[0]) };
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Parses one scalar literal: string, number, boolean, or null.
|
|
782
|
+
*
|
|
783
|
+
* @param state - Mutable parser cursor to read and update in place.
|
|
784
|
+
* @returns Parsed runtime scalar-literal node.
|
|
785
|
+
*/
|
|
786
|
+
function parseScalarLiteral(state: RuntimeParsedRqlState): ParsedRqlScalarLiteral {
|
|
787
|
+
skipWhitespace(state);
|
|
788
|
+
const next = state.text[state.index];
|
|
789
|
+
if (next === "'") return parseStringLiteral(state);
|
|
790
|
+
if (startsWithKeyword(state, 'TRUE')) {
|
|
791
|
+
state.index += 4;
|
|
792
|
+
return { kind: 'boolean', value: true };
|
|
793
|
+
}
|
|
794
|
+
if (startsWithKeyword(state, 'FALSE')) {
|
|
795
|
+
state.index += 5;
|
|
796
|
+
return { kind: 'boolean', value: false };
|
|
797
|
+
}
|
|
798
|
+
if (startsWithKeyword(state, 'NULL')) {
|
|
799
|
+
state.index += 4;
|
|
800
|
+
return { kind: 'null', value: null };
|
|
801
|
+
}
|
|
802
|
+
return parseNumberLiteral(state);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Parses one array literal containing zero or more scalar literal elements.
|
|
807
|
+
*
|
|
808
|
+
* @param state - Mutable parser cursor positioned at the opening `[`.
|
|
809
|
+
* @returns Parsed runtime array-literal node.
|
|
810
|
+
*/
|
|
811
|
+
function parseArrayLiteral(state: RuntimeParsedRqlState): ParsedRqlLiteralArray {
|
|
812
|
+
expectCharacter(state, '[');
|
|
813
|
+
const values: ParsedRqlScalarLiteral[] = [];
|
|
814
|
+
skipWhitespace(state);
|
|
815
|
+
if (consumeCharacter(state, ']')) {
|
|
816
|
+
return { kind: 'array', value: values };
|
|
817
|
+
}
|
|
818
|
+
while (true) {
|
|
819
|
+
values.push(parseScalarLiteral(state));
|
|
820
|
+
skipWhitespace(state);
|
|
821
|
+
if (consumeCharacter(state, ']')) {
|
|
822
|
+
return { kind: 'array', value: values };
|
|
823
|
+
}
|
|
824
|
+
expectCharacter(state, ',');
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Parses either one scalar literal or one array literal at the current parser cursor.
|
|
830
|
+
*
|
|
831
|
+
* @param state - Mutable parser cursor to read and update in place.
|
|
832
|
+
* @returns Parsed runtime literal node.
|
|
833
|
+
*/
|
|
834
|
+
function parseLiteral(state: RuntimeParsedRqlState): ParsedRqlLiteral {
|
|
835
|
+
skipWhitespace(state);
|
|
836
|
+
if (state.text[state.index] === '[') {
|
|
837
|
+
return parseArrayLiteral(state);
|
|
838
|
+
}
|
|
839
|
+
return parseScalarLiteral(state);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Parses one supported comparison operator token in longest-first order.
|
|
844
|
+
*
|
|
845
|
+
* @param state - Mutable parser cursor to read and update in place.
|
|
846
|
+
* @returns Parsed comparison operator token.
|
|
847
|
+
* @throws Error when no supported operator is present.
|
|
848
|
+
*/
|
|
849
|
+
function parseOperator(state: RuntimeParsedRqlState): ParsedRqlComparisonNode['operator'] {
|
|
850
|
+
skipWhitespace(state);
|
|
851
|
+
for (const operator of ['NOT_IN', 'IN', '==', '!=', '<=', '>=', '<', '>'] as const) {
|
|
852
|
+
if (state.text.slice(state.index, state.index + operator.length).toUpperCase() === operator) {
|
|
853
|
+
state.index += operator.length;
|
|
854
|
+
return operator;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
throw new Error(`Expected an RQL operator at index ${state.index}.`);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Parses one full comparison clause.
|
|
862
|
+
*
|
|
863
|
+
* @param state - Mutable parser cursor positioned at the start of one comparison expression.
|
|
864
|
+
* @returns Parsed runtime comparison node.
|
|
865
|
+
*/
|
|
866
|
+
function parseComparison(state: RuntimeParsedRqlState): ParsedRqlComparisonNode {
|
|
867
|
+
const field = parseIdentifier(state);
|
|
868
|
+
const operator = parseOperator(state);
|
|
869
|
+
const value = parseLiteral(state);
|
|
870
|
+
return { kind: 'comparison', field, operator, value };
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Parses one parenthesized subexpression or leaf comparison expression.
|
|
875
|
+
*
|
|
876
|
+
* @param state - Mutable parser cursor positioned at the next primary expression.
|
|
877
|
+
* @returns Parsed runtime expression node.
|
|
878
|
+
*/
|
|
879
|
+
function parsePrimary(state: RuntimeParsedRqlState): ParsedRqlExpressionNode {
|
|
880
|
+
skipWhitespace(state);
|
|
881
|
+
if (consumeCharacter(state, '(')) {
|
|
882
|
+
const expression = parseOrExpression(state);
|
|
883
|
+
expectCharacter(state, ')');
|
|
884
|
+
return expression;
|
|
885
|
+
}
|
|
886
|
+
return parseComparison(state);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Parses one NOT-prefixed expression, recursing to preserve unary precedence.
|
|
891
|
+
*
|
|
892
|
+
* @param state - Mutable parser cursor positioned at the next unary expression.
|
|
893
|
+
* @returns Parsed runtime expression node.
|
|
894
|
+
*/
|
|
895
|
+
function parseNotExpression(state: RuntimeParsedRqlState): ParsedRqlExpressionNode {
|
|
896
|
+
skipWhitespace(state);
|
|
897
|
+
if (consumeKeyword(state, 'NOT')) {
|
|
898
|
+
return { kind: 'not', operand: parseNotExpression(state) };
|
|
899
|
+
}
|
|
900
|
+
return parsePrimary(state);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Parses one AND-composed expression group.
|
|
905
|
+
*
|
|
906
|
+
* @param state - Mutable parser cursor positioned at the next AND-precedence expression.
|
|
907
|
+
* @returns Parsed runtime expression node, collapsed when only one operand is present.
|
|
908
|
+
*/
|
|
909
|
+
function parseAndExpression(state: RuntimeParsedRqlState): ParsedRqlExpressionNode {
|
|
910
|
+
const operands: ParsedRqlExpressionNode[] = [parseNotExpression(state)];
|
|
911
|
+
while (true) {
|
|
912
|
+
const checkpoint = state.index;
|
|
913
|
+
if (!consumeKeyword(state, 'AND')) {
|
|
914
|
+
state.index = checkpoint;
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
operands.push(parseNotExpression(state));
|
|
918
|
+
}
|
|
919
|
+
return operands.length === 1 ?
|
|
920
|
+
(operands[0] as ParsedRqlExpressionNode)
|
|
921
|
+
: { kind: 'logical', operator: 'AND', operands };
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Parses one OR-composed expression group, the lowest-precedence logical form.
|
|
926
|
+
*
|
|
927
|
+
* @param state - Mutable parser cursor positioned at the next OR-precedence expression.
|
|
928
|
+
* @returns Parsed runtime expression node, collapsed when only one operand is present.
|
|
929
|
+
*/
|
|
930
|
+
function parseOrExpression(state: RuntimeParsedRqlState): ParsedRqlExpressionNode {
|
|
931
|
+
const operands: ParsedRqlExpressionNode[] = [parseAndExpression(state)];
|
|
932
|
+
while (true) {
|
|
933
|
+
const checkpoint = state.index;
|
|
934
|
+
if (!consumeKeyword(state, 'OR')) {
|
|
935
|
+
state.index = checkpoint;
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
operands.push(parseAndExpression(state));
|
|
939
|
+
}
|
|
940
|
+
return operands.length === 1 ?
|
|
941
|
+
(operands[0] as ParsedRqlExpressionNode)
|
|
942
|
+
: { kind: 'logical', operator: 'OR', operands };
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Parses one complete parsed-string RQL expression into the runtime AST.
|
|
947
|
+
*
|
|
948
|
+
* @param text - Logical-name RQL source string to parse.
|
|
949
|
+
* @returns Parsed runtime expression tree.
|
|
950
|
+
* @throws Error when the expression is malformed or contains trailing content.
|
|
951
|
+
*/
|
|
952
|
+
function parseTypedRqlExpression(text: string): ParsedRqlExpressionNode {
|
|
953
|
+
const state: RuntimeParsedRqlState = { text, index: 0 };
|
|
954
|
+
const expression = parseOrExpression(state);
|
|
955
|
+
skipWhitespace(state);
|
|
956
|
+
if (state.index !== state.text.length) {
|
|
957
|
+
throw new Error(
|
|
958
|
+
`Unexpected trailing RQL content starting at index ${state.index}: ${state.text.slice(state.index)}.`,
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
return expression;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Resolves the runtime validation/rendering metadata for one logical field name.
|
|
966
|
+
*
|
|
967
|
+
* @param definition - Object definition that owns the valid field set.
|
|
968
|
+
* @param fieldName - Logical field name referenced by the parsed expression.
|
|
969
|
+
* @returns Runtime metadata used to validate literals and render wire-level field names.
|
|
970
|
+
* @throws Error when the field name is unknown for the supplied definition.
|
|
971
|
+
*/
|
|
972
|
+
function resolveRuntimeFieldMetadata(
|
|
973
|
+
definition: AnyCustomObjectDefinition,
|
|
974
|
+
fieldName: string,
|
|
975
|
+
): RuntimeFieldMetadata {
|
|
976
|
+
if ((STANDARD_TYPED_RQL_FIELDS as readonly string[]).includes(fieldName)) {
|
|
977
|
+
return {
|
|
978
|
+
apiName: fieldName,
|
|
979
|
+
category: STANDARD_LOOKUP_FIELDS.has(fieldName) ? 'lookup' : 'string',
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const field = definition.fields[fieldName as FieldNames<typeof definition>];
|
|
984
|
+
if (field == null) {
|
|
985
|
+
throw new Error(
|
|
986
|
+
`Unknown field "${fieldName}" for "${definition.apiName}". Valid fields: ${[
|
|
987
|
+
...STANDARD_TYPED_RQL_FIELDS,
|
|
988
|
+
...Object.keys(definition.fields).sort(),
|
|
989
|
+
].join(', ')}.`,
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
switch (field.kind) {
|
|
994
|
+
case 'text':
|
|
995
|
+
case 'long-text':
|
|
996
|
+
case 'email':
|
|
997
|
+
case 'url':
|
|
998
|
+
case 'phone':
|
|
999
|
+
case 'date':
|
|
1000
|
+
case 'datetime':
|
|
1001
|
+
case 'time':
|
|
1002
|
+
case 'radio':
|
|
1003
|
+
case 'formula-text':
|
|
1004
|
+
case 'formula-date':
|
|
1005
|
+
case 'formula-url':
|
|
1006
|
+
return { apiName: field.apiName, category: 'string' };
|
|
1007
|
+
case 'number':
|
|
1008
|
+
case 'currency':
|
|
1009
|
+
case 'percentage':
|
|
1010
|
+
case 'formula-number':
|
|
1011
|
+
case 'formula-currency':
|
|
1012
|
+
case 'formula-percentage':
|
|
1013
|
+
return { apiName: field.apiName, category: 'number' };
|
|
1014
|
+
case 'boolean':
|
|
1015
|
+
case 'formula-boolean':
|
|
1016
|
+
return { apiName: field.apiName, category: 'boolean' };
|
|
1017
|
+
case 'lookup':
|
|
1018
|
+
case 'parent-child':
|
|
1019
|
+
return { apiName: field.apiName, category: 'lookup' };
|
|
1020
|
+
default:
|
|
1021
|
+
return { apiName: field.apiName, category: 'unsupported' };
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Describes the literal form a runtime field category accepts in human-readable errors.
|
|
1027
|
+
*
|
|
1028
|
+
* @param category - Runtime field category being validated.
|
|
1029
|
+
* @returns Human-readable description of the expected literal form.
|
|
1030
|
+
*/
|
|
1031
|
+
function describeRuntimeExpectedLiteral(category: RuntimeFieldCategory): string {
|
|
1032
|
+
switch (category) {
|
|
1033
|
+
case 'string':
|
|
1034
|
+
return "a quoted string literal such as 'Ada'";
|
|
1035
|
+
case 'number':
|
|
1036
|
+
return 'a numeric literal such as 14';
|
|
1037
|
+
case 'boolean':
|
|
1038
|
+
return 'a boolean literal: True or False';
|
|
1039
|
+
case 'lookup':
|
|
1040
|
+
return "a quoted record-id string such as 'rec_123'";
|
|
1041
|
+
default:
|
|
1042
|
+
return 'a supported literal value';
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Describes one parsed literal value in human-readable runtime errors.
|
|
1048
|
+
*
|
|
1049
|
+
* @param literal - Parsed literal value to describe.
|
|
1050
|
+
* @returns Human-readable description of the provided literal.
|
|
1051
|
+
*/
|
|
1052
|
+
function describeRuntimeLiteral(literal: ParsedRqlLiteral): string {
|
|
1053
|
+
switch (literal.kind) {
|
|
1054
|
+
case 'string':
|
|
1055
|
+
return `quoted string ${encodeTypedRqlString(literal.value)}`;
|
|
1056
|
+
case 'number':
|
|
1057
|
+
return `number ${String(literal.value)}`;
|
|
1058
|
+
case 'boolean':
|
|
1059
|
+
return `boolean ${literal.value ? 'True' : 'False'}`;
|
|
1060
|
+
case 'null':
|
|
1061
|
+
return 'null';
|
|
1062
|
+
case 'array':
|
|
1063
|
+
return `array ${renderTypedRqlLiteral(literal)}`;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Enforces that one parsed literal/operator pairing is valid for the field category.
|
|
1069
|
+
*
|
|
1070
|
+
* @param fieldName - Logical field name used in user-facing error messages.
|
|
1071
|
+
* @param category - Runtime category inferred for that field.
|
|
1072
|
+
* @param operator - Comparison operator applied to the field.
|
|
1073
|
+
* @param literal - Parsed literal value supplied on the right-hand side.
|
|
1074
|
+
* @throws Error when the operator/literal combination is invalid for the field category.
|
|
1075
|
+
*/
|
|
1076
|
+
function assertLiteralMatchesCategory(
|
|
1077
|
+
fieldName: string,
|
|
1078
|
+
category: RuntimeFieldCategory,
|
|
1079
|
+
operator: ParsedRqlComparisonNode['operator'],
|
|
1080
|
+
literal: ParsedRqlLiteral,
|
|
1081
|
+
): void {
|
|
1082
|
+
if (category === 'unsupported') {
|
|
1083
|
+
throw new Error('typedRql(...) does not yet support this field kind in parsed-string mode.');
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (operator === 'IN' || operator === 'NOT_IN') {
|
|
1087
|
+
if (literal.kind !== 'array') {
|
|
1088
|
+
throw new Error(
|
|
1089
|
+
`RQL field "${fieldName}" with operator "${operator}" requires an array literal such as ['value']; received ${describeRuntimeLiteral(
|
|
1090
|
+
literal,
|
|
1091
|
+
)}.`,
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (literal.value.length === 0) {
|
|
1095
|
+
throw new Error(
|
|
1096
|
+
`RQL field "${fieldName}" with operator "${operator}" requires a non-empty array literal such as ['value'].`,
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
for (const value of literal.value) {
|
|
1100
|
+
assertLiteralMatchesCategory(fieldName, category, '==', value);
|
|
1101
|
+
}
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (literal.kind === 'null') {
|
|
1106
|
+
if (operator === '<' || operator === '<=' || operator === '>' || operator === '>=') {
|
|
1107
|
+
throw new Error(
|
|
1108
|
+
`RQL field "${fieldName}" with operator "${operator}" does not allow null. Use a concrete ${describeRuntimeExpectedLiteral(
|
|
1109
|
+
category,
|
|
1110
|
+
)}.`,
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (
|
|
1117
|
+
(operator === '<' || operator === '<=' || operator === '>' || operator === '>=') &&
|
|
1118
|
+
!(category === 'string' || category === 'number')
|
|
1119
|
+
) {
|
|
1120
|
+
throw new Error(
|
|
1121
|
+
`RQL field "${fieldName}" uses operator "${operator}", which is only valid for string or number fields; this field expects ${describeRuntimeExpectedLiteral(
|
|
1122
|
+
category,
|
|
1123
|
+
)}.`,
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
switch (category) {
|
|
1128
|
+
case 'string':
|
|
1129
|
+
if (literal.kind !== 'string') {
|
|
1130
|
+
throw new Error(
|
|
1131
|
+
`RQL field "${fieldName}" with operator "${operator}" expects ${describeRuntimeExpectedLiteral(
|
|
1132
|
+
category,
|
|
1133
|
+
)}; received ${describeRuntimeLiteral(literal)}.`,
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
case 'number':
|
|
1138
|
+
if (literal.kind !== 'number') {
|
|
1139
|
+
throw new Error(
|
|
1140
|
+
`RQL field "${fieldName}" with operator "${operator}" expects ${describeRuntimeExpectedLiteral(
|
|
1141
|
+
category,
|
|
1142
|
+
)}; received ${describeRuntimeLiteral(literal)}.`,
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
return;
|
|
1146
|
+
case 'boolean':
|
|
1147
|
+
if (literal.kind !== 'boolean') {
|
|
1148
|
+
throw new Error(
|
|
1149
|
+
`RQL field "${fieldName}" with operator "${operator}" expects ${describeRuntimeExpectedLiteral(
|
|
1150
|
+
category,
|
|
1151
|
+
)}; received ${describeRuntimeLiteral(literal)}.`,
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
return;
|
|
1155
|
+
case 'lookup':
|
|
1156
|
+
if (literal.kind !== 'string') {
|
|
1157
|
+
throw new Error(
|
|
1158
|
+
`RQL field "${fieldName}" with operator "${operator}" expects ${describeRuntimeExpectedLiteral(
|
|
1159
|
+
category,
|
|
1160
|
+
)}; received ${describeRuntimeLiteral(literal)}.`,
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
return;
|
|
1164
|
+
default:
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Walks the runtime AST and validates each comparison against the object definition.
|
|
1171
|
+
*
|
|
1172
|
+
* @param definition - Object definition that owns the valid field set and field categories.
|
|
1173
|
+
* @param node - Parsed runtime AST node to validate.
|
|
1174
|
+
* @throws Error when any referenced field or literal/operator combination is invalid.
|
|
1175
|
+
*/
|
|
1176
|
+
function validateTypedRqlAst(definition: AnyCustomObjectDefinition, node: ParsedRqlExpressionNode): void {
|
|
1177
|
+
switch (node.kind) {
|
|
1178
|
+
case 'logical':
|
|
1179
|
+
for (const operand of node.operands) validateTypedRqlAst(definition, operand);
|
|
1180
|
+
return;
|
|
1181
|
+
case 'not':
|
|
1182
|
+
validateTypedRqlAst(definition, node.operand);
|
|
1183
|
+
return;
|
|
1184
|
+
case 'comparison': {
|
|
1185
|
+
const metadata = resolveRuntimeFieldMetadata(definition, node.field);
|
|
1186
|
+
assertLiteralMatchesCategory(node.field, metadata.category, node.operator, node.value);
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Escapes one string value back into backend-ready single-quoted RQL syntax.
|
|
1194
|
+
*
|
|
1195
|
+
* @param value - Raw string value to encode.
|
|
1196
|
+
* @returns Escaped single-quoted RQL literal text.
|
|
1197
|
+
*/
|
|
1198
|
+
function encodeTypedRqlString(value: string): string {
|
|
1199
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* Renders one parsed literal value back into backend-ready RQL text.
|
|
1204
|
+
*
|
|
1205
|
+
* @param literal - Parsed literal node to render.
|
|
1206
|
+
* @returns Backend-ready RQL literal text.
|
|
1207
|
+
*/
|
|
1208
|
+
function renderTypedRqlLiteral(literal: ParsedRqlLiteral): string {
|
|
1209
|
+
switch (literal.kind) {
|
|
1210
|
+
case 'string':
|
|
1211
|
+
return encodeTypedRqlString(literal.value);
|
|
1212
|
+
case 'number':
|
|
1213
|
+
return String(literal.value);
|
|
1214
|
+
case 'boolean':
|
|
1215
|
+
return literal.value ? 'True' : 'False';
|
|
1216
|
+
case 'null':
|
|
1217
|
+
return 'null';
|
|
1218
|
+
case 'array':
|
|
1219
|
+
return `[${literal.value.map((value) => renderTypedRqlLiteral(value)).join(', ')}]`;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
/**
|
|
1224
|
+
* Renders the validated runtime AST back into backend-ready wire-level RQL.
|
|
1225
|
+
*
|
|
1226
|
+
* @param definition - Object definition that supplies wire-level field API names.
|
|
1227
|
+
* @param node - Parsed and validated runtime AST node to render.
|
|
1228
|
+
* @returns Backend-ready RQL expression string.
|
|
1229
|
+
*/
|
|
1230
|
+
function renderTypedRqlAst(definition: AnyCustomObjectDefinition, node: ParsedRqlExpressionNode): string {
|
|
1231
|
+
switch (node.kind) {
|
|
1232
|
+
case 'logical':
|
|
1233
|
+
return `(${node.operands
|
|
1234
|
+
.map((operand) => renderTypedRqlAst(definition, operand))
|
|
1235
|
+
.join(` ${node.operator} `)})`;
|
|
1236
|
+
case 'not':
|
|
1237
|
+
return `(NOT ${renderTypedRqlAst(definition, node.operand)})`;
|
|
1238
|
+
case 'comparison': {
|
|
1239
|
+
const metadata = resolveRuntimeFieldMetadata(definition, node.field);
|
|
1240
|
+
return `(${metadata.apiName} ${node.operator} ${renderTypedRqlLiteral(node.value)})`;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* Parses a constrained logical-name RQL string, validates it against the typed custom-object definition,
|
|
1247
|
+
* and renders a backend-ready RQL string that uses wire-level field api names.
|
|
1248
|
+
*
|
|
1249
|
+
* Supported parsed-string custom-object RQL contract:
|
|
1250
|
+
* - standard record fields and local custom-object fields
|
|
1251
|
+
* - `==`, `!=`, `<`, `<=`, `>`, `>=`, `IN`, `NOT_IN`
|
|
1252
|
+
* - `AND`, `OR`, `NOT`
|
|
1253
|
+
* - parentheses / grouping
|
|
1254
|
+
* - string / number / boolean / null / array literals
|
|
1255
|
+
* - lookup equality against quoted ids such as `owner_role == 'role_123'`
|
|
1256
|
+
*
|
|
1257
|
+
* This helper intentionally targets the SDK's documented custom-object subset
|
|
1258
|
+
* rather than the full universe of backend RQL features.
|
|
1259
|
+
*
|
|
1260
|
+
* @param definition - Object definition whose logical field names and value categories should be enforced.
|
|
1261
|
+
* @param expression - Constrained logical-name RQL source string to parse and render.
|
|
1262
|
+
* @returns Backend-ready RQL string that uses wire-level field API names.
|
|
1263
|
+
* @typeParam TDefinition - Object definition whose field names and value types should be enforced.
|
|
1264
|
+
* @typeParam TExpression - Candidate RQL expression string.
|
|
1265
|
+
*/
|
|
1266
|
+
export function typedRql<TDefinition extends AnyCustomObjectDefinition, TExpression extends string>(
|
|
1267
|
+
definition: TDefinition,
|
|
1268
|
+
expression: CheckedParsedRql<TDefinition, TExpression>,
|
|
1269
|
+
): string {
|
|
1270
|
+
const ast = parseTypedRqlExpression(expression as string);
|
|
1271
|
+
validateTypedRqlAst(definition, ast);
|
|
1272
|
+
return renderTypedRqlAst(definition, ast);
|
|
1273
|
+
}
|