Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#35: Refactor the core for more logical structure #36

Merged

Conversation

benedeki
Copy link
Contributor

@benedeki benedeki commented Jun 1, 2023

  • This is a major refactoring of the library classes
  • The calls are more logical
  • DBExcecutor changed to DBEngine, the core and db engine (Slick at the moment) responsibility parts better separated
  • Easier mix-in traits
  • Prepared for new features to be implemented (Result: get columns by name #6, Automatic query composition #7, ...)
  • See how much neater the usage now is in the DatasetSchema example class

Closes #35

@benedeki benedeki requested a review from lsulak June 1, 2023 10:50
@benedeki benedeki self-assigned this Jun 1, 2023
@benedeki benedeki marked this pull request as ready for review June 4, 2023 07:33
…refactor-the-core-for-more-logical-structure
@benedeki
Copy link
Contributor Author

benedeki commented Jun 4, 2023

Need to add/fix the documentation still. (That's why Build / Build and test are failing )
Added now

@github-actions
Copy link

github-actions bot commented Jun 5, 2023

JaCoCo code coverage report - scala 2.12.17

File Coverage [55.97%]
StandardStatusHandling.scala 100% 🍏
UserDefinedStatusHandling.scala 100% 🍏
FunctionStatus.scala 100% 🍏
StatusHandling.scala 100% 🍏
StatusException.scala 86.17% 🍏
DBFailException.scala 80% 🍏
DBSchema.scala 70.69%
DBFunction.scala 24.43%
DBEngine.scala 0%
DBFunctionFabric.scala 0%
SlickPgEngine.scala 0%
SlickQuery.scala 0%
SlickPgFunctionWithStatusSupport.scala 0%
SlickPgFunction.scala 0%
Total Project Coverage 58.75% 🍏

@github-actions
Copy link

github-actions bot commented Jun 5, 2023

JaCoCo code coverage report - scala 2.11.12

File Coverage [56.26%]
StandardStatusHandling.scala 100% 🍏
UserDefinedStatusHandling.scala 100% 🍏
FunctionStatus.scala 100% 🍏
StatusHandling.scala 100% 🍏
StatusException.scala 86.32% 🍏
DBFailException.scala 82.26% 🍏
DBSchema.scala 74.63%
DBFunction.scala 33.99%
DBEngine.scala 0%
DBFunctionFabric.scala 0%
SlickPgEngine.scala 0%
SlickQuery.scala 0%
SlickPgFunctionWithStatusSupport.scala 0%
SlickPgFunction.scala 0%
Total Project Coverage 59.15% 🍏

Copy link
Contributor

@miroslavpojer miroslavpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Pulled
  • Built
  • Test ran
  • Code review (not enough insight into advance scala for this)
  • tests code review
  • test coverage analysis

trait SlickPgFunction[T, R] extends DBFunctionFabric {

protected def sqlToCallFunction(values: T): SQLActionBuilder
/**
* A reference to the [[SlickPgEngine]] to use the [[za.co.absa.fadb.DBFunction]] with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DBFunction link not working

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this doesn't work because it goes to a different module and searches on the not-yet-released doc.


/**
* An extension of the [[SlickPgFunction]] mix-in trait to add support of status handling
* This trait expects another mix-in of [[za.co.absa.fadb.statushandling.StatusHandling]] (or implementation of `checkStatus` function)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StatusHandling link not working.


/**
* Function which should actually check the status code returned by the DB function. Expected to got implemented by
* [[za.co.absa.fadb.statushandling.StatusHandling]] successor trait. But of course can be implemented directly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link not working.

Copy link
Contributor

@miroslavpojer miroslavpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Pulled
  • Built
  • Test ran
  • Code review (not enough insight into advance scala for this)
  • tests code review
  • test coverage analysis

* @tparam R - return the of the query
* @return - sequence of the results of database query
*/
def unique[R](query: QueryType[R]): Future[R] = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking about whether to name this as executeOne

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like 'execute' as prefix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I on the other hand like them distinguished. 😉 Easier to read. and also nicely binds to the successor classes.

Copy link
Collaborator

@lsulak lsulak Jun 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think option is easier to read. It's not intuitive. We are actually executing a SQL query here.

In regards to the unique ... it's kind of better, but still, I don't really like it that much.

Let's have an inspiration from some most famous DB libraries out there. For example SQLAlchemy. There are functions like fetchOne, executeMany etc - https://peps.python.org/pep-0249/#executemany and I think that's much better, because it not only says what the result kind of should be, but also it says about what is actually happening. Does it make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, Will think about the names 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed to do the renames as part of #34

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

benedeki and others added 2 commits June 9, 2023 17:47
@benedeki benedeki added refactoring Improving code quality, paying off tech debt, aligning APIs Core Item affecting the core of the library Slick Item affecting the Slick executor implementation dependent The item depends on some other open item (Issue or PR) and removed dependent The item depends on some other open item (Issue or PR) labels Jun 10, 2023
@lsulak
Copy link
Collaborator

lsulak commented Jun 11, 2023

This exception does't have a companion object with apply function:

case class NamingException(message: String) extends Exception(message)

just saying, all exceptions have this, so it's inconsistent. But I don't strictly insist on changing it, up to you

}

override protected def sqlToCallFunction(values: (String, Option[Int])): SQLActionBuilder = {
override protected def sql(values: (String, Option[Int])): SQLActionBuilder = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this Option[Int] for? If it's schema name an version, then according to the Schema case class, they are both mandatory:

schemaName: String,
schemaVersion: Int,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was in some description.
Version is mandatory with the schema (any entity), but when not provided, the latest version is returned.
Then it's perfectly OK, to use None = Null = unknown/undefined in the query, me thinks.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooh okay. Yeah perhaps some quick code doc can be useful for these examples then. But I know that we'll rework it anyway..

}

final class ListSchemas(implicit schema: DBSchema[ExecutorEngineType])
extends DBSeqFunction[ExecutorEngineType, Boolean, SchemaHeader](schema)
final class List(implicit override val schema: DBSchema, override val dbEngine: SlickPgEngine)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that this is just an example but maybe it can be further improved?

Why ListSchemas -> List? List is quite general and the name can be both verb (list/enumerate something) or a noun (list as a data type). I would prefer ListSchemas or ListSchemaHeaders if you want

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeeaah.
Well the examples were created for Enceladus migration to Postgres. Then the function name in the DB model in that PR were changed. But before reflecting it here, the whole migration was shelved.
The examples confidently show some interesting methods how the DBFunction successors can operate:

  • having or not having status support
  • defining additional apply function
  • overriding the existing one
    So they might serve some benefit until Standalone rerunable examples #9 is delivered.

But I wanted to test it against the Enceladus DB model, just to verify, the refactoring works in practice, not just compilation. That's why the rename... Might be rolled back. 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay I kind of thought so. Well, since there is this #9, which will change everything, I don't mind keeping as is. Maybe, if you are up for it, add some brief code doc, maybe 1-2 sentences can be enough. But up to you - I at least wanted to have some understanding and now I have :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The examples confidently show... -> The examples coincidentally show...

final class ListSchemas(implicit schema: DBSchema[ExecutorEngineType])
extends DBSeqFunction[ExecutorEngineType, Boolean, SchemaHeader](schema)
final class List(implicit override val schema: DBSchema, override val dbEngine: SlickPgEngine)
extends DBSeqFunction[Boolean, SchemaHeader, SlickPgEngine]()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the status support/handling were not used here? What's different there? I think that 'list' operation is similar to 'get' i.e. the DB function should return some status code and status text for us?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list operations returning a number of results and being strictly read-only, don't have to have status results. I still prefer that, while I think @Zejnilovic less.
Anyway, here it works again as an example - status is not mandatory.
In Unify we can (and should) still discuss this concept ❗

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay let's talk about it. I think, after re-reading of https://docs.google.com/document/d/1gYVg6y9Ug4EC5CKSm7sRZ0bN5nv5Eeta_YiVGBoHP4A/edit#, that a pure select operations don't have to have the status code / handling around it. But if there is a chance that a given DB function is doing more then a select, then the status codes are relevant. We can discuss outside of this PR

@lsulak
Copy link
Collaborator

lsulak commented Jun 11, 2023

Will do. There's a renaming task for the repo. And I am wondering if status pacgae shouldn't have a better structure too. Would love to discuss.

I think that it's fine but if you want we can discuss, definitely 👍

@benedeki
Copy link
Contributor Author

This exception does't have a companion object with apply function:

case class NamingException(message: String) extends Exception(message)

just saying, all exceptions have this, so it's inconsistent. But I don't strictly insist on changing it, up to you

It's a case class, with automatic apply function provided by Scala. What should be in the companion object?

Copy link
Collaborator

@lsulak lsulak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The review finished. Just some minor points about potential code docs, otherwise it looks good to me!

I didn't test it - just pulled, build, ran tests, and did the review.

…asetSchema.scala

Co-authored-by: Ladislav Sulak <laco.sulak@gmail.com>
Copy link
Collaborator

@lsulak lsulak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good work, I think that it's time to merge it :)

@benedeki benedeki merged commit a453411 into master Jun 13, 2023
@benedeki benedeki deleted the feature/35-refactor-the-core-for-more-logical-structure branch June 13, 2023 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core Item affecting the core of the library refactoring Improving code quality, paying off tech debt, aligning APIs Slick Item affecting the Slick executor implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor the core for more logical structure
3 participants