Attempting to upgrade from Anorm 2.4.0 to 2.5.0 we run into this issue.
For all aliased columns we get a null value inside columnsDictionary in Row.scala#L128 resulting in the exception below:
An exception or error caused a run to abort: ColumnName(test_users.test_users_email,Some(USER_EMAIL)) anorm.AnormException: ColumnName(test_users.test_users_email,Some(USER_EMAIL))
private[anorm] def get(a: String): MayErr[SqlRequestError, (Any, MetaDataItem)] = for {
m <- MayErr(metaData.get(a).toRight(ColumnNotFound(a, this)))
data <- MayErr(columnsDictionary.get(m.column.qualified.toUpperCase()).
toRight(ColumnNotFound(m.column.qualified, metaData.availableColumns)))
} yield (data, m)
This issue stems from the workaround we used in: http://stackoverflow.com/questions/36431356/unexpectednullablefound-on-left-join
Likely solved in here, but an issue in 2.5
https://github.com/playframework/anorm/blob/2.4.x/core/src/main/scala/anorm/Row.scala#L128
&
https://github.com/playframework/anorm/blob/master/core/src/main/scala/anorm/Row.scala#L128
val simple = {
get[Long]("test_users_id") ~
get[String]("USER_EMAIL") ~
get[String]("test_users_first_name") ~
get[String]("test_users_second_name") ~
get[String]("USER_COMPANY") ~
get[String]("useas") ~
get[Option[String]]("Stripe_CUSTOMER_ID") ~
get[Boolean]("is_invoice_customer") ~
get[Option[String]]("test_users_invoice_email") ~
get[Array[Byte]]("password_hash") ~
get[Array[Byte]]("salt") ~
get[String]("invoice_address") ~
get[Option[String]]("time_zone") ~
get[DateTime]("USER_LAST_PAYMENT_DATE") ~
get[DateTime]("sign_up_date") ~
get[Option[String]]("USER_SPIKE_ROLE") ~
get[Option[Int]]("num_team") ~
get[Int]("paid_for_team") ~
get[Option[Long]]("test_users_admin_id") ~
get[Option[DateTime]]("ADMIN_LAST_PAYMENT_DATE") ~
get[Option[String]]("ADMIN_SPIKE_ROLE") ~
get[Option[DateTime]]("FIRST_PAYMENT_DATE") ~
get[Option[String]]("ADMIN_EMAIL") ~
get[Option[DateTime]]("ADMIN_FIRST_PAYMENT_DATE") ~
get[Option[String]]("utm_source") ~
get[Option[String]]("utm_medium") ~
get[Option[String]]("utm_campaign") ~
get[Option[String]]("sf_exec") ~
get[Option[Long]]("syndication_access_manager") ~
get[Option[String]]("vat_number") ~
get[Boolean]("bounced_email") ~
get[Option[String]]("ADMIN_COMPANY") map {
case testUsersId ~ userEmail ~ testUsersFirstName ~ testUsersSecondName
~ company ~ useAs ~ stripeCustomerId ~ isInvoiceCustomer ~ xeroContactEmail ~ passwordHash ~ salt ~
invoiceAddress ~ timeZone ~ lastPaymentDate ~ signUpDate ~ testRole ~ numTeam ~ paidForTeam ~ testUsersAdminId ~ adminLastPaymentDate ~ adminTestRole ~ firstPaymentDate ~
adminEmail ~ adminFirstPaymentDate ~ utmSource ~ utmMedium ~ utmCampaign ~ sfExec ~ syndicationAccessManagerId ~ vatNumber ~ bouncedEmail ~ adminCompany =>
TestUser(testUsersId, userEmail, testUsersFirstName,
testUsersSecondName, company, useAs, invoiceAddress,
stripeCustomerId,
isInvoiceCustomer,
xeroContactEmail,
passwordHash.toVector, salt.toVector,
teamLastPaymentDate(lastPaymentDate, adminLastPaymentDate, testUsersAdminId, stripeCustomerId), new DateTime(signUpDate, DateTimeZone.UTC),
testRoleFromTeam(testRole, testUsersAdminId, stripeCustomerId, adminTestRole), paidByOtherUser(testUsersAdminId, stripeCustomerId), numTeam.getOrElse[Int](0), //
getSeatCount(paidForTeam), timeZone.flatMap(getSafeTimeZone),
firstPaymentDateFromTeam(testUsersAdminId, stripeCustomerId, firstPaymentDate, adminFirstPaymentDate), adminEmail, utmSource, utmMedium, utmCampaign,
sfExec, syndicationAccessManagerId, vatNumber, getCompanyCustomer(testUsersAdminId, adminCompany, adminFirstPaymentDate, adminTestRole, testUsersId, company, firstPaymentDate, testRole), bouncedEmail)
}
}
def createCompanyCustomer(testUsersAdminId: Option[Long], adminCompany: Option[String], adminFirstPaymentDate: Option[DateTime], adminTestRole: Option[String]): Option[NewsWhipCustomer] = {
for {
id <- testUsersAdminId
company <- adminCompany
firstPaymentDate <- adminFirstPaymentDate
testRole <- adminTestRole
} yield NewsWhipCustomer(id, company, firstPaymentDate, testRole)
}
def getCompanyCustomer(testUsersAdminId: Option[Long], adminCompany: Option[String], adminFirstPaymentDate: Option[DateTime], adminTestRole: Option[String], testUserId: Long, company: String, firstPaymentDate: Option[DateTime], testRole: Option[String]): Option[NewsWhipCustomer] = {
if (testUsersAdminId.isDefined) {
createCompanyCustomer(testUsersAdminId, adminCompany, adminFirstPaymentDate, adminTestRole)
} else {
createCompanyCustomer(Some(testUserId), Some(company), firstPaymentDate, testRole)
}
}
def findByUserId(userId: Long): TestUser = {
DB.withConnection { implicit connection =>
SQL"""
SELECT s.test_users_id, s.test_users_email AS USER_EMAIL, s.test_users_first_name, s.test_users_second_name, s.company AS USER_COMPANY, s.useas, s.Stripe_CUSTOMER_ID,
s.is_invoice_customer, s.test_users_invoice_email,
s.password_hash, s.salt, s.invoice_address,
s.time_zone, s.last_payment_date AS USER_LAST_PAYMENT_DATE, s.sign_up_date, s.test_role AS USER_SPIKE_ROLE, s.num_team, (SELECT COUNT(*) FROM test_users_paid_for WHERE test_users_admin_id = $userId) AS paid_for_team,
s.syndication_access_manager, p.test_users_admin_id, pe.last_payment_date AS ADMIN_LAST_PAYMENT_DATE, pe.test_role AS ADMIN_SPIKE_ROLE,
s.FIRST_PAYMENT_DATE AS FIRST_PAYMENT_DATE, pe.FIRST_PAYMENT_DATE AS ADMIN_FIRST_PAYMENT_DATE, pe.test_users_email AS ADMIN_EMAIL, s.utm_source, s.utm_medium, s.utm_campaign, s.sf_exec, s.bounced_email,
s.vat_number, pe.company AS ADMIN_COMPANY
FROM test_users AS s
LEFT JOIN test_users_paid_for AS p ON email_users_email = s.test_users_email
LEFT JOIN test_users AS pe ON p.test_users_admin_id = pe.test_users_id
WHERE s.test_users_id = $userId
""".as(simple.single)
}
}
This is the content of my columnsDictionary and aliasesDictionary
columsDictionary:
0 = {Tuple2@9987} "(TEST_USERS.FIRST_PAYMENT_DATE,2016-04-11 11:05:44.0)"
1 = {Tuple2@9988} "(TEST_USERS.STRIPE_CUSTOMER_ID,null)"
2 = {Tuple2@9989} "(TEST_USERS.SALT,[B@70ecf57b)"
3 = {Tuple2@9990} "(TEST_USERS.SIGN_UP_DATE,2014-07-07 11:24:55.0)"
4 = {Tuple2@9991} "(TEST_USERS.IS_INVOICE_CUSTOMER,false)"
5 = {Tuple2@9992} "(TEST_USERS.SF_EXEC,null)"
6 = {Tuple2@9993} "(TEST_USERS.UTM_CAMPAIGN,null)"
7 = {Tuple2@9994} "(TEST_USERS.TEST_USERS_SECOND_NAME,d)"
8 = {Tuple2@9995} "(.PAID_FOR_TEAM,0)"
9 = {Tuple2@9996} "(TEST_USERS.INVOICE_ADDRESS,)"
10 = {Tuple2@9997} "(TEST_USERS.UTM_SOURCE,null)"
11 = {Tuple2@9998} "(TEST_USERS.VAT_NUMBER,null)"
12 = {Tuple2@9999} "(TEST_USERS_PAID_FOR.TEST_USERS_ADMIN_ID,4806)"
13 = {Tuple2@10000} "(TEST_USERS.NUM_TEAM,0)"
14 = {Tuple2@10001} "(TEST_USERS.LAST_PAYMENT_DATE,2016-08-06 10:43:32.0)"
15 = {Tuple2@10002} "(TEST_USERS.COMPANY,LeleCreation)"
16 = {Tuple2@10003} "(TEST_USERS.USEAS,general-interest)"
17 = {Tuple2@10004} "(TEST_USERS.PASSWORD_HASH,[B@4e96cb04)"
18 = {Tuple2@10005} "(TEST_USERS.TIME_ZONE,Atlantic/Cape_Verde)"
19 = {Tuple2@10006} "(TEST_USERS.UTM_MEDIUM,null)"
20 = {Tuple2@10007} "(TEST_USERS.SYNDICATION_ACCESS_MANAGER,null)"
21 = {Tuple2@10008} "(TEST_USERS.TEST_USERS_ID,4800)"
22 = {Tuple2@10009} "(TEST_USERS.TEST_USERS_FIRST_NAME,test2)"
23 = {Tuple2@10010} "(TEST_USERS.TEST_USERS_EMAIL,[email protected])"
24 = {Tuple2@10011} "(TEST_USERS.TEST_USERS_INVOICE_EMAIL,null)"
25 = {Tuple2@10012} "(TEST_USERS.BOUNCED_EMAIL,false)"
26 = {Tuple2@10013} "(TEST_USERS.TEST_ROLE,TestTeam)"
aliasesDictionary
0 = {Tuple2@10123} "(SF_EXEC,null)"
1 = {Tuple2@10124} "(BOUNCED_EMAIL,false)"
2 = {Tuple2@10125} "(USER_COMPANY,test2test2)"
3 = {Tuple2@10126} "(SYNDICATION_ACCESS_MANAGER,null)"
4 = {Tuple2@10127} "(ADMIN_LAST_PAYMENT_DATE,2016-08-06 10:43:32.0)"
5 = {Tuple2@10128} "(PAID_FOR_TEAM,0)"
6 = {Tuple2@10129} "(INVOICE_ADDRESS,)"
7 = {Tuple2@10130} "(ADMIN_EMAIL,[email protected])"
8 = {Tuple2@10131} "(TEST_USERS_ADMIN_ID,4806)"
9 = {Tuple2@10132} "(USER_LAST_PAYMENT_DATE,2014-07-09 13:17:06.0)"
10 = {Tuple2@10133} "(TEST_USERS_INVOICE_EMAIL,null)"
11 = {Tuple2@10134} "(ADMIN_FIRST_PAYMENT_DATE,2016-04-11 11:05:44.0)"
12 = {Tuple2@10135} "(TEST_USERS_SECOND_NAME,d)"
13 = {Tuple2@10136} "(STRIPE_CUSTOMER_ID,null)"
14 = {Tuple2@10137} "(TEST_USERS_FIRST_NAME,test2)"
15 = {Tuple2@10138} "(UTM_MEDIUM,null)"
16 = {Tuple2@10139} "(IS_INVOICE_CUSTOMER,false)"
17 = {Tuple2@10140} "(USER_EMAIL,[email protected])"
18 = {Tuple2@10141} "(TEST_USERS_ID,4800)"
19 = {Tuple2@10142} "(VAT_NUMBER,null)"
20 = {Tuple2@10143} "(UTM_CAMPAIGN,null)"
21 = {Tuple2@10144} "(TIME_ZONE,Atlantic/Cape_Verde)"
22 = {Tuple2@10145} "(UTM_SOURCE,null)"
23 = {Tuple2@10146} "(SALT,[B@70ecf57b)"
24 = {Tuple2@10147} "(NUM_TEAM,0)"
25 = {Tuple2@10148} "(ADMIN_COMPANY,LeleCreation)"
26 = {Tuple2@10149} "(FIRST_PAYMENT_DATE,null)"
27 = {Tuple2@10150} "(USEAS,general-interest)"
28 = {Tuple2@10151} "(PASSWORD_HASH,[B@4e96cb04)"
29 = {Tuple2@10152} "(ADMIN_TEST_ROLE,TestTeam)"
30 = {Tuple2@10153} "(SIGN_UP_DATE,2014-07-07 11:24:55.0)"
31 = {Tuple2@10154} "(USER_TEST_ROLE,null)"