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

[WIP] IntegratesQueryBuilder mixin #3

Merged
merged 8 commits into from
Mar 11, 2019

Conversation

hivokas
Copy link
Contributor

@hivokas hivokas commented Feb 13, 2019

This PR adds IntegratesQueryBuilder mixin which integrates https://github.com/coderello/js-query-builder

Example of use:

Article.all({ builder: query => query.filter('name', 'how to').sort('id').page(3) })

@hivokas
Copy link
Contributor Author

hivokas commented Feb 13, 2019

Do you have any ideas on how to cover that by tests?
I'm a little bit confused because js-query-builder is an implicit dependency (not listed in package.json)

Copy link
Owner

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

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

Hi 👋

Thanks for this very cool PR.

I've written a few comments on your code. Regarding the testing, I'm not sure how to mock a node module. Maybe this article could help you get started.

I hope this helps.

{
beforeRequest(request) {
if (superclass.hasOwnProperty('beforeRequest')) {
superclass.beforeRequest(request)
Copy link
Owner

Choose a reason for hiding this comment

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

Since we assume in the rest of the code that this mixin depends on MakesRequests, there is no need to check for the existence of beforeRequest. We can simply do:

request = super.beforeRequest(request)

let queryBuilderModule

try {
queryBuilderModule = require('js-query-builder')
Copy link
Owner

Choose a reason for hiding this comment

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

Good, that seems to be the way to define optional dependencies. We just need to set it up in the externals webpack options and according to this issue it should recognise this as an optional external.

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'm not sure if it is necessary to define it as external dependency somewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

require() works like a charm.

Copy link
Owner

Choose a reason for hiding this comment

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

Okay cool, so you don't have any errors when running npm run build?

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 haven't tried npm run build yet.
But I have no errors with npm run test both with and without js-query-builder being installed.


request.builder(builder)

request.query = builder
Copy link
Owner

Choose a reason for hiding this comment

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

This is a nice integration of js-query-builder but I feel that we could probably do better. Something more laravel-like.

let articles = Articles.query()
    .filter('age', 20)
    .sort('-created_at', 'name')
    .get()

We'd simply need to create a static query method that would return a new class QueryBuilder. This class needs to keep track of the model and have a get methods to send the accumulated request.

Note that both this approach and the current approach can be used together.

Anyway feel free to discard this if you'd rather leave things like this.

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 like your idea 👍

@hivokas
Copy link
Contributor Author

hivokas commented Feb 16, 2019

Thanks for the comments!
I will update PR soon.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 16, 2019

I've updated the code and made it more laravel-like.

@lorisleiva
Copy link
Owner

I really like your changes. Returning the builder directly with an extra get function on it is a brilliant idea. Would you mind writing a few tests before I can merge this?

@hivokas
Copy link
Contributor Author

hivokas commented Feb 17, 2019

Thanks!

Sure, I'll write a few tests.
I think mock-require could help me to mock js-query-builder module. I'll try it asap.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 19, 2019

I've added the tests. But, unfortunately, have a problem with optionality of js-query-builder.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 19, 2019

WARNING in ./src/IntegratesQueryBuilder.js
Module not found: Error: Can't resolve 'js-query-builder' in '/home/hivokas/development/projects/javel/src'
 @ ./src/IntegratesQueryBuilder.js
 @ ./src/index.js

@hivokas
Copy link
Contributor Author

hivokas commented Feb 19, 2019

Adding js-query-builder to the externals solves the issue for javel build.

externals: {
    mixwith: 'mixwith',
    'js-query-builder': 'js-query-builder',
},

But when I install javel to another project and try to build it, I receive a warning similar to mentioned in the previous comment.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 19, 2019

Do you have any ideas on how to beat this problem?

@lorisleiva
Copy link
Owner

Hi @hivokas thanks for writing those tests. Unfortunately I am really struggling to find any literature regarding optional externals with webpack. Could you copy/paste the warning that you get when installing Javel to another project?

@hivokas
Copy link
Contributor Author

hivokas commented Feb 22, 2019

                Chunks             Chunk Names
/assets/dashboard/app.css   237 KiB  /assets/dashboard/app  [emitted]  /assets/dashboard/app
 /assets/dashboard/app.js  1.86 MiB  /assets/dashboard/app  [emitted]  /assets/dashboard/app
     /assets/main/app.css   396 KiB  /assets/dashboard/app  [emitted]  /assets/dashboard/app

WARNING in ./node_modules/javel/dist/javel.js
Module not found: Error: Can't resolve 'js-query-builder' in '/home/hivokas/development/projects/blog/node_modules/javel/dist'
 @ ./node_modules/javel/dist/javel.js
 @ ./resources/assets/dashboard/js/models/BaseModel.js
 @ ./resources/assets/dashboard/js/models/Article.js
 @ ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/assets/dashboard/js/components/App.vue?vue&type=script&lang=js&
 @ ./resources/assets/dashboard/js/components/App.vue?vue&type=script&lang=js&
 @ ./resources/assets/dashboard/js/components/App.vue
 @ ./resources/assets/dashboard/js/app.js
 @ multi ./resources/assets/dashboard/js/app.js ./resources/assets/dashboard/css/app.scss ./resources/assets/main/css/app.scss
Done in 12.60s.

@lorisleiva
Copy link
Owner

@hivokas That is very annoying, I wrote a reply on an existing webpack issue to see if we're missing anything. Otherwise, I might have to consider using a different bundling solution.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 27, 2019

I have updated the pull request. What do you think about such workaround?

@lorisleiva
Copy link
Owner

Thanks for your work on this.

There is something I'm not sure to understand.

  • Is this Module not found warning only occurring because of the testing?
  • If we did not need to test this module at all, and did not include the dependency as an external, would we still have this warning?

Because if this is the case, then I think you work around makes sense but I'd like the "fake module registration" to belongs in the test folder whether than the src folder.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 28, 2019

Module not found error occurs because of require('js-query-builder') in IntegratesQueryBuilder.

@hivokas
Copy link
Contributor Author

hivokas commented Feb 28, 2019

What do you mean by "fake module registration"?
It is not fake module registration.

Let me explain my idea:

If user wants to use IntegratesQueryBuilder he will need to:

  • install js-query-builder into his project;
  • register it using Javel class:
import * as JsQueryBuilder from 'js-query-builder'
import { Javel } from 'javel'

Javel.registerOptionalModule('js-query-builder', JsQueryBuilder)

@hivokas
Copy link
Contributor Author

hivokas commented Feb 28, 2019

This way I'm avoiding require() use and the warning previously caused by it.

Copy link
Owner

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

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

Oh I see. Thank you for your explanation.

Now I understand why you've decided to mock your library in the tests.

I think it's a good idea but I just have a few comments regarding the implementation that I've written as a review.

package.json Outdated
@@ -41,6 +41,7 @@
"babel-plugin-webpack-alias-7": "^0.1.1",
"eslint": "^5.12.1",
"eslint-loader": "^2.1.1",
"mock-require": "^3.0.3",
Copy link
Owner

Choose a reason for hiding this comment

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

I don't think we need this dependency anymore, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah

@@ -0,0 +1,43 @@
import { Mixin } from 'mixwith'
import Javel from '@/Javel'
Copy link
Owner

Choose a reason for hiding this comment

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

I'd rather register the modules a little bit differently.

Instead of exposing a global Javel class...

import { Javel } from 'javel'

Javel.registerOptionalModule(name, dependency)
let dependency = Javel.resolveOptionalModule(name)

... I'd rather expose the functions directly

import { registerModule, resolveModule } from 'javel'

registerModule(name, dependency)
let dependency = resolveModule(name)

That way we can even rename the Javel class into something more specific like ModuleRegistration.

What do you think?

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 like your idea.

try {
queryBuilderModule = Javel.resolveOptionalModule('js-query-builder')
} catch (e) {
throw new Error('IntegratesQueryBuilder mixin requires optional "js-query-builder" module to be registered.')
Copy link
Owner

Choose a reason for hiding this comment

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

I don't think the try/catch here is necessary anymore since the resolveOptionalModule method already has it's own try/catch.

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've wrapped resolving of the module with try/catch in order to make an exception message more sensible.

Copy link
Owner

Choose a reason for hiding this comment

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

Okay makes sense. 🙂

@hivokas
Copy link
Contributor Author

hivokas commented Mar 6, 2019

I've updated the pull request according to your review.

@lorisleiva lorisleiva merged commit fc48d7c into lorisleiva:master Mar 11, 2019
@lorisleiva
Copy link
Owner

Thank you very much this PR and for your work on finding out how to register optional modules! Before I create a new release, can you please confirm that this PR is completely transparent to users that do not use the js-query-builder dependency?

Thanks again! 🍺

@hivokas
Copy link
Contributor Author

hivokas commented Mar 11, 2019

Do we need kinda readme for this mixin?

@hivokas
Copy link
Contributor Author

hivokas commented Mar 13, 2019

@lorisleiva

@lorisleiva
Copy link
Owner

Hi, yes I think we would need to update the documentation to explain this new module registration system. I see it as:

  • One small section at the end of the README explaining how to add mixins that have dependencies in Javel.
  • For each mixins that have external dependencies, add in their documentation page how to register the dependency itself.

Screenshot 2019-03-13 at 09 41 48

What do you think?

@hivokas
Copy link
Contributor Author

hivokas commented Mar 14, 2019

@lorisleiva, yeah, I agree with you. Who will work on it: you or me?

@lorisleiva
Copy link
Owner

Hi, I'm more than happy to do it. I just think that once I've written the main structure of the second bulletpoint, maybe you could document some of the features of your js-query-builder library.

I won't be able to do that just now but I'll open an issue to make sure it's in my pipeline. 👍

@hivokas
Copy link
Contributor Author

hivokas commented Mar 14, 2019

Deal 🕶️
Let me know when I can start my part (you can mention me in #6).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants