@baasix/baasix 0.1.0
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/LICENSE.MD +85 -0
- package/README.md +526 -0
- package/assets/banner.jpg +0 -0
- package/assets/banner_small.jpg +0 -0
- package/assets/logo_icon.svg +20 -0
- package/assets/logo_icon_rounded.svg +20 -0
- package/dist/LICENSE.MD +85 -0
- package/dist/README.md +526 -0
- package/dist/app/404/index.html +1 -0
- package/dist/app/404.html +1 -0
- package/dist/app/_next/static/chunks/041e1f03-56ae8a902a7f2fe6.js +24 -0
- package/dist/app/_next/static/chunks/1117-05479929a8da73e3.js +1 -0
- package/dist/app/_next/static/chunks/1299.77cc7b7b76b75cba.js +1 -0
- package/dist/app/_next/static/chunks/1303-35a96e9c9cdeab9d.js +1 -0
- package/dist/app/_next/static/chunks/1509-56ac00cdaaecdf53.js +1 -0
- package/dist/app/_next/static/chunks/1668-e3eabd0f6753c780.js +1 -0
- package/dist/app/_next/static/chunks/1783-d9fb550fd324300c.js +1 -0
- package/dist/app/_next/static/chunks/2117-29b5fa47421595ad.js +2 -0
- package/dist/app/_next/static/chunks/2344.35b46d2179a765b5.js +1 -0
- package/dist/app/_next/static/chunks/257.990da16794a31292.js +1 -0
- package/dist/app/_next/static/chunks/2676-73b0ee7c80073a84.js +1 -0
- package/dist/app/_next/static/chunks/3563-b8842744384391fe.js +1 -0
- package/dist/app/_next/static/chunks/363642f4-933b579ed3c85f60.js +1 -0
- package/dist/app/_next/static/chunks/3817-e20c8f0a0810fc95.js +1 -0
- package/dist/app/_next/static/chunks/3834.84944e390d902509.js +2 -0
- package/dist/app/_next/static/chunks/4043-3a30c8a75896f241.js +1 -0
- package/dist/app/_next/static/chunks/4225-14090c7c0cd9dec6.js +1 -0
- package/dist/app/_next/static/chunks/4438-c9a12ca15b6e9160.js +1 -0
- package/dist/app/_next/static/chunks/4458-679fd0c6884f456a.js +1 -0
- package/dist/app/_next/static/chunks/4475-8bdfbd536fba8c48.js +1 -0
- package/dist/app/_next/static/chunks/4883-8a924721bb21b3b0.js +1 -0
- package/dist/app/_next/static/chunks/489-683ab07188f9df2b.js +1 -0
- package/dist/app/_next/static/chunks/4952-1b97320cf61f3f21.js +1 -0
- package/dist/app/_next/static/chunks/5094-8d53e403235d4ca6.js +1 -0
- package/dist/app/_next/static/chunks/5101-3a146e0625747ad1.js +1 -0
- package/dist/app/_next/static/chunks/54a60aa6-d9747982e0a81f58.js +79 -0
- package/dist/app/_next/static/chunks/5650-f096291df402bfc2.js +1 -0
- package/dist/app/_next/static/chunks/600-539045311240f579.js +1 -0
- package/dist/app/_next/static/chunks/6170-803b82e19d3ade6d.js +89 -0
- package/dist/app/_next/static/chunks/6241-30d7169d1010e5a4.js +1 -0
- package/dist/app/_next/static/chunks/6530-a91e10cffa4200c4.js +1 -0
- package/dist/app/_next/static/chunks/6547-4bbbdb5c399aef1e.js +1 -0
- package/dist/app/_next/static/chunks/6712-781937c53a2c49da.js +1 -0
- package/dist/app/_next/static/chunks/6fcbdc68-90be1a5480b8d353.js +1 -0
- package/dist/app/_next/static/chunks/70e0d97a-aeaf0cdc26ba1a58.js +1 -0
- package/dist/app/_next/static/chunks/7214-5154a89d08d24dde.js +1 -0
- package/dist/app/_next/static/chunks/7324-b53229c59a640880.js +10 -0
- package/dist/app/_next/static/chunks/7636-66424f0b51d350e9.js +1 -0
- package/dist/app/_next/static/chunks/7874-39a3f2541165a675.js +1 -0
- package/dist/app/_next/static/chunks/7982-9da12b83f11e3f5f.js +1 -0
- package/dist/app/_next/static/chunks/8213a2eb-da25a3b3c5521b2b.js +1 -0
- package/dist/app/_next/static/chunks/8473-6598318371eca31b.js +1 -0
- package/dist/app/_next/static/chunks/8640fa6b-72e43370f68e5587.js +1 -0
- package/dist/app/_next/static/chunks/9090-3ef676f29c95f1c7.js +1 -0
- package/dist/app/_next/static/chunks/9124-a02f9e209e6e3cce.js +1 -0
- package/dist/app/_next/static/chunks/926-156f32067d111d6b.js +1 -0
- package/dist/app/_next/static/chunks/9487-b17481605e513b83.js +1 -0
- package/dist/app/_next/static/chunks/9599-a7e572bb88c3392b.js +1 -0
- package/dist/app/_next/static/chunks/9881-419697138376e755.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/all-activity/page-8917930b4d663405.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/email-log/page-b27a6ee32782d7df.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/notifications/page-b7eda523ede2702c.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/page-1cfa62d1caedaed0.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/sessions/page-3e21e20db90aeff7.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/workflow-executions/page-27bcc26b747fb29b.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/activity-log/workflow-logs/page-9f9e9e952aef436e.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/change-password/page-8d61aa499eabb127.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/dashboard/page-1ceeac9e72997a8a.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/data-browser/page-8cda2b57759dd670.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/file-manager/page-8c6f1b1da66ad7e4.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/layout-f70d225b2759c998.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/migrations/page-aacec8f7cfb40ab2.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/permissions/page-828110cfcde429c6.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/project/page-420e794bb76bd204.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/roles/page-9001d02b28f70708.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/schema/page-899574f35091dd58.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/tasks/page-ad7ab3e27c83f44f.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/templates/edit/page-bd83414cb8c4cb04.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/templates/page-3181447f8772b1d3.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/settings/tenants/page-ef9bfbacef5a1d73.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/users/invites/page-480306b7b2bbac7e.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/users/list/page-74da51254c2606b3.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/users/page-e99c6f0b915001b2.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/users/preferences/page-1a935630ce8f2b12.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/users/user-roles/page-901dfb8ea1f39ca8.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/workflows/detail/page-9a6b839aea688ca4.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/workflows/edit/page-11774efbc2fecae2.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/workflows/execution/page-8ec1aea90412c03d.js +1 -0
- package/dist/app/_next/static/chunks/app/(authenticated)/workflows/page-88bc5b36ccb0a1f7.js +1 -0
- package/dist/app/_next/static/chunks/app/(public)/forgot-password/page-ed263fd46ef81c20.js +1 -0
- package/dist/app/_next/static/chunks/app/(public)/layout-f538977545844af8.js +1 -0
- package/dist/app/_next/static/chunks/app/(public)/login/page-c0a10b137f346096.js +1 -0
- package/dist/app/_next/static/chunks/app/(public)/register/page-4cb7644893efd9b3.js +1 -0
- package/dist/app/_next/static/chunks/app/_not-found/page-653f8815b78256cc.js +1 -0
- package/dist/app/_next/static/chunks/app/layout-591ca7a3e16528a1.js +1 -0
- package/dist/app/_next/static/chunks/app/page-dd19d124b5fa2577.js +1 -0
- package/dist/app/_next/static/chunks/c37d3baf.c2ff165f5b02c692.js +1 -0
- package/dist/app/_next/static/chunks/d0deef33.0379166a4ec23470.js +1 -0
- package/dist/app/_next/static/chunks/fd9d1056-54169f07cd680d6c.js +1 -0
- package/dist/app/_next/static/chunks/framework-8e0e0f4a6b83a956.js +1 -0
- package/dist/app/_next/static/chunks/main-324e91f5a430cddf.js +1 -0
- package/dist/app/_next/static/chunks/main-app-55bcae20c77aaf0e.js +1 -0
- package/dist/app/_next/static/chunks/pages/_app-3c9ca398d360b709.js +1 -0
- package/dist/app/_next/static/chunks/pages/_error-cf5ca766ac8f493f.js +1 -0
- package/dist/app/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/app/_next/static/chunks/webpack-2c306566f7ee1b63.js +1 -0
- package/dist/app/_next/static/css/6c4002bae4e236b2.css +3 -0
- package/dist/app/_next/static/css/a275cc2b185e04f8.css +1 -0
- package/dist/app/_next/static/eCWhKA8XHqmB1zgFcEtN2/_buildManifest.js +1 -0
- package/dist/app/_next/static/eCWhKA8XHqmB1zgFcEtN2/_ssgManifest.js +1 -0
- package/dist/app/activity-log/all-activity/index.html +1 -0
- package/dist/app/activity-log/all-activity/index.txt +14 -0
- package/dist/app/activity-log/email-log/index.html +1 -0
- package/dist/app/activity-log/email-log/index.txt +14 -0
- package/dist/app/activity-log/index.html +1 -0
- package/dist/app/activity-log/index.txt +14 -0
- package/dist/app/activity-log/notifications/index.html +1 -0
- package/dist/app/activity-log/notifications/index.txt +14 -0
- package/dist/app/activity-log/sessions/index.html +1 -0
- package/dist/app/activity-log/sessions/index.txt +14 -0
- package/dist/app/activity-log/workflow-executions/index.html +1 -0
- package/dist/app/activity-log/workflow-executions/index.txt +14 -0
- package/dist/app/activity-log/workflow-logs/index.html +1 -0
- package/dist/app/activity-log/workflow-logs/index.txt +14 -0
- package/dist/app/change-password/index.html +1 -0
- package/dist/app/change-password/index.txt +14 -0
- package/dist/app/dashboard/index.html +1 -0
- package/dist/app/dashboard/index.txt +14 -0
- package/dist/app/data-browser/index.html +1 -0
- package/dist/app/data-browser/index.txt +14 -0
- package/dist/app/file-manager/index.html +1 -0
- package/dist/app/file-manager/index.txt +14 -0
- package/dist/app/forgot-password/index.html +1 -0
- package/dist/app/forgot-password/index.txt +13 -0
- package/dist/app/index.html +1 -0
- package/dist/app/index.txt +9 -0
- package/dist/app/login/index.html +1 -0
- package/dist/app/login/index.txt +13 -0
- package/dist/app/logo-dark.png +0 -0
- package/dist/app/logo-icon.svg +81 -0
- package/dist/app/logo-light.png +0 -0
- package/dist/app/register/index.html +1 -0
- package/dist/app/register/index.txt +13 -0
- package/dist/app/settings/migrations/index.html +1 -0
- package/dist/app/settings/migrations/index.txt +14 -0
- package/dist/app/settings/permissions/index.html +1 -0
- package/dist/app/settings/permissions/index.txt +14 -0
- package/dist/app/settings/project/index.html +1 -0
- package/dist/app/settings/project/index.txt +14 -0
- package/dist/app/settings/roles/index.html +1 -0
- package/dist/app/settings/roles/index.txt +14 -0
- package/dist/app/settings/schema/index.html +1 -0
- package/dist/app/settings/schema/index.txt +14 -0
- package/dist/app/settings/tasks/index.html +1 -0
- package/dist/app/settings/tasks/index.txt +14 -0
- package/dist/app/settings/templates/edit/index.html +1 -0
- package/dist/app/settings/templates/edit/index.txt +14 -0
- package/dist/app/settings/templates/index.html +1 -0
- package/dist/app/settings/templates/index.txt +14 -0
- package/dist/app/settings/tenants/index.html +1 -0
- package/dist/app/settings/tenants/index.txt +14 -0
- package/dist/app/users/index.html +1 -0
- package/dist/app/users/index.txt +14 -0
- package/dist/app/users/invites/index.html +1 -0
- package/dist/app/users/invites/index.txt +14 -0
- package/dist/app/users/list/index.html +1 -0
- package/dist/app/users/list/index.txt +14 -0
- package/dist/app/users/preferences/index.html +1 -0
- package/dist/app/users/preferences/index.txt +14 -0
- package/dist/app/users/user-roles/index.html +1 -0
- package/dist/app/users/user-roles/index.txt +14 -0
- package/dist/app/workflows/detail/index.html +1 -0
- package/dist/app/workflows/detail/index.txt +14 -0
- package/dist/app/workflows/edit/index.html +1 -0
- package/dist/app/workflows/edit/index.txt +14 -0
- package/dist/app/workflows/execution/index.html +1 -0
- package/dist/app/workflows/execution/index.txt +14 -0
- package/dist/app/workflows/index.html +1 -0
- package/dist/app/workflows/index.txt +14 -0
- package/dist/app.d.ts +36 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +546 -0
- package/dist/app.js.map +1 -0
- package/dist/auth/adapters/baasix-adapter.d.ts +12 -0
- package/dist/auth/adapters/baasix-adapter.d.ts.map +1 -0
- package/dist/auth/adapters/baasix-adapter.js +318 -0
- package/dist/auth/adapters/baasix-adapter.js.map +1 -0
- package/dist/auth/adapters/index.d.ts +6 -0
- package/dist/auth/adapters/index.d.ts.map +1 -0
- package/dist/auth/adapters/index.js +5 -0
- package/dist/auth/adapters/index.js.map +1 -0
- package/dist/auth/core.d.ts +73 -0
- package/dist/auth/core.d.ts.map +1 -0
- package/dist/auth/core.js +528 -0
- package/dist/auth/core.js.map +1 -0
- package/dist/auth/index.d.ts +56 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +58 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth2/index.d.ts +5 -0
- package/dist/auth/oauth2/index.d.ts.map +1 -0
- package/dist/auth/oauth2/index.js +5 -0
- package/dist/auth/oauth2/index.js.map +1 -0
- package/dist/auth/oauth2/utils.d.ts +90 -0
- package/dist/auth/oauth2/utils.d.ts.map +1 -0
- package/dist/auth/oauth2/utils.js +167 -0
- package/dist/auth/oauth2/utils.js.map +1 -0
- package/dist/auth/providers/apple.d.ts +28 -0
- package/dist/auth/providers/apple.d.ts.map +1 -0
- package/dist/auth/providers/apple.js +192 -0
- package/dist/auth/providers/apple.js.map +1 -0
- package/dist/auth/providers/credential.d.ts +87 -0
- package/dist/auth/providers/credential.d.ts.map +1 -0
- package/dist/auth/providers/credential.js +162 -0
- package/dist/auth/providers/credential.js.map +1 -0
- package/dist/auth/providers/facebook.d.ts +26 -0
- package/dist/auth/providers/facebook.d.ts.map +1 -0
- package/dist/auth/providers/facebook.js +112 -0
- package/dist/auth/providers/facebook.js.map +1 -0
- package/dist/auth/providers/github.d.ts +29 -0
- package/dist/auth/providers/github.d.ts.map +1 -0
- package/dist/auth/providers/github.js +144 -0
- package/dist/auth/providers/github.js.map +1 -0
- package/dist/auth/providers/google.d.ts +32 -0
- package/dist/auth/providers/google.d.ts.map +1 -0
- package/dist/auth/providers/google.js +145 -0
- package/dist/auth/providers/google.js.map +1 -0
- package/dist/auth/providers/index.d.ts +22 -0
- package/dist/auth/providers/index.d.ts.map +1 -0
- package/dist/auth/providers/index.js +17 -0
- package/dist/auth/providers/index.js.map +1 -0
- package/dist/auth/routes.d.ts +63 -0
- package/dist/auth/routes.d.ts.map +1 -0
- package/dist/auth/routes.js +827 -0
- package/dist/auth/routes.js.map +1 -0
- package/dist/auth/services/index.d.ts +10 -0
- package/dist/auth/services/index.d.ts.map +1 -0
- package/dist/auth/services/index.js +7 -0
- package/dist/auth/services/index.js.map +1 -0
- package/dist/auth/services/session.d.ts +81 -0
- package/dist/auth/services/session.d.ts.map +1 -0
- package/dist/auth/services/session.js +186 -0
- package/dist/auth/services/session.js.map +1 -0
- package/dist/auth/services/token.d.ts +41 -0
- package/dist/auth/services/token.d.ts.map +1 -0
- package/dist/auth/services/token.js +44 -0
- package/dist/auth/services/token.js.map +1 -0
- package/dist/auth/services/verification.d.ts +77 -0
- package/dist/auth/services/verification.d.ts.map +1 -0
- package/dist/auth/services/verification.js +143 -0
- package/dist/auth/services/verification.js.map +1 -0
- package/dist/auth/types.d.ts +318 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +6 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/customTypes/arrays.d.ts +200 -0
- package/dist/customTypes/arrays.d.ts.map +1 -0
- package/dist/customTypes/arrays.js +309 -0
- package/dist/customTypes/arrays.js.map +1 -0
- package/dist/customTypes/index.d.ts +8 -0
- package/dist/customTypes/index.d.ts.map +1 -0
- package/dist/customTypes/index.js +11 -0
- package/dist/customTypes/index.js.map +1 -0
- package/dist/customTypes/postgis.d.ts +146 -0
- package/dist/customTypes/postgis.d.ts.map +1 -0
- package/dist/customTypes/postgis.js +315 -0
- package/dist/customTypes/postgis.js.map +1 -0
- package/dist/customTypes/ranges.d.ts +128 -0
- package/dist/customTypes/ranges.d.ts.map +1 -0
- package/dist/customTypes/ranges.js +257 -0
- package/dist/customTypes/ranges.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/0.1.0-alpha.0_initial_setup.d.ts +29 -0
- package/dist/migrations/0.1.0-alpha.0_initial_setup.d.ts.map +1 -0
- package/dist/migrations/0.1.0-alpha.0_initial_setup.js +72 -0
- package/dist/migrations/0.1.0-alpha.0_initial_setup.js.map +1 -0
- package/dist/migrations/_example_migration.d.ts +31 -0
- package/dist/migrations/_example_migration.d.ts.map +1 -0
- package/dist/migrations/_example_migration.js +75 -0
- package/dist/migrations/_example_migration.js.map +1 -0
- package/dist/plugins/definePlugin.d.ts +49 -0
- package/dist/plugins/definePlugin.d.ts.map +1 -0
- package/dist/plugins/definePlugin.js +131 -0
- package/dist/plugins/definePlugin.js.map +1 -0
- package/dist/plugins/softDelete.d.ts +179 -0
- package/dist/plugins/softDelete.d.ts.map +1 -0
- package/dist/plugins/softDelete.js +235 -0
- package/dist/plugins/softDelete.js.map +1 -0
- package/dist/routes/auth.route.d.ts +14 -0
- package/dist/routes/auth.route.d.ts.map +1 -0
- package/dist/routes/auth.route.js +421 -0
- package/dist/routes/auth.route.js.map +1 -0
- package/dist/routes/file.route.d.ts +7 -0
- package/dist/routes/file.route.d.ts.map +1 -0
- package/dist/routes/file.route.js +274 -0
- package/dist/routes/file.route.js.map +1 -0
- package/dist/routes/items.route.d.ts +7 -0
- package/dist/routes/items.route.d.ts.map +1 -0
- package/dist/routes/items.route.js +369 -0
- package/dist/routes/items.route.js.map +1 -0
- package/dist/routes/migration.route.d.ts +7 -0
- package/dist/routes/migration.route.d.ts.map +1 -0
- package/dist/routes/migration.route.js +225 -0
- package/dist/routes/migration.route.js.map +1 -0
- package/dist/routes/notification.route.d.ts +7 -0
- package/dist/routes/notification.route.d.ts.map +1 -0
- package/dist/routes/notification.route.js +124 -0
- package/dist/routes/notification.route.js.map +1 -0
- package/dist/routes/openapi.route.d.ts +7 -0
- package/dist/routes/openapi.route.d.ts.map +1 -0
- package/dist/routes/openapi.route.js +2169 -0
- package/dist/routes/openapi.route.js.map +1 -0
- package/dist/routes/permission.route.d.ts +7 -0
- package/dist/routes/permission.route.d.ts.map +1 -0
- package/dist/routes/permission.route.js +158 -0
- package/dist/routes/permission.route.js.map +1 -0
- package/dist/routes/realtime.route.d.ts +21 -0
- package/dist/routes/realtime.route.d.ts.map +1 -0
- package/dist/routes/realtime.route.js +243 -0
- package/dist/routes/realtime.route.js.map +1 -0
- package/dist/routes/reports.route.d.ts +7 -0
- package/dist/routes/reports.route.d.ts.map +1 -0
- package/dist/routes/reports.route.js +95 -0
- package/dist/routes/reports.route.js.map +1 -0
- package/dist/routes/schema.route.d.ts +7 -0
- package/dist/routes/schema.route.d.ts.map +1 -0
- package/dist/routes/schema.route.js +1780 -0
- package/dist/routes/schema.route.js.map +1 -0
- package/dist/routes/settings.route.d.ts +7 -0
- package/dist/routes/settings.route.d.ts.map +1 -0
- package/dist/routes/settings.route.js +154 -0
- package/dist/routes/settings.route.js.map +1 -0
- package/dist/routes/templates.route.d.ts +7 -0
- package/dist/routes/templates.route.d.ts.map +1 -0
- package/dist/routes/templates.route.js +91 -0
- package/dist/routes/templates.route.js.map +1 -0
- package/dist/routes/utils.route.d.ts +7 -0
- package/dist/routes/utils.route.d.ts.map +1 -0
- package/dist/routes/utils.route.js +33 -0
- package/dist/routes/utils.route.js.map +1 -0
- package/dist/routes/workflow.route.d.ts +7 -0
- package/dist/routes/workflow.route.d.ts.map +1 -0
- package/dist/routes/workflow.route.js +787 -0
- package/dist/routes/workflow.route.js.map +1 -0
- package/dist/services/AssetsService.d.ts +39 -0
- package/dist/services/AssetsService.d.ts.map +1 -0
- package/dist/services/AssetsService.js +255 -0
- package/dist/services/AssetsService.js.map +1 -0
- package/dist/services/CacheService.d.ts +169 -0
- package/dist/services/CacheService.d.ts.map +1 -0
- package/dist/services/CacheService.js +722 -0
- package/dist/services/CacheService.js.map +1 -0
- package/dist/services/FilesService.d.ts +30 -0
- package/dist/services/FilesService.d.ts.map +1 -0
- package/dist/services/FilesService.js +268 -0
- package/dist/services/FilesService.js.map +1 -0
- package/dist/services/HooksManager.d.ts +38 -0
- package/dist/services/HooksManager.d.ts.map +1 -0
- package/dist/services/HooksManager.js +165 -0
- package/dist/services/HooksManager.js.map +1 -0
- package/dist/services/ItemsService.d.ts +273 -0
- package/dist/services/ItemsService.d.ts.map +1 -0
- package/dist/services/ItemsService.js +2458 -0
- package/dist/services/ItemsService.js.map +1 -0
- package/dist/services/MailService.d.ts +76 -0
- package/dist/services/MailService.d.ts.map +1 -0
- package/dist/services/MailService.js +585 -0
- package/dist/services/MailService.js.map +1 -0
- package/dist/services/MigrationService.d.ts +243 -0
- package/dist/services/MigrationService.d.ts.map +1 -0
- package/dist/services/MigrationService.js +914 -0
- package/dist/services/MigrationService.js.map +1 -0
- package/dist/services/NotificationService.d.ts +35 -0
- package/dist/services/NotificationService.d.ts.map +1 -0
- package/dist/services/NotificationService.js +159 -0
- package/dist/services/NotificationService.js.map +1 -0
- package/dist/services/PermissionService.d.ts +128 -0
- package/dist/services/PermissionService.d.ts.map +1 -0
- package/dist/services/PermissionService.js +373 -0
- package/dist/services/PermissionService.js.map +1 -0
- package/dist/services/PluginManager.d.ts +138 -0
- package/dist/services/PluginManager.d.ts.map +1 -0
- package/dist/services/PluginManager.js +463 -0
- package/dist/services/PluginManager.js.map +1 -0
- package/dist/services/RealtimeService.d.ts +209 -0
- package/dist/services/RealtimeService.d.ts.map +1 -0
- package/dist/services/RealtimeService.js +978 -0
- package/dist/services/RealtimeService.js.map +1 -0
- package/dist/services/ReportService.d.ts +13 -0
- package/dist/services/ReportService.d.ts.map +1 -0
- package/dist/services/ReportService.js +91 -0
- package/dist/services/ReportService.js.map +1 -0
- package/dist/services/SettingsService.d.ts +60 -0
- package/dist/services/SettingsService.d.ts.map +1 -0
- package/dist/services/SettingsService.js +474 -0
- package/dist/services/SettingsService.js.map +1 -0
- package/dist/services/SocketService.d.ts +129 -0
- package/dist/services/SocketService.d.ts.map +1 -0
- package/dist/services/SocketService.js +600 -0
- package/dist/services/SocketService.js.map +1 -0
- package/dist/services/StatsService.d.ts +10 -0
- package/dist/services/StatsService.d.ts.map +1 -0
- package/dist/services/StatsService.js +40 -0
- package/dist/services/StatsService.js.map +1 -0
- package/dist/services/StorageService.d.ts +20 -0
- package/dist/services/StorageService.d.ts.map +1 -0
- package/dist/services/StorageService.js +164 -0
- package/dist/services/StorageService.js.map +1 -0
- package/dist/services/TasksService.d.ts +74 -0
- package/dist/services/TasksService.d.ts.map +1 -0
- package/dist/services/TasksService.js +404 -0
- package/dist/services/TasksService.js.map +1 -0
- package/dist/services/WorkflowService.d.ts +305 -0
- package/dist/services/WorkflowService.d.ts.map +1 -0
- package/dist/services/WorkflowService.js +1811 -0
- package/dist/services/WorkflowService.js.map +1 -0
- package/dist/templates/logo/logo.png +0 -0
- package/dist/templates/mails/default.liquid +23 -0
- package/dist/types/aggregation.d.ts +40 -0
- package/dist/types/aggregation.d.ts.map +1 -0
- package/dist/types/aggregation.js +6 -0
- package/dist/types/aggregation.js.map +1 -0
- package/dist/types/assets.d.ts +32 -0
- package/dist/types/assets.d.ts.map +1 -0
- package/dist/types/assets.js +6 -0
- package/dist/types/assets.js.map +1 -0
- package/dist/types/auth.d.ts +50 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +6 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/cache.d.ts +47 -0
- package/dist/types/cache.d.ts.map +1 -0
- package/dist/types/cache.js +6 -0
- package/dist/types/cache.js.map +1 -0
- package/dist/types/database.d.ts +16 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/database.js +6 -0
- package/dist/types/database.js.map +1 -0
- package/dist/types/fields.d.ts +71 -0
- package/dist/types/fields.d.ts.map +1 -0
- package/dist/types/fields.js +6 -0
- package/dist/types/fields.js.map +1 -0
- package/dist/types/files.d.ts +33 -0
- package/dist/types/files.d.ts.map +1 -0
- package/dist/types/files.js +6 -0
- package/dist/types/files.js.map +1 -0
- package/dist/types/hooks.d.ts +29 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/hooks.js +6 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/import-export.d.ts +62 -0
- package/dist/types/import-export.d.ts.map +1 -0
- package/dist/types/import-export.js +6 -0
- package/dist/types/import-export.js.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +58 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mail.d.ts +34 -0
- package/dist/types/mail.d.ts.map +1 -0
- package/dist/types/mail.js +6 -0
- package/dist/types/mail.js.map +1 -0
- package/dist/types/notifications.d.ts +16 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/notifications.js +6 -0
- package/dist/types/notifications.js.map +1 -0
- package/dist/types/plugin.d.ts +351 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +8 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/query.d.ts +71 -0
- package/dist/types/query.d.ts.map +1 -0
- package/dist/types/query.js +6 -0
- package/dist/types/query.js.map +1 -0
- package/dist/types/relations.d.ts +111 -0
- package/dist/types/relations.d.ts.map +1 -0
- package/dist/types/relations.js +6 -0
- package/dist/types/relations.js.map +1 -0
- package/dist/types/reports.d.ts +17 -0
- package/dist/types/reports.d.ts.map +1 -0
- package/dist/types/reports.js +6 -0
- package/dist/types/reports.js.map +1 -0
- package/dist/types/schema.d.ts +26 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +6 -0
- package/dist/types/schema.js.map +1 -0
- package/dist/types/seed.d.ts +27 -0
- package/dist/types/seed.d.ts.map +1 -0
- package/dist/types/seed.js +6 -0
- package/dist/types/seed.js.map +1 -0
- package/dist/types/services.d.ts +68 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +6 -0
- package/dist/types/services.js.map +1 -0
- package/dist/types/settings.d.ts +36 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/settings.js +6 -0
- package/dist/types/settings.js.map +1 -0
- package/dist/types/sockets.d.ts +26 -0
- package/dist/types/sockets.d.ts.map +1 -0
- package/dist/types/sockets.js +6 -0
- package/dist/types/sockets.js.map +1 -0
- package/dist/types/sort.d.ts +25 -0
- package/dist/types/sort.d.ts.map +1 -0
- package/dist/types/sort.js +6 -0
- package/dist/types/sort.js.map +1 -0
- package/dist/types/spatial.d.ts +19 -0
- package/dist/types/spatial.d.ts.map +1 -0
- package/dist/types/spatial.js +6 -0
- package/dist/types/spatial.js.map +1 -0
- package/dist/types/stats.d.ts +21 -0
- package/dist/types/stats.d.ts.map +1 -0
- package/dist/types/stats.js +6 -0
- package/dist/types/stats.js.map +1 -0
- package/dist/types/storage.d.ts +19 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +6 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/tasks.d.ts +14 -0
- package/dist/types/tasks.d.ts.map +1 -0
- package/dist/types/tasks.js +6 -0
- package/dist/types/tasks.js.map +1 -0
- package/dist/types/utils.d.ts +54 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +6 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types/workflow.d.ts +17 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +6 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/utils/aggregationUtils.d.ts +192 -0
- package/dist/utils/aggregationUtils.d.ts.map +1 -0
- package/dist/utils/aggregationUtils.js +450 -0
- package/dist/utils/aggregationUtils.js.map +1 -0
- package/dist/utils/auth.d.ts +93 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +557 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/cache.d.ts +64 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +464 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/common.d.ts +53 -0
- package/dist/utils/common.d.ts.map +1 -0
- package/dist/utils/common.js +162 -0
- package/dist/utils/common.js.map +1 -0
- package/dist/utils/db.d.ts +101 -0
- package/dist/utils/db.d.ts.map +1 -0
- package/dist/utils/db.js +413 -0
- package/dist/utils/db.js.map +1 -0
- package/dist/utils/dirname.d.ts +30 -0
- package/dist/utils/dirname.d.ts.map +1 -0
- package/dist/utils/dirname.js +95 -0
- package/dist/utils/dirname.js.map +1 -0
- package/dist/utils/dynamicVariableResolver.d.ts +17 -0
- package/dist/utils/dynamicVariableResolver.d.ts.map +1 -0
- package/dist/utils/dynamicVariableResolver.js +262 -0
- package/dist/utils/dynamicVariableResolver.js.map +1 -0
- package/dist/utils/env.d.ts +38 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +80 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/errorHandler.d.ts +14 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +79 -0
- package/dist/utils/errorHandler.js.map +1 -0
- package/dist/utils/fieldExpansion.d.ts +30 -0
- package/dist/utils/fieldExpansion.d.ts.map +1 -0
- package/dist/utils/fieldExpansion.js +145 -0
- package/dist/utils/fieldExpansion.js.map +1 -0
- package/dist/utils/fieldUtils.d.ts +179 -0
- package/dist/utils/fieldUtils.d.ts.map +1 -0
- package/dist/utils/fieldUtils.js +424 -0
- package/dist/utils/fieldUtils.js.map +1 -0
- package/dist/utils/filterOperators.d.ts +472 -0
- package/dist/utils/filterOperators.d.ts.map +1 -0
- package/dist/utils/filterOperators.js +1229 -0
- package/dist/utils/filterOperators.js.map +1 -0
- package/dist/utils/importUtils.d.ts +127 -0
- package/dist/utils/importUtils.d.ts.map +1 -0
- package/dist/utils/importUtils.js +437 -0
- package/dist/utils/importUtils.js.map +1 -0
- package/dist/utils/index.d.ts +75 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +101 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +41 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +217 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/orderUtils.d.ts +117 -0
- package/dist/utils/orderUtils.d.ts.map +1 -0
- package/dist/utils/orderUtils.js +249 -0
- package/dist/utils/orderUtils.js.map +1 -0
- package/dist/utils/queryBuilder.d.ts +118 -0
- package/dist/utils/queryBuilder.d.ts.map +1 -0
- package/dist/utils/queryBuilder.js +489 -0
- package/dist/utils/queryBuilder.js.map +1 -0
- package/dist/utils/relationLoader.d.ts +65 -0
- package/dist/utils/relationLoader.d.ts.map +1 -0
- package/dist/utils/relationLoader.js +1081 -0
- package/dist/utils/relationLoader.js.map +1 -0
- package/dist/utils/relationPathResolver.d.ts +30 -0
- package/dist/utils/relationPathResolver.d.ts.map +1 -0
- package/dist/utils/relationPathResolver.js +173 -0
- package/dist/utils/relationPathResolver.js.map +1 -0
- package/dist/utils/relationUtils.d.ts +139 -0
- package/dist/utils/relationUtils.d.ts.map +1 -0
- package/dist/utils/relationUtils.js +711 -0
- package/dist/utils/relationUtils.js.map +1 -0
- package/dist/utils/router.d.ts +6 -0
- package/dist/utils/router.d.ts.map +1 -0
- package/dist/utils/router.js +95 -0
- package/dist/utils/router.js.map +1 -0
- package/dist/utils/schema.d.ts +88 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +24 -0
- package/dist/utils/schema.js.map +1 -0
- package/dist/utils/schemaManager.d.ts +238 -0
- package/dist/utils/schemaManager.d.ts.map +1 -0
- package/dist/utils/schemaManager.js +1992 -0
- package/dist/utils/schemaManager.js.map +1 -0
- package/dist/utils/schemaValidator.d.ts +83 -0
- package/dist/utils/schemaValidator.d.ts.map +1 -0
- package/dist/utils/schemaValidator.js +491 -0
- package/dist/utils/schemaValidator.js.map +1 -0
- package/dist/utils/seed.d.ts +45 -0
- package/dist/utils/seed.d.ts.map +1 -0
- package/dist/utils/seed.js +248 -0
- package/dist/utils/seed.js.map +1 -0
- package/dist/utils/sessionCleanup.d.ts +10 -0
- package/dist/utils/sessionCleanup.d.ts.map +1 -0
- package/dist/utils/sessionCleanup.js +49 -0
- package/dist/utils/sessionCleanup.js.map +1 -0
- package/dist/utils/sortUtils.d.ts +117 -0
- package/dist/utils/sortUtils.d.ts.map +1 -0
- package/dist/utils/sortUtils.js +232 -0
- package/dist/utils/sortUtils.js.map +1 -0
- package/dist/utils/spatialUtils.d.ts +244 -0
- package/dist/utils/spatialUtils.d.ts.map +1 -0
- package/dist/utils/spatialUtils.js +359 -0
- package/dist/utils/spatialUtils.js.map +1 -0
- package/dist/utils/systemschema.d.ts +11040 -0
- package/dist/utils/systemschema.d.ts.map +1 -0
- package/dist/utils/systemschema.js +1777 -0
- package/dist/utils/systemschema.js.map +1 -0
- package/dist/utils/tenantUtils.d.ts +34 -0
- package/dist/utils/tenantUtils.d.ts.map +1 -0
- package/dist/utils/tenantUtils.js +124 -0
- package/dist/utils/tenantUtils.js.map +1 -0
- package/dist/utils/typeMapper.d.ts +25 -0
- package/dist/utils/typeMapper.d.ts.map +1 -0
- package/dist/utils/typeMapper.js +282 -0
- package/dist/utils/typeMapper.js.map +1 -0
- package/dist/utils/valueValidator.d.ts +60 -0
- package/dist/utils/valueValidator.d.ts.map +1 -0
- package/dist/utils/valueValidator.js +303 -0
- package/dist/utils/valueValidator.js.map +1 -0
- package/dist/utils/workflow.d.ts +87 -0
- package/dist/utils/workflow.d.ts.map +1 -0
- package/dist/utils/workflow.js +205 -0
- package/dist/utils/workflow.js.map +1 -0
- package/package.json +115 -0
|
@@ -0,0 +1,1229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter Operators Module for Drizzle ORM
|
|
3
|
+
*
|
|
4
|
+
* This module provides a comprehensive set of filter operators that map
|
|
5
|
+
* Sequelize-style filter syntax to Drizzle ORM where conditions.
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - Basic comparison operators (eq, ne, gt, lt, gte, lte)
|
|
9
|
+
* - String pattern matching (like, ilike, startsWith, endsWith)
|
|
10
|
+
* - Collection operators (in, notIn)
|
|
11
|
+
* - Range operators (between, notBetween)
|
|
12
|
+
* - Null checks (isNull, isNotNull)
|
|
13
|
+
* - Array operators (arraycontains, arraycontained)
|
|
14
|
+
* - JSONB operators (jsonbContains, jsonbHasKey, jsonbPathExists, etc.)
|
|
15
|
+
* - Geo/spatial operators (within, contains, intersects, dwithin)
|
|
16
|
+
* - Column-to-column comparisons with $COL() syntax
|
|
17
|
+
* - Type casting with PostgreSQL :: syntax
|
|
18
|
+
*/
|
|
19
|
+
import { eq, ne, gt, gte, lt, lte, isNull, isNotNull, inArray, notInArray, between, notBetween, like, ilike, notLike, notIlike, sql } from 'drizzle-orm';
|
|
20
|
+
/**
|
|
21
|
+
* Valid PostgreSQL cast types to prevent SQL injection
|
|
22
|
+
*/
|
|
23
|
+
const VALID_CAST_TYPES = [
|
|
24
|
+
'text', 'varchar', 'char', 'character',
|
|
25
|
+
'integer', 'int', 'bigint', 'smallint',
|
|
26
|
+
'decimal', 'numeric', 'real', 'double precision', 'float',
|
|
27
|
+
'boolean', 'bool',
|
|
28
|
+
'date', 'timestamp', 'timestamptz', 'time', 'timetz',
|
|
29
|
+
'uuid', 'json', 'jsonb',
|
|
30
|
+
'text[]', 'varchar[]', 'integer[]', 'bigint[]', 'uuid[]'
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Validate PostgreSQL cast type to prevent SQL injection
|
|
34
|
+
*/
|
|
35
|
+
function validateCastType(castType) {
|
|
36
|
+
if (!castType)
|
|
37
|
+
return null;
|
|
38
|
+
const normalizedType = castType.toLowerCase().trim();
|
|
39
|
+
if (VALID_CAST_TYPES.includes(normalizedType)) {
|
|
40
|
+
return normalizedType;
|
|
41
|
+
}
|
|
42
|
+
// Invalid cast types are silently ignored (return null to skip casting)
|
|
43
|
+
console.warn(`Invalid cast type "${castType}" will be ignored. Allowed types: ${VALID_CAST_TYPES.join(', ')}`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if a value is a column reference
|
|
48
|
+
* Format: $COL(columnName) or $COL(tableName.columnName)
|
|
49
|
+
*/
|
|
50
|
+
export function isColumnReference(value) {
|
|
51
|
+
return typeof value === 'string' && value.startsWith('$COL(') && value.endsWith(')');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract column name/path from column reference
|
|
55
|
+
*/
|
|
56
|
+
export function extractColumnFromReference(value) {
|
|
57
|
+
return value.slice(5, -1); // Remove '$COL(' and ')'
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse PostgreSQL casting syntax from column reference
|
|
61
|
+
* Example: "columnName::text" -> { columnPath: "columnName", castType: "text" }
|
|
62
|
+
*/
|
|
63
|
+
export function parseColumnCastSyntax(columnPath) {
|
|
64
|
+
const castMatch = columnPath.match(/^(.+)::(.+)$/);
|
|
65
|
+
if (castMatch) {
|
|
66
|
+
return {
|
|
67
|
+
columnPath: castMatch[1],
|
|
68
|
+
castType: castMatch[2]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
columnPath,
|
|
73
|
+
castType: null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build SQL identifier for column with optional casting
|
|
78
|
+
*/
|
|
79
|
+
export function buildColumnSQL(columnPath, castType) {
|
|
80
|
+
const validated = validateCastType(castType || undefined);
|
|
81
|
+
// Check if columnPath is already quoted (e.g., from resolveRelationPath)
|
|
82
|
+
// Format: "alias"."column" or "column"
|
|
83
|
+
if (columnPath.startsWith('"')) {
|
|
84
|
+
// Already quoted, use as-is without nesting sql templates
|
|
85
|
+
return validated ? sql.raw(`CAST(${columnPath} AS ${validated.toUpperCase()})`) : sql.raw(columnPath);
|
|
86
|
+
}
|
|
87
|
+
if (columnPath.includes('.')) {
|
|
88
|
+
const [tableName, columnName] = columnPath.split('.');
|
|
89
|
+
const quotedPath = `"${tableName}"."${columnName}"`;
|
|
90
|
+
return validated ? sql.raw(`CAST(${quotedPath} AS ${validated.toUpperCase()})`) : sql.raw(quotedPath);
|
|
91
|
+
}
|
|
92
|
+
const quotedPath = `"${columnPath}"`;
|
|
93
|
+
return validated ? sql.raw(`CAST(${quotedPath} AS ${validated.toUpperCase()})`) : sql.raw(quotedPath);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build raw SQL string for column identifier (without wrapping in SQL object)
|
|
97
|
+
* Used when we need to build a completely raw SQL expression
|
|
98
|
+
*/
|
|
99
|
+
function buildColumnSQLString(columnPath, castType) {
|
|
100
|
+
const validated = validateCastType(castType || undefined);
|
|
101
|
+
// Check if columnPath is already quoted (e.g., from resolveRelationPath)
|
|
102
|
+
// Format: "alias"."column" or "column"
|
|
103
|
+
let quotedPath;
|
|
104
|
+
if (columnPath.startsWith('"')) {
|
|
105
|
+
// Already quoted, use as-is
|
|
106
|
+
quotedPath = columnPath;
|
|
107
|
+
}
|
|
108
|
+
else if (columnPath.includes('.')) {
|
|
109
|
+
const [tableName, columnName] = columnPath.split('.');
|
|
110
|
+
quotedPath = `"${tableName}"."${columnName}"`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
quotedPath = `"${columnPath}"`;
|
|
114
|
+
}
|
|
115
|
+
return validated ? `CAST(${quotedPath} AS ${validated.toUpperCase()})` : quotedPath;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Safely escape SQL string values
|
|
119
|
+
*/
|
|
120
|
+
function escapeSqlValue(value) {
|
|
121
|
+
return String(value).replace(/'/g, "''");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Convert a value to a raw SQL string literal for use in filter operations
|
|
125
|
+
* Handles dates, strings, and numbers appropriately
|
|
126
|
+
*/
|
|
127
|
+
function valueToRawSQL(value) {
|
|
128
|
+
console.log(`[valueToRawSQL] Input value:`, value, `Type:`, typeof value);
|
|
129
|
+
if (typeof value === 'string') {
|
|
130
|
+
// Check if it's a date-like string (YYYY-MM-DD or ISO format)
|
|
131
|
+
const datePattern = /^\d{4}-\d{2}-\d{2}/;
|
|
132
|
+
if (datePattern.test(value)) {
|
|
133
|
+
const dateObj = new Date(value);
|
|
134
|
+
if (!isNaN(dateObj.getTime())) {
|
|
135
|
+
const result = `'${dateObj.toISOString()}'`;
|
|
136
|
+
console.log(`[valueToRawSQL] Date string converted:`, result);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Regular string - escape and quote
|
|
141
|
+
const result = `'${value.replace(/'/g, "''")}'`;
|
|
142
|
+
console.log(`[valueToRawSQL] String escaped:`, result);
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
else if (value instanceof Date) {
|
|
146
|
+
const result = `'${value.toISOString()}'`;
|
|
147
|
+
console.log(`[valueToRawSQL] Date object converted:`, result);
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Numbers and other types - no quotes
|
|
152
|
+
const result = String(value);
|
|
153
|
+
console.log(`[valueToRawSQL] Number/other:`, result);
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Normalize date values - convert datetime strings to Date objects
|
|
159
|
+
* Keep date-only strings (YYYY-MM-DD) as strings for Date type columns
|
|
160
|
+
* Convert datetime strings (YYYY-MM-DDTHH:MM:SS) to Date objects for DateTime/Timestamp columns
|
|
161
|
+
*/
|
|
162
|
+
function normalizeDateValue(value) {
|
|
163
|
+
// If already a Date, return as-is
|
|
164
|
+
if (value instanceof Date) {
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
167
|
+
// If it's a string that looks like a datetime (has time component), convert to Date
|
|
168
|
+
if (typeof value === 'string') {
|
|
169
|
+
// Check if it's a full datetime string (has time component)
|
|
170
|
+
const datetimePattern = /^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}/;
|
|
171
|
+
if (datetimePattern.test(value)) {
|
|
172
|
+
const parsedDate = new Date(value);
|
|
173
|
+
if (!isNaN(parsedDate.getTime())) {
|
|
174
|
+
return parsedDate;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// For date-only strings (YYYY-MM-DD), keep as string
|
|
178
|
+
// This is needed for Date type columns which expect strings, not Date objects
|
|
179
|
+
}
|
|
180
|
+
// Return as-is for other types (including date-only strings)
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Format array values based on PostgreSQL element type
|
|
185
|
+
*/
|
|
186
|
+
function formatArrayForPostgreSQL(value, elementType) {
|
|
187
|
+
const arrayValue = Array.isArray(value) ? value : [value];
|
|
188
|
+
switch (elementType.toLowerCase()) {
|
|
189
|
+
case 'integer':
|
|
190
|
+
case 'bigint':
|
|
191
|
+
return `ARRAY[${arrayValue.map(v => parseInt(String(v)) || 0).join(',')}]`;
|
|
192
|
+
case 'decimal':
|
|
193
|
+
case 'numeric':
|
|
194
|
+
case 'real':
|
|
195
|
+
case 'double precision':
|
|
196
|
+
return `ARRAY[${arrayValue.map(v => parseFloat(String(v)) || 0).join(',')}]`;
|
|
197
|
+
case 'boolean':
|
|
198
|
+
return `ARRAY[${arrayValue.map(v => Boolean(v)).join(',')}]`;
|
|
199
|
+
case 'uuid':
|
|
200
|
+
return `ARRAY[${arrayValue.map(v => `'${escapeSqlValue(v)}'`).join(',')}]::uuid[]`;
|
|
201
|
+
case 'date':
|
|
202
|
+
case 'dateonly':
|
|
203
|
+
case 'time':
|
|
204
|
+
return `ARRAY[${arrayValue.map(v => `'${escapeSqlValue(v)}'`).join(',')}]::${elementType}[]`;
|
|
205
|
+
case 'string':
|
|
206
|
+
case 'text':
|
|
207
|
+
case 'varchar':
|
|
208
|
+
default:
|
|
209
|
+
return `ARRAY[${arrayValue.map(v => `'${escapeSqlValue(v)}'`).join(',')}]::text[]`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Operator: Equality (eq)
|
|
214
|
+
* Example: { age: { eq: 25 } } -> age = 25
|
|
215
|
+
*/
|
|
216
|
+
export function eqOperator(ctx, value, castType) {
|
|
217
|
+
if (isColumnReference(value)) {
|
|
218
|
+
const rightCol = extractColumnFromReference(value);
|
|
219
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
220
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
221
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
222
|
+
return sql `${leftSQL} = ${rightSQL}`;
|
|
223
|
+
}
|
|
224
|
+
// Normalize date values (convert string dates to Date objects)
|
|
225
|
+
const normalizedValue = normalizeDateValue(value);
|
|
226
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
227
|
+
if (castType || ctx.tableName) {
|
|
228
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
229
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
230
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
231
|
+
return sql.raw(`${leftSQL} = ${rightSQL}`);
|
|
232
|
+
}
|
|
233
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
234
|
+
return eq(ctx.column, normalizedValue);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Operator: Not Equal (ne)
|
|
238
|
+
* Example: { status: { ne: 'inactive' } } -> status != 'inactive'
|
|
239
|
+
* Example: { contract_number: { ne: null } } -> contract_number IS NOT NULL
|
|
240
|
+
*/
|
|
241
|
+
export function neOperator(ctx, value, castType) {
|
|
242
|
+
if (isColumnReference(value)) {
|
|
243
|
+
const rightCol = extractColumnFromReference(value);
|
|
244
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
245
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
246
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
247
|
+
return sql `${leftSQL} != ${rightSQL}`;
|
|
248
|
+
}
|
|
249
|
+
// Special handling for null values - must use IS NOT NULL syntax
|
|
250
|
+
if (value === null) {
|
|
251
|
+
if (castType || ctx.tableName) {
|
|
252
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
253
|
+
return sql `${leftSQL} IS NOT NULL`;
|
|
254
|
+
}
|
|
255
|
+
return isNotNull(ctx.column);
|
|
256
|
+
}
|
|
257
|
+
// Normalize date values (convert string dates to Date objects)
|
|
258
|
+
const normalizedValue = normalizeDateValue(value);
|
|
259
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
260
|
+
if (castType || ctx.tableName) {
|
|
261
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
262
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
263
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
264
|
+
return sql.raw(`${leftSQL} != ${rightSQL}`);
|
|
265
|
+
}
|
|
266
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
267
|
+
return ne(ctx.column, normalizedValue);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Operator: Greater Than (gt)
|
|
271
|
+
* Example: { age: { gt: 18 } } -> age > 18
|
|
272
|
+
*/
|
|
273
|
+
export function gtOperator(ctx, value, castType) {
|
|
274
|
+
if (isColumnReference(value)) {
|
|
275
|
+
const rightCol = extractColumnFromReference(value);
|
|
276
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
277
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
278
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
279
|
+
return sql `${leftSQL} > ${rightSQL}`;
|
|
280
|
+
}
|
|
281
|
+
// Normalize date values (convert string dates to Date objects)
|
|
282
|
+
const normalizedValue = normalizeDateValue(value);
|
|
283
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
284
|
+
if (castType || ctx.tableName) {
|
|
285
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
286
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
287
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
288
|
+
return sql.raw(`${leftSQL} > ${rightSQL}`);
|
|
289
|
+
}
|
|
290
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
291
|
+
return gt(ctx.column, normalizedValue);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Operator: Greater Than or Equal (gte)
|
|
295
|
+
* Example: { age: { gte: 18 } } -> age >= 18
|
|
296
|
+
*/
|
|
297
|
+
export function gteOperator(ctx, value, castType) {
|
|
298
|
+
if (isColumnReference(value)) {
|
|
299
|
+
const rightCol = extractColumnFromReference(value);
|
|
300
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
301
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
302
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
303
|
+
return sql `${leftSQL} >= ${rightSQL}`;
|
|
304
|
+
}
|
|
305
|
+
// Normalize date values (convert string dates to Date objects)
|
|
306
|
+
const normalizedValue = normalizeDateValue(value);
|
|
307
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
308
|
+
if (castType || ctx.tableName) {
|
|
309
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
310
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
311
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
312
|
+
return sql.raw(`${leftSQL} >= ${rightSQL}`);
|
|
313
|
+
}
|
|
314
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
315
|
+
return gte(ctx.column, normalizedValue);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Operator: Less Than (lt)
|
|
319
|
+
* Example: { age: { lt: 65 } } -> age < 65
|
|
320
|
+
*/
|
|
321
|
+
export function ltOperator(ctx, value, castType) {
|
|
322
|
+
if (isColumnReference(value)) {
|
|
323
|
+
const rightCol = extractColumnFromReference(value);
|
|
324
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
325
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
326
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
327
|
+
return sql `${leftSQL} < ${rightSQL}`;
|
|
328
|
+
}
|
|
329
|
+
// Normalize date values (convert string dates to Date objects)
|
|
330
|
+
const normalizedValue = normalizeDateValue(value);
|
|
331
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
332
|
+
if (castType || ctx.tableName) {
|
|
333
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
334
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
335
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
336
|
+
return sql.raw(`${leftSQL} < ${rightSQL}`);
|
|
337
|
+
}
|
|
338
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
339
|
+
return lt(ctx.column, normalizedValue);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Operator: Less Than or Equal (lte)
|
|
343
|
+
* Example: { age: { lte: 65 } } -> age <= 65
|
|
344
|
+
*/
|
|
345
|
+
export function lteOperator(ctx, value, castType) {
|
|
346
|
+
if (isColumnReference(value)) {
|
|
347
|
+
const rightCol = extractColumnFromReference(value);
|
|
348
|
+
const { columnPath, castType: rightCast } = parseColumnCastSyntax(rightCol);
|
|
349
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
350
|
+
const rightSQL = buildColumnSQL(columnPath, rightCast || castType);
|
|
351
|
+
return sql `${leftSQL} <= ${rightSQL}`;
|
|
352
|
+
}
|
|
353
|
+
// Normalize date values (convert string dates to Date objects)
|
|
354
|
+
const normalizedValue = normalizeDateValue(value);
|
|
355
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
356
|
+
if (castType || ctx.tableName) {
|
|
357
|
+
// Build the entire expression as raw SQL to completely bypass Drizzle's type mappers
|
|
358
|
+
const leftSQL = buildColumnSQLString(ctx.fieldName, castType);
|
|
359
|
+
const rightSQL = valueToRawSQL(normalizedValue);
|
|
360
|
+
return sql.raw(`${leftSQL} <= ${rightSQL}`);
|
|
361
|
+
}
|
|
362
|
+
// For Drizzle operators, keep as Date object (Drizzle's column mappers expect Date objects)
|
|
363
|
+
return lte(ctx.column, normalizedValue);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Operator: LIKE (case-sensitive pattern matching)
|
|
367
|
+
* Example: { name: { like: 'John' } } -> name LIKE '%John%'
|
|
368
|
+
*/
|
|
369
|
+
export function likeOperator(ctx, value, castType) {
|
|
370
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
371
|
+
if (castType || ctx.tableName) {
|
|
372
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
373
|
+
return sql `${leftSQL} LIKE ${'%' + escapeSqlValue(value) + '%'}`;
|
|
374
|
+
}
|
|
375
|
+
return like(ctx.column, `%${value}%`);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Operator: NOT LIKE (case-sensitive pattern non-matching)
|
|
379
|
+
*/
|
|
380
|
+
export function notLikeOperator(ctx, value, castType) {
|
|
381
|
+
if (castType || ctx.tableName) {
|
|
382
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
383
|
+
return sql `${leftSQL} NOT LIKE ${'%' + escapeSqlValue(value) + '%'}`;
|
|
384
|
+
}
|
|
385
|
+
return notLike(ctx.column, `%${value}%`);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Operator: ILIKE (case-insensitive pattern matching)
|
|
389
|
+
* Example: { name: { iLike: 'john' } } -> name ILIKE '%john%'
|
|
390
|
+
*/
|
|
391
|
+
export function iLikeOperator(ctx, value, castType) {
|
|
392
|
+
if (castType || ctx.tableName) {
|
|
393
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
394
|
+
return sql `${leftSQL} ILIKE ${'%' + escapeSqlValue(value) + '%'}`;
|
|
395
|
+
}
|
|
396
|
+
return ilike(ctx.column, `%${value}%`);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Operator: NOT ILIKE (case-insensitive pattern non-matching)
|
|
400
|
+
*/
|
|
401
|
+
export function notILikeOperator(ctx, value, castType) {
|
|
402
|
+
if (castType || ctx.tableName) {
|
|
403
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
404
|
+
return sql `${leftSQL} NOT ILIKE ${'%' + escapeSqlValue(value) + '%'}`;
|
|
405
|
+
}
|
|
406
|
+
return notIlike(ctx.column, `%${value}%`);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Operator: Starts With (case-insensitive)
|
|
410
|
+
* Example: { name: { startsWith: 'John' } } -> name ILIKE 'John%'
|
|
411
|
+
*/
|
|
412
|
+
export function startsWithOperator(ctx, value, castType) {
|
|
413
|
+
if (castType) {
|
|
414
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
415
|
+
return sql `${leftSQL} ILIKE ${escapeSqlValue(value) + '%'}`;
|
|
416
|
+
}
|
|
417
|
+
return ilike(ctx.column, `${value}%`);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Operator: Starts With Case-Sensitive (startsWiths)
|
|
421
|
+
*/
|
|
422
|
+
export function startsWithsOperator(ctx, value, castType) {
|
|
423
|
+
if (castType) {
|
|
424
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
425
|
+
return sql `${leftSQL} LIKE ${escapeSqlValue(value) + '%'}`;
|
|
426
|
+
}
|
|
427
|
+
return like(ctx.column, `${value}%`);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Operator: Ends With (case-insensitive)
|
|
431
|
+
* Example: { name: { endsWith: 'son' } } -> name ILIKE '%son'
|
|
432
|
+
*/
|
|
433
|
+
export function endsWithOperator(ctx, value, castType) {
|
|
434
|
+
if (castType) {
|
|
435
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
436
|
+
return sql `${leftSQL} ILIKE ${'%' + escapeSqlValue(value)}`;
|
|
437
|
+
}
|
|
438
|
+
return ilike(ctx.column, `%${value}`);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Operator: Ends With Case-Sensitive (endsWiths)
|
|
442
|
+
*/
|
|
443
|
+
export function endsWithsOperator(ctx, value, castType) {
|
|
444
|
+
if (castType) {
|
|
445
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
446
|
+
return sql `${leftSQL} LIKE ${'%' + escapeSqlValue(value)}`;
|
|
447
|
+
}
|
|
448
|
+
return like(ctx.column, `%${value}`);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Operator: Not Starts With (case-insensitive)
|
|
452
|
+
*/
|
|
453
|
+
export function nstartsWithOperator(ctx, value, castType) {
|
|
454
|
+
if (castType) {
|
|
455
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
456
|
+
return sql `${leftSQL} NOT ILIKE ${escapeSqlValue(value) + '%'}`;
|
|
457
|
+
}
|
|
458
|
+
return notIlike(ctx.column, `${value}%`);
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Operator: Not Starts With Case-Sensitive
|
|
462
|
+
*/
|
|
463
|
+
export function nstartsWithsOperator(ctx, value, castType) {
|
|
464
|
+
if (castType) {
|
|
465
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
466
|
+
return sql `${leftSQL} NOT LIKE ${escapeSqlValue(value) + '%'}`;
|
|
467
|
+
}
|
|
468
|
+
return notLike(ctx.column, `${value}%`);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Operator: Not Ends With (case-insensitive)
|
|
472
|
+
*/
|
|
473
|
+
export function nendsWithOperator(ctx, value, castType) {
|
|
474
|
+
if (castType) {
|
|
475
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
476
|
+
return sql `${leftSQL} NOT ILIKE ${'%' + escapeSqlValue(value)}`;
|
|
477
|
+
}
|
|
478
|
+
return notIlike(ctx.column, `%${value}`);
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Operator: Not Ends With Case-Sensitive
|
|
482
|
+
*/
|
|
483
|
+
export function nendsWithsOperator(ctx, value, castType) {
|
|
484
|
+
if (castType) {
|
|
485
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
486
|
+
return sql `${leftSQL} NOT LIKE ${'%' + escapeSqlValue(value)}`;
|
|
487
|
+
}
|
|
488
|
+
return notLike(ctx.column, `%${value}`);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Operator: IN (value in array)
|
|
492
|
+
* Example: { status: { in: ['active', 'pending'] } }
|
|
493
|
+
*/
|
|
494
|
+
export function inOperator(ctx, value, castType) {
|
|
495
|
+
// Handle null/undefined/non-array values - return a condition that's always false
|
|
496
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
497
|
+
return sql `1 = 0`;
|
|
498
|
+
}
|
|
499
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
500
|
+
if (castType || ctx.tableName) {
|
|
501
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
502
|
+
// Use parameterized values instead of manual escaping
|
|
503
|
+
return sql `${leftSQL} IN (${sql.join(value.map(v => sql `${v}`), sql `, `)})`;
|
|
504
|
+
}
|
|
505
|
+
return inArray(ctx.column, value);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Operator: NOT IN (value not in array)
|
|
509
|
+
* Example: { status: { notIn: ['deleted', 'archived'] } }
|
|
510
|
+
*/
|
|
511
|
+
export function notInOperator(ctx, value, castType) {
|
|
512
|
+
// Handle null/undefined/non-array values - return a condition that's always true
|
|
513
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
514
|
+
return sql `1 = 1`;
|
|
515
|
+
}
|
|
516
|
+
// Use buildColumnSQL if we have a tableName (alias) or castType to ensure proper aliasing
|
|
517
|
+
if (castType || ctx.tableName) {
|
|
518
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
519
|
+
// Use parameterized values instead of manual escaping
|
|
520
|
+
return sql `${leftSQL} NOT IN (${sql.join(value.map(v => sql `${v}`), sql `, `)})`;
|
|
521
|
+
}
|
|
522
|
+
return notInArray(ctx.column, value);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Operator: BETWEEN (value in range)
|
|
526
|
+
* Example: { age: { between: [18, 65] } } -> age BETWEEN 18 AND 65
|
|
527
|
+
*/
|
|
528
|
+
export function betweenOperator(ctx, value, castType) {
|
|
529
|
+
if (!Array.isArray(value) || value.length !== 2) {
|
|
530
|
+
throw new Error('BETWEEN operator requires array of exactly 2 values');
|
|
531
|
+
}
|
|
532
|
+
if (castType || ctx.tableName) {
|
|
533
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
534
|
+
return sql `${leftSQL} BETWEEN ${value[0]} AND ${value[1]}`;
|
|
535
|
+
}
|
|
536
|
+
return between(ctx.column, value[0], value[1]);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Operator: NOT BETWEEN (value not in range)
|
|
540
|
+
*/
|
|
541
|
+
export function notBetweenOperator(ctx, value, castType) {
|
|
542
|
+
if (!Array.isArray(value) || value.length !== 2) {
|
|
543
|
+
throw new Error('NOT BETWEEN operator requires array of exactly 2 values');
|
|
544
|
+
}
|
|
545
|
+
if (castType || ctx.tableName) {
|
|
546
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
547
|
+
return sql `${leftSQL} NOT BETWEEN ${value[0]} AND ${value[1]}`;
|
|
548
|
+
}
|
|
549
|
+
return notBetween(ctx.column, value[0], value[1]);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Operator: IS NULL
|
|
553
|
+
* Example: { deletedAt: { isNull: true } } -> deletedAt IS NULL
|
|
554
|
+
*/
|
|
555
|
+
export function isNullOperator(ctx, value, castType) {
|
|
556
|
+
if (castType || ctx.tableName) {
|
|
557
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
558
|
+
const checkValue = value === true || value === 'true';
|
|
559
|
+
// Use sql keywords instead of sql.raw for NULL
|
|
560
|
+
return checkValue ? sql `${leftSQL} IS NULL` : sql `${leftSQL} IS NOT NULL`;
|
|
561
|
+
}
|
|
562
|
+
const checkValue = value === true || (typeof value === 'string' && value === 'true');
|
|
563
|
+
return checkValue ? isNull(ctx.column) : isNotNull(ctx.column);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Operator: IS NOT NULL
|
|
567
|
+
* Example: { deletedAt: { isNotNull: true } } -> deletedAt IS NOT NULL
|
|
568
|
+
*/
|
|
569
|
+
export function isNotNullOperator(ctx, value, castType) {
|
|
570
|
+
if (castType || ctx.tableName) {
|
|
571
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
572
|
+
const checkValue = value === true || (typeof value === 'string' && value === 'true');
|
|
573
|
+
// Use sql keywords instead of sql.raw for NULL
|
|
574
|
+
return checkValue ? sql `${leftSQL} IS NOT NULL` : sql `${leftSQL} IS NULL`;
|
|
575
|
+
}
|
|
576
|
+
const checkValue = value === true || (typeof value === 'string' && value === 'true');
|
|
577
|
+
return checkValue ? isNotNull(ctx.column) : isNull(ctx.column);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Operator: Array Contains (@>)
|
|
581
|
+
* Example: { tags: { arraycontains: ['javascript', 'nodejs'] } }
|
|
582
|
+
* PostgreSQL: tags @> ARRAY['javascript', 'nodejs']
|
|
583
|
+
*/
|
|
584
|
+
export function arrayContainsOperator(ctx, value, elementType = 'text') {
|
|
585
|
+
const preparedValues = Array.isArray(value) ? value : [value];
|
|
586
|
+
const formattedArray = formatArrayForPostgreSQL(preparedValues, elementType);
|
|
587
|
+
// Use buildColumnSQL for proper relation path handling (same pattern as other operators)
|
|
588
|
+
if (ctx.tableName) {
|
|
589
|
+
// For relational paths or when we have a table alias
|
|
590
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
591
|
+
// For string types, cast to text[]
|
|
592
|
+
if (['string', 'text', 'varchar'].includes(elementType)) {
|
|
593
|
+
return sql.raw(`${columnSQL}::text[] @> ${formattedArray}`);
|
|
594
|
+
}
|
|
595
|
+
return sql.raw(`${columnSQL} @> ${formattedArray}`);
|
|
596
|
+
}
|
|
597
|
+
// Direct field without relation
|
|
598
|
+
const formattedArrayDirect = formatArrayForPostgreSQL(value, elementType);
|
|
599
|
+
// For string types, cast to text[]
|
|
600
|
+
if (['string', 'text', 'varchar'].includes(elementType)) {
|
|
601
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
602
|
+
return sql.raw(`${columnSQL}::text[] @> ${formattedArrayDirect}`);
|
|
603
|
+
}
|
|
604
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
605
|
+
return sql.raw(`${columnSQL} @> ${formattedArrayDirect}`);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Operator: Array Contained By (<@)
|
|
609
|
+
* Example: { tags: { arraycontained: ['javascript', 'nodejs', 'typescript'] } }
|
|
610
|
+
* PostgreSQL: tags <@ ARRAY['javascript', 'nodejs', 'typescript']
|
|
611
|
+
*/
|
|
612
|
+
export function arrayContainedOperator(ctx, value, elementType = 'text') {
|
|
613
|
+
const preparedValues = Array.isArray(value) ? value : [value];
|
|
614
|
+
const formattedArray = formatArrayForPostgreSQL(preparedValues, elementType);
|
|
615
|
+
// Use buildColumnSQL for proper relation path handling (same pattern as other operators)
|
|
616
|
+
if (ctx.tableName) {
|
|
617
|
+
// For relational paths or when we have a table alias
|
|
618
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
619
|
+
// For string types, cast to text[]
|
|
620
|
+
if (['string', 'text', 'varchar'].includes(elementType)) {
|
|
621
|
+
return sql.raw(`${columnSQL}::text[] <@ ${formattedArray}`);
|
|
622
|
+
}
|
|
623
|
+
return sql.raw(`${columnSQL} <@ ${formattedArray}`);
|
|
624
|
+
}
|
|
625
|
+
// Direct field without relation
|
|
626
|
+
const formattedArrayDirect = formatArrayForPostgreSQL(value, elementType);
|
|
627
|
+
// For string types, cast to text[]
|
|
628
|
+
if (['string', 'text', 'varchar'].includes(elementType)) {
|
|
629
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
630
|
+
return sql.raw(`${columnSQL}::text[] <@ ${formattedArrayDirect}`);
|
|
631
|
+
}
|
|
632
|
+
const columnSQL = buildColumnSQLString(ctx.fieldName);
|
|
633
|
+
return sql.raw(`${columnSQL} <@ ${formattedArrayDirect}`);
|
|
634
|
+
}
|
|
635
|
+
// ============================================================================
|
|
636
|
+
// JSONB OPERATORS
|
|
637
|
+
// PostgreSQL provides powerful JSONB operators for querying JSON data.
|
|
638
|
+
// These operators allow filtering based on JSON structure and contents.
|
|
639
|
+
// ============================================================================
|
|
640
|
+
/**
|
|
641
|
+
* Helper to build field reference for JSONB operations
|
|
642
|
+
*/
|
|
643
|
+
function buildFieldRef(fieldName) {
|
|
644
|
+
if (fieldName.startsWith('"')) {
|
|
645
|
+
return fieldName;
|
|
646
|
+
}
|
|
647
|
+
else if (fieldName.includes('.')) {
|
|
648
|
+
const [table, col] = fieldName.split('.');
|
|
649
|
+
return `"${table}"."${col}"`;
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
return `"${fieldName}"`;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Safely escape and stringify JSON value for SQL
|
|
657
|
+
*/
|
|
658
|
+
function jsonToSqlString(value) {
|
|
659
|
+
return JSON.stringify(value).replace(/'/g, "''");
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Operator: JSONB Contains (@>)
|
|
663
|
+
* Checks if the JSONB column contains the specified JSON value
|
|
664
|
+
* Example: { metadata: { jsonbContains: { status: "active" } } }
|
|
665
|
+
* PostgreSQL: metadata @> '{"status": "active"}'::jsonb
|
|
666
|
+
*
|
|
667
|
+
* This operator tests whether the left JSONB value contains the right JSONB value.
|
|
668
|
+
* A JSONB value contains another if it has all the keys and matching values.
|
|
669
|
+
*/
|
|
670
|
+
export function jsonbContainsOperator(ctx, value) {
|
|
671
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
672
|
+
const jsonValue = jsonToSqlString(value);
|
|
673
|
+
return sql.raw(`${fieldRef} @> '${jsonValue}'::jsonb`);
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Operator: JSONB Contained By (<@)
|
|
677
|
+
* Checks if the JSONB column is contained by the specified JSON value
|
|
678
|
+
* Example: { metadata: { jsonbContainedBy: { status: "active", type: "user", role: "admin" } } }
|
|
679
|
+
* PostgreSQL: metadata <@ '{"status": "active", "type": "user", "role": "admin"}'::jsonb
|
|
680
|
+
*
|
|
681
|
+
* This operator tests whether the left JSONB value is contained by the right JSONB value.
|
|
682
|
+
*/
|
|
683
|
+
export function jsonbContainedByOperator(ctx, value) {
|
|
684
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
685
|
+
const jsonValue = jsonToSqlString(value);
|
|
686
|
+
return sql.raw(`${fieldRef} <@ '${jsonValue}'::jsonb`);
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Operator: JSONB Has Key (?)
|
|
690
|
+
* Checks if the JSONB column has a specific top-level key
|
|
691
|
+
* Example: { metadata: { jsonbHasKey: "status" } }
|
|
692
|
+
* PostgreSQL: metadata ? 'status'
|
|
693
|
+
*/
|
|
694
|
+
export function jsonbHasKeyOperator(ctx, value) {
|
|
695
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
696
|
+
const escapedKey = String(value).replace(/'/g, "''");
|
|
697
|
+
return sql.raw(`${fieldRef} ? '${escapedKey}'`);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Operator: JSONB Has Any Keys (?|)
|
|
701
|
+
* Checks if the JSONB column has any of the specified keys
|
|
702
|
+
* Example: { metadata: { jsonbHasAnyKeys: ["status", "type", "role"] } }
|
|
703
|
+
* PostgreSQL: metadata ?| array['status', 'type', 'role']
|
|
704
|
+
*/
|
|
705
|
+
export function jsonbHasAnyKeysOperator(ctx, value) {
|
|
706
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
707
|
+
const keys = Array.isArray(value) ? value : value != null ? [value] : [];
|
|
708
|
+
if (keys.length === 0) {
|
|
709
|
+
return sql `1 = 0`;
|
|
710
|
+
}
|
|
711
|
+
const escapedKeys = keys.map(k => `'${String(k).replace(/'/g, "''")}'`).join(', ');
|
|
712
|
+
return sql.raw(`${fieldRef} ?| array[${escapedKeys}]`);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Operator: JSONB Has All Keys (?&)
|
|
716
|
+
* Checks if the JSONB column has all of the specified keys
|
|
717
|
+
* Example: { metadata: { jsonbHasAllKeys: ["status", "type"] } }
|
|
718
|
+
* PostgreSQL: metadata ?& array['status', 'type']
|
|
719
|
+
*/
|
|
720
|
+
export function jsonbHasAllKeysOperator(ctx, value) {
|
|
721
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
722
|
+
const keys = Array.isArray(value) ? value : value != null ? [value] : [];
|
|
723
|
+
if (keys.length === 0) {
|
|
724
|
+
return sql `1 = 1`;
|
|
725
|
+
}
|
|
726
|
+
const escapedKeys = keys.map(k => `'${String(k).replace(/'/g, "''")}'`).join(', ');
|
|
727
|
+
return sql.raw(`${fieldRef} ?& array[${escapedKeys}]`);
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Operator: JSONB Path Exists (using @?)
|
|
731
|
+
* Checks if a JSON path exists and returns any items
|
|
732
|
+
* Example: { metadata: { jsonbPathExists: "$.user.preferences" } }
|
|
733
|
+
* PostgreSQL: metadata @? '$.user.preferences'
|
|
734
|
+
*
|
|
735
|
+
* This uses the JSON path language to query JSONB data.
|
|
736
|
+
* The path can include filters like: $.items[*] ? (@.price > 10)
|
|
737
|
+
*/
|
|
738
|
+
export function jsonbPathExistsOperator(ctx, value) {
|
|
739
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
740
|
+
const escapedPath = String(value).replace(/'/g, "''");
|
|
741
|
+
return sql.raw(`${fieldRef} @? '${escapedPath}'`);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Operator: JSONB Path Match (using @@)
|
|
745
|
+
* Checks if a JSON path predicate returns true
|
|
746
|
+
* Example: { metadata: { jsonbPathMatch: "$.price > 10" } }
|
|
747
|
+
* PostgreSQL: metadata @@ '$.price > 10'
|
|
748
|
+
*
|
|
749
|
+
* The path predicate must return a boolean value.
|
|
750
|
+
*/
|
|
751
|
+
export function jsonbPathMatchOperator(ctx, value) {
|
|
752
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
753
|
+
const escapedPath = String(value).replace(/'/g, "''");
|
|
754
|
+
return sql.raw(`${fieldRef} @@ '${escapedPath}'`);
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Operator: JSONB Not Contains (NOT @>)
|
|
758
|
+
* Checks if the JSONB column does NOT contain the specified JSON value
|
|
759
|
+
* Example: { metadata: { jsonbNotContains: { status: "deleted" } } }
|
|
760
|
+
* PostgreSQL: NOT (metadata @> '{"status": "deleted"}'::jsonb)
|
|
761
|
+
*/
|
|
762
|
+
export function jsonbNotContainsOperator(ctx, value) {
|
|
763
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
764
|
+
const jsonValue = jsonToSqlString(value);
|
|
765
|
+
return sql.raw(`NOT (${fieldRef} @> '${jsonValue}'::jsonb)`);
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Operator: JSONB Key Equals (->>, then compare)
|
|
769
|
+
* Access a top-level key and compare its text value
|
|
770
|
+
* Example: { metadata: { jsonbKeyEquals: { key: "status", value: "active" } } }
|
|
771
|
+
* PostgreSQL: metadata->>'status' = 'active'
|
|
772
|
+
*
|
|
773
|
+
* This is useful when you want to compare a specific key's value directly.
|
|
774
|
+
*/
|
|
775
|
+
export function jsonbKeyEqualsOperator(ctx, value) {
|
|
776
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
777
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
778
|
+
if (value.value === null) {
|
|
779
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' IS NULL`);
|
|
780
|
+
}
|
|
781
|
+
if (typeof value.value === 'number') {
|
|
782
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric = ${value.value}`);
|
|
783
|
+
}
|
|
784
|
+
if (typeof value.value === 'boolean') {
|
|
785
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::boolean = ${value.value}`);
|
|
786
|
+
}
|
|
787
|
+
const escapedValue = String(value.value).replace(/'/g, "''");
|
|
788
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' = '${escapedValue}'`);
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Operator: JSONB Key Not Equals (->>, then compare)
|
|
792
|
+
* Access a top-level key and compare its text value is NOT equal
|
|
793
|
+
* Example: { metadata: { jsonbKeyNotEquals: { key: "status", value: "deleted" } } }
|
|
794
|
+
* PostgreSQL: metadata->>'status' != 'deleted' OR metadata->>'status' IS NULL
|
|
795
|
+
*/
|
|
796
|
+
export function jsonbKeyNotEqualsOperator(ctx, value) {
|
|
797
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
798
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
799
|
+
if (value.value === null) {
|
|
800
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' IS NOT NULL`);
|
|
801
|
+
}
|
|
802
|
+
if (typeof value.value === 'number') {
|
|
803
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric != ${value.value} OR ${fieldRef}->>'${escapedKey}' IS NULL`);
|
|
804
|
+
}
|
|
805
|
+
if (typeof value.value === 'boolean') {
|
|
806
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::boolean != ${value.value} OR ${fieldRef}->>'${escapedKey}' IS NULL`);
|
|
807
|
+
}
|
|
808
|
+
const escapedValue = String(value.value).replace(/'/g, "''");
|
|
809
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' != '${escapedValue}' OR ${fieldRef}->>'${escapedKey}' IS NULL`);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Operator: JSONB Key Greater Than
|
|
813
|
+
* Access a top-level key and compare if value is greater than
|
|
814
|
+
* Example: { metadata: { jsonbKeyGt: { key: "price", value: 100 } } }
|
|
815
|
+
* PostgreSQL: (metadata->>'price')::numeric > 100
|
|
816
|
+
*/
|
|
817
|
+
export function jsonbKeyGtOperator(ctx, value) {
|
|
818
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
819
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
820
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric > ${value.value}`);
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Operator: JSONB Key Greater Than or Equal
|
|
824
|
+
* Example: { metadata: { jsonbKeyGte: { key: "price", value: 100 } } }
|
|
825
|
+
*/
|
|
826
|
+
export function jsonbKeyGteOperator(ctx, value) {
|
|
827
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
828
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
829
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric >= ${value.value}`);
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Operator: JSONB Key Less Than
|
|
833
|
+
* Example: { metadata: { jsonbKeyLt: { key: "price", value: 100 } } }
|
|
834
|
+
*/
|
|
835
|
+
export function jsonbKeyLtOperator(ctx, value) {
|
|
836
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
837
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
838
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric < ${value.value}`);
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Operator: JSONB Key Less Than or Equal
|
|
842
|
+
* Example: { metadata: { jsonbKeyLte: { key: "price", value: 100 } } }
|
|
843
|
+
*/
|
|
844
|
+
export function jsonbKeyLteOperator(ctx, value) {
|
|
845
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
846
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
847
|
+
return sql.raw(`(${fieldRef}->>'${escapedKey}')::numeric <= ${value.value}`);
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Operator: JSONB Key In (->>, then IN)
|
|
851
|
+
* Access a top-level key and check if value is in a list
|
|
852
|
+
* Example: { metadata: { jsonbKeyIn: { key: "status", values: ["active", "pending"] } } }
|
|
853
|
+
* PostgreSQL: metadata->>'status' IN ('active', 'pending')
|
|
854
|
+
*/
|
|
855
|
+
export function jsonbKeyInOperator(ctx, value) {
|
|
856
|
+
if (!value || value.key == null) {
|
|
857
|
+
return sql `1 = 0`;
|
|
858
|
+
}
|
|
859
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
860
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
861
|
+
const values = Array.isArray(value.values) ? value.values : value.values != null ? [value.values] : [];
|
|
862
|
+
if (values.length === 0) {
|
|
863
|
+
return sql `1 = 0`;
|
|
864
|
+
}
|
|
865
|
+
const escapedValues = values.map(v => `'${String(v).replace(/'/g, "''")}'`).join(', ');
|
|
866
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' IN (${escapedValues})`);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Operator: JSONB Key Not In
|
|
870
|
+
* Example: { metadata: { jsonbKeyNotIn: { key: "status", values: ["deleted", "archived"] } } }
|
|
871
|
+
*/
|
|
872
|
+
export function jsonbKeyNotInOperator(ctx, value) {
|
|
873
|
+
if (!value || value.key == null) {
|
|
874
|
+
return sql `1 = 1`;
|
|
875
|
+
}
|
|
876
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
877
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
878
|
+
const values = Array.isArray(value.values) ? value.values : value.values != null ? [value.values] : [];
|
|
879
|
+
if (values.length === 0) {
|
|
880
|
+
return sql `1 = 1`;
|
|
881
|
+
}
|
|
882
|
+
const escapedValues = values.map(v => `'${String(v).replace(/'/g, "''")}'`).join(', ');
|
|
883
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' NOT IN (${escapedValues})`);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Operator: JSONB Key Like (->>, then ILIKE)
|
|
887
|
+
* Access a top-level key and perform pattern matching
|
|
888
|
+
* Example: { metadata: { jsonbKeyLike: { key: "name", pattern: "%john%" } } }
|
|
889
|
+
* PostgreSQL: metadata->>'name' ILIKE '%john%'
|
|
890
|
+
*/
|
|
891
|
+
export function jsonbKeyLikeOperator(ctx, value) {
|
|
892
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
893
|
+
const escapedKey = String(value.key).replace(/'/g, "''");
|
|
894
|
+
const escapedPattern = String(value.pattern).replace(/'/g, "''");
|
|
895
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' ILIKE '${escapedPattern}'`);
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Operator: JSONB Key Is Null
|
|
899
|
+
* Check if a specific key's value is null (not if the key is missing)
|
|
900
|
+
* Example: { metadata: { jsonbKeyIsNull: "deletedAt" } }
|
|
901
|
+
* PostgreSQL: metadata->>'deletedAt' IS NULL
|
|
902
|
+
*/
|
|
903
|
+
export function jsonbKeyIsNullOperator(ctx, value) {
|
|
904
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
905
|
+
const escapedKey = String(value).replace(/'/g, "''");
|
|
906
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' IS NULL`);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Operator: JSONB Key Is Not Null
|
|
910
|
+
* Check if a specific key's value is not null
|
|
911
|
+
* Example: { metadata: { jsonbKeyIsNotNull: "createdAt" } }
|
|
912
|
+
* PostgreSQL: metadata->>'createdAt' IS NOT NULL
|
|
913
|
+
*/
|
|
914
|
+
export function jsonbKeyIsNotNullOperator(ctx, value) {
|
|
915
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
916
|
+
const escapedKey = String(value).replace(/'/g, "''");
|
|
917
|
+
return sql.raw(`${fieldRef}->>'${escapedKey}' IS NOT NULL`);
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Operator: JSONB Array Length
|
|
921
|
+
* Check the length of a JSONB array at a specific path
|
|
922
|
+
* Example: { metadata: { jsonbArrayLength: { path: "items", op: "gte", value: 5 } } }
|
|
923
|
+
* PostgreSQL: jsonb_array_length(metadata->'items') >= 5
|
|
924
|
+
*/
|
|
925
|
+
export function jsonbArrayLengthOperator(ctx, value) {
|
|
926
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
927
|
+
const operators = {
|
|
928
|
+
eq: '=',
|
|
929
|
+
ne: '!=',
|
|
930
|
+
gt: '>',
|
|
931
|
+
gte: '>=',
|
|
932
|
+
lt: '<',
|
|
933
|
+
lte: '<='
|
|
934
|
+
};
|
|
935
|
+
const sqlOp = operators[value.op] || '=';
|
|
936
|
+
if (value.path) {
|
|
937
|
+
const escapedPath = String(value.path).replace(/'/g, "''");
|
|
938
|
+
return sql.raw(`jsonb_array_length(${fieldRef}->'${escapedPath}') ${sqlOp} ${value.value}`);
|
|
939
|
+
}
|
|
940
|
+
// If no path, assume the column itself is the array
|
|
941
|
+
return sql.raw(`jsonb_array_length(${fieldRef}) ${sqlOp} ${value.value}`);
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Operator: JSONB Type Of
|
|
945
|
+
* Check the type of a JSONB value or a key's value
|
|
946
|
+
* Example: { metadata: { jsonbTypeOf: { path: "price", type: "number" } } }
|
|
947
|
+
* PostgreSQL: jsonb_typeof(metadata->'price') = 'number'
|
|
948
|
+
*
|
|
949
|
+
* Valid types: 'object', 'array', 'string', 'number', 'boolean', 'null'
|
|
950
|
+
*/
|
|
951
|
+
export function jsonbTypeOfOperator(ctx, value) {
|
|
952
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
953
|
+
const escapedType = String(value.type).replace(/'/g, "''");
|
|
954
|
+
if (value.path) {
|
|
955
|
+
const escapedPath = String(value.path).replace(/'/g, "''");
|
|
956
|
+
return sql.raw(`jsonb_typeof(${fieldRef}->'${escapedPath}') = '${escapedType}'`);
|
|
957
|
+
}
|
|
958
|
+
return sql.raw(`jsonb_typeof(${fieldRef}) = '${escapedType}'`);
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Operator: JSONB Deep Value (using #>> for nested path)
|
|
962
|
+
* Access a deeply nested value and compare
|
|
963
|
+
* Example: { metadata: { jsonbDeepValue: { path: ["user", "preferences", "theme"], value: "dark" } } }
|
|
964
|
+
* PostgreSQL: metadata #>> '{user,preferences,theme}' = 'dark'
|
|
965
|
+
*
|
|
966
|
+
* The path array represents the keys to traverse.
|
|
967
|
+
*/
|
|
968
|
+
export function jsonbDeepValueOperator(ctx, value) {
|
|
969
|
+
if (!value || value.path == null) {
|
|
970
|
+
return sql `1 = 0`;
|
|
971
|
+
}
|
|
972
|
+
const fieldRef = buildFieldRef(ctx.fieldName);
|
|
973
|
+
const pathArray = Array.isArray(value.path) ? value.path : value.path != null ? [value.path] : [];
|
|
974
|
+
if (pathArray.length === 0) {
|
|
975
|
+
return sql `1 = 0`;
|
|
976
|
+
}
|
|
977
|
+
const escapedPath = pathArray.map(p => String(p).replace(/"/g, '\\"')).join(',');
|
|
978
|
+
const op = value.op || 'eq';
|
|
979
|
+
const operators = {
|
|
980
|
+
eq: '=',
|
|
981
|
+
ne: '!=',
|
|
982
|
+
gt: '>',
|
|
983
|
+
gte: '>=',
|
|
984
|
+
lt: '<',
|
|
985
|
+
lte: '<=',
|
|
986
|
+
like: 'LIKE',
|
|
987
|
+
ilike: 'ILIKE'
|
|
988
|
+
};
|
|
989
|
+
const sqlOp = operators[op] || '=';
|
|
990
|
+
if (value.value === null) {
|
|
991
|
+
return op === 'ne'
|
|
992
|
+
? sql.raw(`${fieldRef} #>> '{${escapedPath}}' IS NOT NULL`)
|
|
993
|
+
: sql.raw(`${fieldRef} #>> '{${escapedPath}}' IS NULL`);
|
|
994
|
+
}
|
|
995
|
+
if (typeof value.value === 'number' && !['like', 'ilike'].includes(op)) {
|
|
996
|
+
return sql.raw(`(${fieldRef} #>> '{${escapedPath}}')::numeric ${sqlOp} ${value.value}`);
|
|
997
|
+
}
|
|
998
|
+
const escapedValue = String(value.value).replace(/'/g, "''");
|
|
999
|
+
return sql.raw(`${fieldRef} #>> '{${escapedPath}}' ${sqlOp} '${escapedValue}'`);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Operator: ST_Within (geometry within)
|
|
1003
|
+
* Example: { location: { within: geoJSON } }
|
|
1004
|
+
*/
|
|
1005
|
+
export function withinOperator(ctx, value) {
|
|
1006
|
+
// Build properly quoted column reference
|
|
1007
|
+
let fieldRef;
|
|
1008
|
+
if (ctx.fieldName.startsWith('"')) {
|
|
1009
|
+
// Already quoted
|
|
1010
|
+
fieldRef = ctx.fieldName;
|
|
1011
|
+
}
|
|
1012
|
+
else if (ctx.fieldName.includes('.')) {
|
|
1013
|
+
const [table, col] = ctx.fieldName.split('.');
|
|
1014
|
+
fieldRef = `"${table}"."${col}"`;
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
fieldRef = `"${ctx.fieldName}"`;
|
|
1018
|
+
}
|
|
1019
|
+
return sql.raw(`ST_Within(${fieldRef}, ST_GeomFromGeoJSON('${JSON.stringify(value)}'))`);
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Operator: ST_Contains (geometry contains)
|
|
1023
|
+
* Example: { boundary: { containsGEO: geoJSON } }
|
|
1024
|
+
*/
|
|
1025
|
+
export function containsGEOOperator(ctx, value) {
|
|
1026
|
+
// Build properly quoted column reference
|
|
1027
|
+
let fieldRef;
|
|
1028
|
+
if (ctx.fieldName.startsWith('"')) {
|
|
1029
|
+
// Already quoted
|
|
1030
|
+
fieldRef = ctx.fieldName;
|
|
1031
|
+
}
|
|
1032
|
+
else if (ctx.fieldName.includes('.')) {
|
|
1033
|
+
const [table, col] = ctx.fieldName.split('.');
|
|
1034
|
+
fieldRef = `"${table}"."${col}"`;
|
|
1035
|
+
}
|
|
1036
|
+
else {
|
|
1037
|
+
fieldRef = `"${ctx.fieldName}"`;
|
|
1038
|
+
}
|
|
1039
|
+
return sql.raw(`ST_Contains(${fieldRef}, ST_GeomFromGeoJSON('${JSON.stringify(value)}'))`);
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Operator: ST_Intersects (geometries intersect)
|
|
1043
|
+
* Example: { area: { intersects: geoJSON } }
|
|
1044
|
+
*/
|
|
1045
|
+
export function intersectsOperator(ctx, value) {
|
|
1046
|
+
// Build properly quoted column reference
|
|
1047
|
+
let fieldRef;
|
|
1048
|
+
if (ctx.fieldName.startsWith('"')) {
|
|
1049
|
+
// Already quoted
|
|
1050
|
+
fieldRef = ctx.fieldName;
|
|
1051
|
+
}
|
|
1052
|
+
else if (ctx.fieldName.includes('.')) {
|
|
1053
|
+
const [table, col] = ctx.fieldName.split('.');
|
|
1054
|
+
fieldRef = `"${table}"."${col}"`;
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
fieldRef = `"${ctx.fieldName}"`;
|
|
1058
|
+
}
|
|
1059
|
+
// Cast column to geometry to resolve function overload ambiguity
|
|
1060
|
+
return sql.raw(`ST_Intersects(${fieldRef}::geometry, ST_GeomFromGeoJSON('${JSON.stringify(value)}'))`);
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Operator: NOT ST_Intersects
|
|
1064
|
+
*/
|
|
1065
|
+
export function nIntersectsOperator(ctx, value) {
|
|
1066
|
+
// Build properly quoted column reference
|
|
1067
|
+
let fieldRef;
|
|
1068
|
+
if (ctx.fieldName.startsWith('"')) {
|
|
1069
|
+
// Already quoted
|
|
1070
|
+
fieldRef = ctx.fieldName;
|
|
1071
|
+
}
|
|
1072
|
+
else if (ctx.fieldName.includes('.')) {
|
|
1073
|
+
const [table, col] = ctx.fieldName.split('.');
|
|
1074
|
+
fieldRef = `"${table}"."${col}"`;
|
|
1075
|
+
}
|
|
1076
|
+
else {
|
|
1077
|
+
fieldRef = `"${ctx.fieldName}"`;
|
|
1078
|
+
}
|
|
1079
|
+
return sql.raw(`NOT ST_Intersects(${fieldRef}, ST_GeomFromGeoJSON('${JSON.stringify(value)}'))`);
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Operator: ST_DWithin (within distance)
|
|
1083
|
+
* Example: { location: { dwithin: { geometry: geoJSON, distance: 1000, not: false } } }
|
|
1084
|
+
* Uses ST_DistanceSpheroid for accurate earth-surface distance calculations in meters
|
|
1085
|
+
*/
|
|
1086
|
+
export function dwithinOperator(ctx, value) {
|
|
1087
|
+
const { geometry, distance, not: negated } = value;
|
|
1088
|
+
// Build properly quoted column reference
|
|
1089
|
+
let fieldRef;
|
|
1090
|
+
if (ctx.fieldName.startsWith('"')) {
|
|
1091
|
+
// Already quoted
|
|
1092
|
+
fieldRef = ctx.fieldName;
|
|
1093
|
+
}
|
|
1094
|
+
else if (ctx.fieldName.includes('.')) {
|
|
1095
|
+
const [table, col] = ctx.fieldName.split('.');
|
|
1096
|
+
fieldRef = `"${table}"."${col}"`;
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
fieldRef = `"${ctx.fieldName}"`;
|
|
1100
|
+
}
|
|
1101
|
+
// Use ST_DistanceSpheroid for accurate distance calculations in meters
|
|
1102
|
+
// This is more reliable than ::geography casting across different PostGIS versions
|
|
1103
|
+
const spheroid = `SPHEROID["WGS 84",6378137,298.257223563]`;
|
|
1104
|
+
const condition = `ST_DistanceSpheroid(${fieldRef}, ST_SetSRID(ST_GeomFromGeoJSON('${JSON.stringify(geometry)}'), 4326), '${spheroid}') <= ${distance}`;
|
|
1105
|
+
return negated ? sql.raw(`NOT (${condition})`) : sql.raw(condition);
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Operator: NOT
|
|
1109
|
+
* Example: { status: { not: 'active' } } -> status != 'active'
|
|
1110
|
+
* Example: { id: { not: null } } -> id IS NOT NULL
|
|
1111
|
+
*/
|
|
1112
|
+
export function notOperator(ctx, value, castType) {
|
|
1113
|
+
// Special handling for null values - must use IS NOT NULL syntax
|
|
1114
|
+
if (value === null) {
|
|
1115
|
+
if (castType || ctx.tableName) {
|
|
1116
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
1117
|
+
return sql `${leftSQL} IS NOT NULL`;
|
|
1118
|
+
}
|
|
1119
|
+
return isNotNull(ctx.column);
|
|
1120
|
+
}
|
|
1121
|
+
if (castType || ctx.tableName) {
|
|
1122
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
1123
|
+
return sql `NOT (${leftSQL} = ${value})`;
|
|
1124
|
+
}
|
|
1125
|
+
return ne(ctx.column, value);
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Operator: IS
|
|
1129
|
+
* Example: { deletedAt: { is: null } } -> deletedAt IS NULL
|
|
1130
|
+
*/
|
|
1131
|
+
export function isOperator(ctx, value, castType) {
|
|
1132
|
+
if (castType || ctx.tableName) {
|
|
1133
|
+
const leftSQL = buildColumnSQL(ctx.fieldName, castType);
|
|
1134
|
+
// Handle NULL specially with IS NULL syntax
|
|
1135
|
+
if (value === null || value === 'null') {
|
|
1136
|
+
return sql `${leftSQL} IS NULL`;
|
|
1137
|
+
}
|
|
1138
|
+
return sql `${leftSQL} IS ${value}`;
|
|
1139
|
+
}
|
|
1140
|
+
if (value === null) {
|
|
1141
|
+
return isNull(ctx.column);
|
|
1142
|
+
}
|
|
1143
|
+
return eq(ctx.column, value);
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Map of operator names to their handler functions
|
|
1147
|
+
*/
|
|
1148
|
+
export const OPERATOR_MAP = {
|
|
1149
|
+
// Comparison
|
|
1150
|
+
eq: eqOperator,
|
|
1151
|
+
ne: neOperator,
|
|
1152
|
+
gt: gtOperator,
|
|
1153
|
+
gte: gteOperator,
|
|
1154
|
+
lt: ltOperator,
|
|
1155
|
+
lte: lteOperator,
|
|
1156
|
+
// String pattern matching
|
|
1157
|
+
like: likeOperator,
|
|
1158
|
+
notLike: notLikeOperator,
|
|
1159
|
+
iLike: iLikeOperator,
|
|
1160
|
+
notILike: notILikeOperator,
|
|
1161
|
+
startsWith: startsWithOperator,
|
|
1162
|
+
startsWiths: startsWithsOperator,
|
|
1163
|
+
endsWith: endsWithOperator,
|
|
1164
|
+
endsWiths: endsWithsOperator,
|
|
1165
|
+
nstartsWith: nstartsWithOperator,
|
|
1166
|
+
nstartsWiths: nstartsWithsOperator,
|
|
1167
|
+
nendsWith: nendsWithOperator,
|
|
1168
|
+
nendsWiths: nendsWithsOperator,
|
|
1169
|
+
// Collection
|
|
1170
|
+
in: inOperator,
|
|
1171
|
+
notIn: notInOperator,
|
|
1172
|
+
not: notOperator,
|
|
1173
|
+
is: isOperator,
|
|
1174
|
+
// Range
|
|
1175
|
+
between: betweenOperator,
|
|
1176
|
+
notBetween: notBetweenOperator,
|
|
1177
|
+
// Null checks
|
|
1178
|
+
isNull: isNullOperator,
|
|
1179
|
+
isNotNull: isNotNullOperator,
|
|
1180
|
+
// Array operators
|
|
1181
|
+
arraycontains: arrayContainsOperator,
|
|
1182
|
+
arraycontained: arrayContainedOperator,
|
|
1183
|
+
// JSONB operators
|
|
1184
|
+
jsonbContains: jsonbContainsOperator,
|
|
1185
|
+
jsonbContainedBy: jsonbContainedByOperator,
|
|
1186
|
+
jsonbHasKey: jsonbHasKeyOperator,
|
|
1187
|
+
jsonbHasAnyKeys: jsonbHasAnyKeysOperator,
|
|
1188
|
+
jsonbHasAllKeys: jsonbHasAllKeysOperator,
|
|
1189
|
+
jsonbPathExists: jsonbPathExistsOperator,
|
|
1190
|
+
jsonbPathMatch: jsonbPathMatchOperator,
|
|
1191
|
+
jsonbNotContains: jsonbNotContainsOperator,
|
|
1192
|
+
jsonbKeyEquals: jsonbKeyEqualsOperator,
|
|
1193
|
+
jsonbKeyNotEquals: jsonbKeyNotEqualsOperator,
|
|
1194
|
+
jsonbKeyGt: jsonbKeyGtOperator,
|
|
1195
|
+
jsonbKeyGte: jsonbKeyGteOperator,
|
|
1196
|
+
jsonbKeyLt: jsonbKeyLtOperator,
|
|
1197
|
+
jsonbKeyLte: jsonbKeyLteOperator,
|
|
1198
|
+
jsonbKeyIn: jsonbKeyInOperator,
|
|
1199
|
+
jsonbKeyNotIn: jsonbKeyNotInOperator,
|
|
1200
|
+
jsonbKeyLike: jsonbKeyLikeOperator,
|
|
1201
|
+
jsonbKeyIsNull: jsonbKeyIsNullOperator,
|
|
1202
|
+
jsonbKeyIsNotNull: jsonbKeyIsNotNullOperator,
|
|
1203
|
+
jsonbArrayLength: jsonbArrayLengthOperator,
|
|
1204
|
+
jsonbTypeOf: jsonbTypeOfOperator,
|
|
1205
|
+
jsonbDeepValue: jsonbDeepValueOperator,
|
|
1206
|
+
// Geo operators
|
|
1207
|
+
within: withinOperator,
|
|
1208
|
+
containsGEO: containsGEOOperator,
|
|
1209
|
+
intersects: intersectsOperator,
|
|
1210
|
+
nIntersects: nIntersectsOperator,
|
|
1211
|
+
dwithin: dwithinOperator,
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* Apply an operator to a column with a value
|
|
1215
|
+
*/
|
|
1216
|
+
export function applyOperator(operatorName, ctx, value, castType, elementType) {
|
|
1217
|
+
const operator = OPERATOR_MAP[operatorName];
|
|
1218
|
+
if (!operator) {
|
|
1219
|
+
console.warn(`Unknown operator: ${operatorName}`);
|
|
1220
|
+
return null;
|
|
1221
|
+
}
|
|
1222
|
+
// Special handling for array operators
|
|
1223
|
+
if (operatorName === 'arraycontains' || operatorName === 'arraycontained') {
|
|
1224
|
+
return operator(ctx, value, elementType);
|
|
1225
|
+
}
|
|
1226
|
+
// @ts-ignore - Type complexity with operator overloads
|
|
1227
|
+
return operator(ctx, value, castType);
|
|
1228
|
+
}
|
|
1229
|
+
//# sourceMappingURL=filterOperators.js.map
|