On Returning SQL Queries As Arrays In ColdFusion

On Returning SQL Queries As Arrays In ColdFusion

[ad_1]

In my ColdFusion packages, I exploit a tiered structure through which the inner-most layer is the Knowledge Get admission to Layer (DAL). In the entire years that I have been the use of ColdFusion, this DAL has returned database information the use of the ColdFusion-native Question object. The Question object is a big a part of what has, traditionally, made ColdFusion so easy to paintings with. However, as I have endured to adapt my programming practices, I have leaned very closely into the use of Structs and Arrays. As such, I determined that Dig Deep Health – my ColdFusion health tracker – would handiest ever go back Arrays, no longer queries, from the Knowledge Get admission to Layer. After a number of months of operating this fashion, I assumed it may well be great to forestall and replicate at the follow.

In ColdFusion, switching from a Question object over to an Array for a SQL recordset is so simple as including returnType="array" to the CFQuery tag. So, for instance, in my Dig Deep Health ExerciseGateway.cfc element, I’ve a technique titled, getExercisesByFilter(), which returns zero-or-more information in accordance with the equipped filter out standards:

ASIDE: Typically, my records get entry to layer could be coded the use of Tag Islands such that my element may well be authored in CFScript whilst my SQL would get wrapped within the ultimate developer ergonomics of the CFQuery tag. Sadly, tag islands are handiest supported in Lucee CFML and my Dig Deep Health app is being written in Adobe ColdFusion. As such, I’ve determined to make all of my records get entry to parts Tag-based. I might quite use CFQuery tags and consume the cruft of the opposite tag-based constructs than need to care for the queryExecute() string-based nonsense.

<cfcomponent>

	<cffunction title="getExercisesByFilter" returnType="array">

		<cfargument title="identity" sort="numeric" required="false" />
		<cfargument title="userID" sort="numeric" required="false" />

		<cfif (
			isNull( identity ) &&
			isNull( userID )
			)>

			<cfthrow
				sort="SQL.ForbiddenSelect"
				message="Question calls for a minimum of one listed column."
			/>

		</cfif>

		<cfquery title="native.effects" end result="native.metaResults" returnType="array">
			/* DEBUG: lib.type.resistance.ExerciseGateway.getExercisesByFilter(). */
			SELECT
				e.identity,
				e.title,
				e.description,
				e.movementPlaneID,
				e.movementLateralityID,
				e.shoulderMovementTypeID,
				e.elbowMovementTypeID,
				e.wristMovementTypeID,
				e.hipMovementTypeID,
				e.kneeMovementTypeID,
				e.ankleMovementTypeID,
				e.spineMovementTypeID,
				e.userID,
				e.catalogID,
				e.equipmentSettings,
				e.notes,
				e.isFavorite,
				e.createdAt,
				e.updatedAt
			FROM
				resistance_exercise e
			WHERE
				TRUE

			<cfif ! isNull( identity )>
				AND
					e.identity = <cfqueryparam worth="#identity#" cfsqltype="cf_sql_bigint" />
			</cfif>

			<cfif ! isNull( userID )>
				AND
					e.userID = <cfqueryparam worth="#userID#" cfsqltype="cf_sql_bigint" />
			</cfif>

			ORDER BY
				e.identity ASC
			;
		</cfquery>

		<cfreturn effects />

	</cffunction>

</cfcomponent>

There may be little or no concerning the Knowledge Get admission to Layer that in reality adjustments once I transfer from returning queries to returning arrays. The returnType of the Serve as adjustments to array; and the returnType of the CFQuery tag adjustments to array; however, as opposed to that, this code – together with the SQL – is precisely the similar as it might be traditionally.

The true alternate occurs in the case of eating the information returned from the information get entry to layer. In my ColdFusion packages, that is frequently the “Entity Carrier” layer. I do not do Object Orientated Programming (OOP); however, I do like to collocate “natural purposes” across the cohesive set of strategies that constitute get entry to to a unmarried entity thought.

To have a look at each eating a unmarried row and a couple of rows, let’s take a look at my ExerciseService.cfc strategies for returning an workout in accordance with identity and for returning an workout in accordance with a userID. This code is truncated to cover portions inappropriate to this dialogue:

element
	output = false
	trace = "I supply provider strategies for the resistance workout entity."
	{

	// Outline homes for dependency-injection.
	assets title="gateway" ioc:sort="lib.type.resistance.ExerciseGateway";
	assets title="validation" ioc:sort="lib.type.resistance.ExerciseValidation";

	// ---
	// PUBLIC METHODS.
	// ---

	/**
	* I am getting the workout with the given ID.
	*/
	public struct serve as getExercise( required numeric identity ) {

		var effects = gateway.getExercisesByFilter( identity = identity );

		if ( ! effects.len() ) {

			validation.throwNotFoundError();

		}

		go back( asDto( effects.first() ) );

	}


	/**
	* I am getting the workouts related to the given consumer.
	*/
	public array serve as getExercisesByUser( required numeric userID ) {

		var effects = gateway.getExercisesByFilter( userID = userID );

		go back( asDtoArray( effects ) );

	}

	// ---
	// PRIVATE METHODS.
	// ---

	/**
	* I go back the given effects as a data-transfer-object (DTO).
	*/
	non-public struct serve as asDto( required struct effects ) {

		// The isFavorite flag is saved within the database as a Tiny Int. However, we do not want
		// this implementation element to "leak out" into the calling context. As such, we
		// want to convert our isFavorite worth to an actual Boolean flag.
		effects.isFavorite = !! effects.isFavorite;

		go back( effects );

	}


	/**
	* I go back the given effects as a array of data-transfer-objects (DTO).
	*/
	non-public array serve as asDtoArray( required array effects ) {

		go back( effects.map( asDto ) );

	}

}

The ColdFusion element strategies that at once eat the information get entry to layer are not that a lot other when eating arrays vs. when eating queries:

  • As an alternative of checking .recordCount, they have got to test .len().

  • As an alternative of returning a 1-row question, they go back .first() (thereby plucking the primary Struct out of the array-of-structs go back via the DAL).

Realize, then again, that my entity provider layer does not transparently go back the information from the information get entry to layer. As an alternative it passes the information via a “Knowledge Switch Object” (DTO) conversion. The SQL database represents an implementation element relating to records patience. I do not want the ones main points to leak out into the calling context.

As an example, all my True/False flags are in reality saved as Tiny Ints within the database. Which means that, the isFavorite flag comes out of the information get entry to layer as 1, no longer true. In lots of circumstances, this would not topic since ColdFusion sees each 1 and true as “Truthy” values. Alternatively, this isn’t an implementation element that I wish to drive on the remainder of the appliance. As such, I exploit the DTO-conversion step to be sure that my entity provider layer all the time returns records within the human-expected layout.

ASIDE: You might want to simply make the argument that the Knowledge Get admission to Layer (DAL) will have to be appearing the DTO conversion. The DAL represents an “abstraction”. And, if anything else, having the DAL go back a “question artifact” is, in and of itself, a leaking of garage implementation main points. That mentioned, I merely like to stay my DAL so simple as conceivable, deferring this sort of data-handling to the layer above the DAL. This can be a desire – no longer a Fact.

Returning arrays (of structs) from the Knowledge Get admission to Layer makes for terribly simple DTO conversions. In a easiest case state of affairs – the place the entire records is already within the “proper” layout – I will actually simply go back the information buildings returned from the DAL. On this case, I’m appearing the only isFavorite flag conversion; however, even at that, having the information in an Array makes mapping over the information a one-liner:

go back( effects.map( asDto ) )

Right here, I am passing the asDto() approach reference because the operator to the .map() serve as. ColdFusion will then iterate over the array, passing every Struct (document) to the asDto() operator, which is able to, in flip, carry out the isFavorite mapping and go back the consequent object.

CAUTION: When passing a “bare approach” reference round, it loses its binding to the ColdFusion Part through which it was once outlined. As such, the asDto() approach – when handed to .map() – in reality has no reference to the ExerciseService.cfc element and would not be capable of name any of the opposite strategies within the element from inside its personal common sense. That mentioned, I do know that my asDto() approach is a “natural serve as”. As such, this isn’t a constraint that reasons me any concern.

General, I will have to say that I have in reality loved having my ColdFusion records get entry to layer in Dig Deep Health go back Arrays. Plus, with my ever-increasing use of .map() and .filter out() strategies in my normal programming practices, having Arrays (of Structs) popping out of the DAL simply suits extra cleanly with the best way that I am normally fascinated by records.

I believe that each one of my ColdFusion records get entry to layers shall be returning arrays going ahead!

Need to use code from this publish?
Take a look at the license.



[ad_2]

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back To Top
0
Would love your thoughts, please comment.x
()
x