From aeebec4833b3f2b97eb90ef716f2cdd71cd6e289 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 3 Feb 2025 14:47:51 -0700 Subject: [PATCH] feat: BoxLang compatibility This release adds compatibility with BoxLang. It is being marked as a breaking change out of an abundance of caution, even though no breaking changes were added. BREAKING CHANGE: Added BoxLang compatibility --- .github/workflows/cron.yml | 11 ++++-- .github/workflows/pr.yml | 11 ++++-- .github/workflows/prerelease.yml | 11 ++++-- .github/workflows/release.yml | 22 +++++------- box.json | 7 ++-- models/BaseEntity.cfc | 4 ++- models/QuickBuilder.cfc | 4 +++ models/QuickQB.cfc | 23 +++++++++--- server.json | 5 ++- tests/index.cfm | 2 +- tests/resources/app/models/Song.cfc | 36 ++++++++++++++----- .../integration/BaseEntity/ChildClassSpec.cfc | 25 ++++++++++--- .../BaseEntity/Events/PostDeleteSpec.cfc | 6 ++-- .../BaseEntity/Events/PostInsertSpec.cfc | 13 ++++--- .../BaseEntity/Events/PostSaveSpec.cfc | 17 +++++---- .../BaseEntity/Events/PostUpdateSpec.cfc | 6 ++-- .../BaseEntity/Events/PreDeleteSpec.cfc | 6 ++-- .../BaseEntity/Events/PreInsertSpec.cfc | 14 +++++--- .../BaseEntity/Events/PreSaveSpec.cfc | 17 +++++---- .../BaseEntity/Events/PreUpdateSpec.cfc | 13 +++++-- .../Relationships/RelationshipLoadingSpec.cfc | 4 +-- .../integration/GoodErrorMessagesSpec.cfc | 20 ++++++----- .../specs/integration/QuickCollectionSpec.cfc | 28 ++++++++------- 23 files changed, 206 insertions(+), 99 deletions(-) diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 8d7c535d..4f44e002 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "lucee@6", "lucee@be", "adobe@2018", "adobe@2021", "adobe@2023", "adobe@be"] + cfengine: ["lucee@5", "lucee@6", "lucee@be", "adobe@2018", "adobe@2023", "adobe@be", "boxlang@be"] coldbox: ["coldbox@6", "coldbox@7", "coldbox@be"] javaVersion: ["openjdk8", "openjdk11"] services: @@ -51,7 +51,14 @@ jobs: DB_USER: quick DB_PASSWORD: quick run: | - box server start cfengine=${{ matrix.cfengine }} javaVersion=${{ matrix.javaVersion }} + if [[ "${{ matrix.cfengine }}" == *"boxlang"* ]] ; then + box server start cfengine=${{ matrix.cfengine }} javaVersion=openjdk21_jdk + box run-script bx-modules:install + box server restart + else + box server start cfengine=${{ matrix.cfengine }} javaVersion=${{ matrix.javaVersion }} + fi + # Install Adobe 2021 cfpm modules if [[ "${{ matrix.cfengine }}" == "adobe@2021" ]] ; then box run-script install:2021 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index af83017b..5ae63307 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "adobe@2018", "adobe@2021", "adobe@2023"] + cfengine: ["lucee@5", "adobe@2018", "adobe@2023", "boxlang@be"] coldbox: ["coldbox@6", "coldbox@7", "coldbox@be"] services: mysql: @@ -58,7 +58,14 @@ jobs: DB_USER: quick DB_PASSWORD: quick run: | - box server start cfengine=${{ matrix.cfengine }} + if [[ "${{ matrix.cfengine }}" == *"boxlang"* ]] ; then + box server start cfengine=${{ matrix.cfengine }} javaVersion=openjdk21_jdk + box run-script bx-modules:install + box server restart + else + box server start cfengine=${{ matrix.cfengine }} + fi + # Install Adobe 2021 cfpm modules if [[ "${{ matrix.cfengine }}" == "adobe@2021" ]] ; then box run-script install:2021 diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index ce983f14..cb464a08 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "adobe@2018", "adobe@2021", "adobe@2023"] + cfengine: ["lucee@5", "adobe@2018", "adobe@2023", "boxlang@be"] coldbox: ["coldbox@6", "coldbox@7", "coldbox@be"] services: mysql: @@ -52,7 +52,14 @@ jobs: DB_USER: quick DB_PASSWORD: quick run: | - box server start cfengine=${{ matrix.cfengine }} + if [[ "${{ matrix.cfengine }}" == *"boxlang"* ]] ; then + box server start cfengine=${{ matrix.cfengine }} javaVersion=openjdk21_jdk + box run-script bx-modules:install + box server restart + else + box server start cfengine=${{ matrix.cfengine }} + fi + # Install Adobe 2021 cfpm modules if [[ "${{ matrix.cfengine }}" == "adobe@2021" ]] ; then box run-script install:2021 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05d475c7..3cff67b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - cfengine: ["lucee@5", "adobe@2018", "adobe@2021", "adobe@2023"] + cfengine: ["lucee@5", "adobe@2018", "adobe@2023", "boxlang@be"] coldbox: ["coldbox@6", "coldbox@7", "coldbox@be"] services: mysql: @@ -53,7 +53,14 @@ jobs: DB_USER: quick DB_PASSWORD: quick run: | - box server start cfengine=${{ matrix.cfengine }} + if [[ "${{ matrix.cfengine }}" == *"boxlang"* ]] ; then + box server start cfengine=${{ matrix.cfengine }} javaVersion=openjdk21_jdk + box run-script bx-modules:install + box server restart + else + box server start cfengine=${{ matrix.cfengine }} + fi + # Install Adobe 2021 cfpm modules if [[ "${{ matrix.cfengine }}" == "adobe@2021" ]] ; then box run-script install:2021 @@ -109,14 +116,3 @@ jobs: - name: Get Current Version id: current_version run: echo "::set-output name=version::`cat box.json | jq '.version' -r`" - - - name: Upload API Docs to S3 - uses: jakejarvis/s3-sync-action@master - with: - args: --acl public-read - env: - AWS_S3_BUCKET: "apidocs.ortussolutions.com" - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} - SOURCE_DIR: ".tmp/apidocs" - DEST_DIR: "${{ github.repository }}/${{ steps.current_version.outputs.version }}" diff --git a/box.json b/box.json index 2a8ac069..6c698f5b 100644 --- a/box.json +++ b/box.json @@ -24,17 +24,18 @@ "format:check":"cfformat check dsl/**/*.cfc,extras/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc --verbose", "format:watch":"cfformat watch dsl/**/*.cfc,extras/**/*.cfc,models/**/*.cfc,tests/specs/**/*.cfc", "generateAPIDocs":"rm .tmp --recurse --force && docbox generate mapping=quick excludes=test|/modules|ModuleConfig|QuickCollection strategy-outputDir=.tmp/apidocs strategy-projectTitle=Quick", - "install:2021":"cfpm install document,feed,mysql,zip" + "install:2021":"cfpm install document,feed,mysql,zip", + "bx-modules:install":"install bx-compat-cfml@be,bx-esapi,bx-mysql" }, "type":"modules", "dependencies":{ - "qb":"^11.0.1", + "qb":"^11.0.2", "str":"^4.0.0", "mementifier":"^3.0.0" }, "devDependencies":{ "coldbox":"v7.3.0", - "testbox":"v6.1.0", + "testbox":"be", "cfcollection":"^3.6.4", "cfmigrations":"^4.0.0" }, diff --git a/models/BaseEntity.cfc b/models/BaseEntity.cfc index 2c2b3bbd..e3ea68af 100644 --- a/models/BaseEntity.cfc +++ b/models/BaseEntity.cfc @@ -3076,7 +3076,9 @@ component accessors="true" { public any function ignoreLoadedGuard( required any callback ) { variables._ignoreNotLoadedGuard = true; try { - return arguments.callback(); + var retval = arguments.callback(); + variables._ignoreNotLoadedGuard = false; + return isNull( retval ) ? javacast( "null", "" ) : retval; } finally { variables._ignoreNotLoadedGuard = false; } diff --git a/models/QuickBuilder.cfc b/models/QuickBuilder.cfc index e0d5b8b1..f1ee892f 100644 --- a/models/QuickBuilder.cfc +++ b/models/QuickBuilder.cfc @@ -1334,6 +1334,10 @@ component accessors="true" transientCache="false" { qb.setColumns( qb.getColumns() .map( function( column ) { + if ( variables.qb.getUtils().isExpression( column ) ) { + return column; + } + if ( !qualifiedColumns.contains( column ) ) { return column; } diff --git a/models/QuickQB.cfc b/models/QuickQB.cfc index 9656120d..bef89b67 100644 --- a/models/QuickQB.cfc +++ b/models/QuickQB.cfc @@ -60,7 +60,7 @@ component combinator = "and", negate = false ) { - if ( structKeyExists( arguments.query, "isQuickBuilder" ) ) { + if ( isStruct( arguments.query ) && structKeyExists( arguments.query, "isQuickBuilder" ) ) { arguments.query = arguments.query.getQB(); } @@ -359,7 +359,12 @@ component combinator = "and", negate = false ) { - if ( structKeyExists( arguments.query, "isQuickBuilder" ) ) { + if ( + !isClosure( arguments.query ) && !isCustomFunction( arguments.query ) && structKeyExists( + arguments.query, + "isQuickBuilder" + ) + ) { arguments.query = arguments.query.getQB(); } @@ -857,7 +862,12 @@ component "value" : ( isNull( arguments.value ) || getEntity().isNullValue( arguments.column, arguments.value ) ) ? "" : arguments.value, "cfsqltype" : getEntity().attributeHasSqlType( arguments.column ) ? getEntity().retrieveSqlTypeForAttribute( arguments.column - ) : ( isNull( arguments.value ) ? "CF_SQL_VARCHAR" : getUtils().inferSqlType( arguments.value, variables.grammar ) ), + ) : ( + isNull( arguments.value ) ? "CF_SQL_VARCHAR" : getUtils().inferSqlType( + arguments.value, + variables.grammar + ) + ), "null" : isNull( arguments.value ) || ( getEntity().canConvertToNull( arguments.column ) && getEntity().isNullValue( arguments.column, @@ -876,7 +886,12 @@ component "value" : isNull( arguments.value ) ? "" : arguments.value, "cfsqltype" : getEntity().attributeHasSqlType( arguments.column ) ? getEntity().retrieveSqlTypeForAttribute( arguments.column - ) : ( isNull( arguments.value ) ? "CF_SQL_VARCHAR" : getUtils().inferSqlType( arguments.value, variables.grammar ) ), + ) : ( + isNull( arguments.value ) ? "CF_SQL_VARCHAR" : getUtils().inferSqlType( + arguments.value, + variables.grammar + ) + ), "null" : isNull( arguments.value ), "nulls" : isNull( arguments.value ) }; diff --git a/server.json b/server.json index d986ee15..d980e6ed 100644 --- a/server.json +++ b/server.json @@ -1,6 +1,9 @@ { "app":{ - "cfengine":"adobe@2018" + "cfengine":"adobe@2021" + }, + "JVM":{ + "javaVersion":"openjdk21" }, "web":{ "http":{ diff --git a/tests/index.cfm b/tests/index.cfm index 03ce2774..7e669ee4 100644 --- a/tests/index.cfm +++ b/tests/index.cfm @@ -49,7 +49,7 @@ TestBox Global Runner - +