[
  {
    "path": ".gitattributes",
    "content": "# Path-based git attributes\n# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html\n\n# Ignore all test and documentation with \"export-ignore\".\n/.github            export-ignore\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/phpunit.xml        export-ignore\n/phpunit.xml.dist   export-ignore\n/art                export-ignore\n/database           export-ignore\n/docs               export-ignore\n/tests              export-ignore\n/.editorconfig      export-ignore\n/.php_cs.dist.php   export-ignore\n/psalm.xml          export-ignore\n/psalm.xml.dist     export-ignore\n/pint.json          export-ignore\n/testbench.yaml     export-ignore\n/UPGRADING.md       export-ignore\n/phpstan.neon.dist  export-ignore\n/phpstan-baseline.neon  export-ignore\n/.scrutinizer.yml   export-ignore\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/biiiiiigmonster/hasin/discussions/new?category=q-a\n    about: Ask the community for help\n  - name: Request a feature\n    url: https://github.com/biiiiiigmonster/hasin/discussions/new?category=ideas\n    about: Share ideas for new features\n  - name: Report a security issue\n    url: https://github.com/biiiiiigmonster/hasin/security/policy\n    about: Learn how to notify us for sensitive bugs\n  - name: Report a bug\n    url: https://github.com/biiiiiigmonster/hasin/issues/new\n    about: Report a reproducable bug\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"dependencies\""
  },
  {
    "path": ".github/workflows/dependabot-auto-merge.yml",
    "content": "name: dependabot-auto-merge\non: pull_request_target\n\npermissions:\n  pull-requests: write\n  contents: write\n\njobs:\n  dependabot:\n    runs-on: ubuntu-latest\n    if: ${{ github.actor == 'dependabot[bot]' }}\n    steps:\n    \n      - name: Dependabot metadata\n        id: metadata\n        uses: dependabot/fetch-metadata@v2.5.0\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          \n      - name: Auto-merge Dependabot PRs for semver-minor updates\n        if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}}\n        run: gh pr merge --auto --merge \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}\n          \n      - name: Auto-merge Dependabot PRs for semver-patch updates\n        if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}}\n        run: gh pr merge --auto --merge \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}\n"
  },
  {
    "path": ".github/workflows/fix-php-code-style-issues.yml",
    "content": "name: Fix PHP code style issues\n\non: [push]\n\njobs:\n  php-code-styling:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ github.head_ref }}\n\n      - name: Fix PHP code style issues\n        uses: aglipanci/laravel-pint-action@2.6\n\n      - name: Commit changes\n        uses: stefanzweifel/git-auto-commit-action@v7\n        with:\n          commit_message: Fix styling\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "name: run-tests\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n\n    services:\n      mysql:\n        image: mysql:5.7\n        env:\n          MYSQL_ROOT_PASSWORD: root\n          MYSQL_DATABASE: laravel\n        ports:\n          - 33306:3306\n        options: --health-cmd=\"mysqladmin ping\" --health-interval=10s --health-timeout=5s --health-retries=3\n\n    strategy:\n      fail-fast: true\n      matrix:\n        os: [ubuntu-latest]\n        php: [8.2, 8.3, 8.4]\n        laravel: ['12.*', '13.*']\n        stability: [prefer-lowest, prefer-stable]\n        include:\n          - laravel: 12.*\n            testbench: 10.*\n          - laravel: 13.*\n            testbench: 11.*\n        exclude:\n          - laravel: 13.*\n            php: 8.2\n\n    name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo\n          coverage: xdebug\n\n      - name: Setup problem matchers\n        run: |\n          echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"\n          echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n\n      - name: Install dependencies\n        run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction\n\n      - name: Execute tests\n        run: vendor/bin/pest\n        env:\n          DB_PORT: 33306\n          DB_PASSWORD: root\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.phpunit.result.cache\nbuild\ncomposer.lock\ncoverage\ndocs\nphpunit.xml\ntestbench.yaml\nvendor\nnode_modules\n.phpunit.cache\n"
  },
  {
    "path": ".scrutinizer.yml",
    "content": "checks:\n  php:\n    code_rating: true\n    remove_extra_empty_lines: true\n    remove_php_closing_tag: true\n    remove_trailing_whitespace: true\n    fix_use_statements:\n      remove_unused: true\n      preserve_multiple: false\n      preserve_blanklines: true\n      order_alphabetically: true\n    fix_linefeed: true\n    fix_line_ending: true\n    fix_identation_4spaces: true\n\nbuild:\n  image: default-bionic\n  environment:\n    php:\n      version: 8.2\n  tests:\n    override:\n      - command: './vendor/bin/pest'\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to `hasin` will be documented in this file.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) Yunfeng Lu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README-CN.md",
    "content": "[English](./README.md) | 中文\n\n<div align=\"center\">\n\n# LARAVEL HASIN\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/biiiiiigmonster/hasin.svg?style=flat-square)](https://packagist.org/packages/biiiiiigmonster/hasin)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/biiiiiigmonster/hasin/run-tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/biiiiiigmonster/hasin/actions?query=workflow%3Arun-tests+branch%3Amaster)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/biiiiiigmonster/hasin/fix-php-code-style-issues.yml?branch=master&label=code%20style&style=flat-square)](https://github.com/biiiiiigmonster/hasin/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amaster)\n[![Coverage Status](https://coveralls.io/repos/github/biiiiiigmonster/hasin/badge.svg?branch=master)](https://coveralls.io/github/biiiiiigmonster/hasin?branch=master)\n[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/biiiiiigmonster/hasin.svg?label=Scrutinizer&style=flat-square)](https://scrutinizer-ci.com/g/biiiiiigmonster/hasin/)\n[![Total Downloads](https://img.shields.io/packagist/dt/biiiiiigmonster/hasin.svg?style=flat-square)](https://packagist.org/packages/biiiiiigmonster/hasin)\n\n</div>\n\n`hasin`是一个基于`where in`语法实现的`Laravel ORM`关联关系查询的扩展包，部分业务场景下可以替代`Laravel ORM`中基于`where exists`语法实现的`has`，以获取更高的性能。\n\n## 安装\n\n| Laravel 版本      | 安装命令                                                |\n|-----------------|-----------------------------------------------------|\n| Laravel 12      | ``` composer require biiiiiigmonster/hasin:^5.0 ``` |\n| Laravel 11      | ``` composer require biiiiiigmonster/hasin:^4.0 ``` |\n| Laravel 10      | ``` composer require biiiiiigmonster/hasin:^3.0 ``` |\n| Laravel 9       | ``` composer require biiiiiigmonster/hasin:^2.0 ``` |\n| Laravel 5.5 ~ 8 | ``` composer require biiiiiigmonster/hasin:^1.0 ``` |\n\n## 简介\n\n`Laravel ORM`的关联关系非常强大，基于关联关系的查询`has`也给我们提供了诸多灵活的调用方式，然而某些情形下，`has`使用了**where exists**语法实现\n\n例如:\n```php\n// User hasMany Post\nUser::has('posts')->get();\n```\n#### `select * from users where exists (select * from posts where users.id = posts.user_id)`\n> exists是对外表做loop循环，每次loop循环再对内表（子查询）进行查询，那么因为对内表的查询使用的索引（内表效率高，故可用大表），而外表有多大都需要遍历，不可避免（尽量用小表），故内表大的使用exists，可加快效率。\n\n当**User表**数据量较大的时候，就会出现性能问题，那么这时候用**where in**语法将会极大的提高性能\n\n#### `select * from users where users.id in (select posts.user_id from posts)`\n> in是把外表和内表做hash连接，先查询内表，再把内表结果与外表匹配，对外表使用索引（外表效率高，可用大表），而内表多大都需要查询，不可避免，故外表大的使用in，可加快效率。\n\n因此在代码中使用`has(hasMorph)`或者`hasIn(hasMorphIn)`应由**数据体量**来决定……\n\n```php\n/**\n * SQL:\n * \n * select * from `users` \n * where exists \n *   ( \n *      select * from `posts` \n *      where `users`.`id` = `posts`.`user_id` \n *   ) \n * limit 10 offset 0\n */\n$users = User::has('posts')->paginate(10);\n\n/**\n * SQL:\n * \n * select * from `users` \n * where `users`.`id` in  \n *   ( \n *      select `posts`.`user_id` from `posts` \n *   ) \n * limit 10 offset 0\n */\n$users = User::hasIn('posts')->paginate(10);\n```\n\n## 使用\n\n此扩展方法`hasIn(hasMorphIn)`支持`Laravel ORM`中的所有关联关系，入参调用及内部实现流程与框架的`has(hasMorph)`完全一致。\n\n> hasIn\n\n```php\n// hasIn\nUser::hasIn('posts')->get();\n\n// orHasIn\nUser::where('age', '>', 18)->orHasIn('posts')->get();\n\n// doesntHaveIn\nUser::doesntHaveIn('posts')->get();\n\n// orDoesntHaveIn\nUser::where('age', '>', 18)->orDoesntHaveIn('posts')->get();\n```\n\n> whereHasIn\n\n```php\n// whereHasIn\nUser::whereHasIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// orWhereHasIn\nUser::where('age', '>', 18)->orWhereHasIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// whereDoesntHaveIn\nUser::whereDoesntHaveIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// orWhereDoesntHaveIn\nUser::where('age', '>', 18)->orWhereDoesntHaveIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n```\n\n> hasMorphIn\n\n```php\nImage::hasMorphIn('imageable', [Post::class, Comment::class])->get();\n```\n\n### 嵌套关联\n\n```php\nUser::hasIn('posts.comments')->get();\n```\n\n## 测试\n```bash\ncomposer test\n```\n\n## 联系交流\nwx：biiiiiigmonster(备注：hasin)\n\n## 协议\n[MIT 协议](LICENSE)\n"
  },
  {
    "path": "README.md",
    "content": "English | [中文](./README-CN.md)\n\n<div align=\"center\">\n\n# LARAVEL HASIN\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/biiiiiigmonster/hasin.svg?style=flat-square)](https://packagist.org/packages/biiiiiigmonster/hasin)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/biiiiiigmonster/hasin/run-tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/biiiiiigmonster/hasin/actions?query=workflow%3Arun-tests+branch%3Amaster)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/biiiiiigmonster/hasin/fix-php-code-style-issues.yml?branch=master&label=code%20style&style=flat-square)](https://github.com/biiiiiigmonster/hasin/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amaster)\n[![Coverage Status](https://coveralls.io/repos/github/biiiiiigmonster/hasin/badge.svg?branch=master)](https://coveralls.io/github/biiiiiigmonster/hasin?branch=master)\n[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/biiiiiigmonster/hasin.svg?label=Scrutinizer&style=flat-square)](https://scrutinizer-ci.com/g/biiiiiigmonster/hasin/)\n[![Total Downloads](https://img.shields.io/packagist/dt/biiiiiigmonster/hasin.svg?style=flat-square)](https://packagist.org/packages/biiiiiigmonster/hasin)\n\n</div>\n\nThe `hasin` is composer package based on `where in` syntax to query the relationship of `laravel ORM`, which can replace `has` based on `where exists` syntax in some business scenarios to obtain higher performance.\n\n# Installation\n| Laravel Version | Install command                                     |\n|-----------------|-----------------------------------------------------|\n| Laravel 12      | ``` composer require biiiiiigmonster/hasin:^5.0 ``` |\n| Laravel 11      | ``` composer require biiiiiigmonster/hasin:^4.0 ``` |\n| Laravel 10      | ``` composer require biiiiiigmonster/hasin:^3.0 ``` |\n| Laravel 9       | ``` composer require biiiiiigmonster/hasin:^2.0 ``` |\n| Laravel 5.5 ~ 8 | ``` composer require biiiiiigmonster/hasin:^1.0 ``` |\n\n# Introductions\n\nThe relationship of `laravel ORM` is very powerful, and the query `has` based on the relationship also provides us with many flexible calling methods. However, in some cases, `has` is implemented with **where exists** syntax.\n\nFor example:\n```php\n// User hasMany Post\nUser::has('posts')->get();\n```\n#### `select * from users where exists (select * from posts where users.id = posts.user_id)`\n> 'exists' is a loop to the external table, and then queries the internal table (subQuery) every time. Because the index used for the query of the internal table (the internal table is efficient, so it can be used as a large table), and how much of the external table needs to be traversed, it is inevitable (try to use a small table), so the use of exists for the large internal table can speed up the efficiency.\n\nWhen the **User** table has a large amount of data, there will be performance problems, so the **where in** syntax will greatly improve the performance.\n\n#### `select * from users where users.id in (select posts.user_id from posts)`\n> 'in' is to hash connect the appearance and inner table, first query the inner table, then match the result of the inner table with the appearance, and use the index for the outer table (the appearance is efficient, and large tables can be used). Most of the inner tables need to be queried, which is inevitable. Therefore, using 'in' with large appearance can speed up the efficiency.\n\nTherefore, the use of `has(hasMorph)` or `hasIn(hasMorphIn)` in code should be determined by **data size**\n\n```php\n/**\n * SQL:\n * \n * select * from `users` \n * where exists \n *   ( \n *      select * from `posts` \n *      where `users`.`id` = `posts`.`user_id` \n *   ) \n * limit 10 offset 0\n */\n$users = User::has('posts')->paginate(10);\n\n/**\n * SQL:\n * \n * select * from `users` \n * where `users`.`id` in  \n *   ( \n *      select `posts`.`user_id` from `posts` \n *   ) \n * limit 10 offset 0\n */\n$users = User::hasIn('posts')->paginate(10);\n```\n\n# Usage example\n\n`hasIn(hasMorphIn)` supports all `Relations` in `laravel ORM`. The call mode and internal implementation are completely consistent with `has(hasMorph)` of the framework.\n\n> hasIn\n\n```php\n// hasIn\nUser::hasIn('posts')->get();\n\n// orHasIn\nUser::where('age', '>', 18)->orHasIn('posts')->get();\n\n// doesntHaveIn\nUser::doesntHaveIn('posts')->get();\n\n// orDoesntHaveIn\nUser::where('age', '>', 18)->orDoesntHaveIn('posts')->get();\n```\n\n> whereHasIn\n\n```php\n// whereHasIn\nUser::whereHasIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// orWhereHasIn\nUser::where('age', '>', 18)->orWhereHasIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// whereDoesntHaveIn\nUser::whereDoesntHaveIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n\n// orWhereDoesntHaveIn\nUser::where('age', '>', 18)->orWhereDoesntHaveIn('posts', function ($query) {\n    $query->where('votes', '>', 10);\n})->get();\n```\n\n> hasMorphIn\n\n```php\nImage::hasMorphIn('imageable', [Post::class, Comment::class])->get();\n```\n\n### Nested Relation\n\n```php\nUser::hasIn('posts.comments')->get();\n```\n\n# Testing\n```bash\ncomposer test\n```\n>**Tips**: before testing, you need to configure your database connection in the `phpunit.xml.dist`.\n\n# License\n[MIT](./LICENSE)\n"
  },
  {
    "path": "_laravel_ide_helper.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\n{\n    use Closure;\n\n    if (false) {\n        class Builder\n        {\n            /**\n             * Add a relationship count / whereIn condition to the query.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\Relation|string  $relation\n             * @param  string  $operator\n             * @param  int  $count\n             * @param  string  $boolean\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @throws \\RuntimeException\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function hasIn($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with an \"or\".\n             *\n             * @param  string  $relation\n             * @param  string  $operator\n             * @param  int  $count\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orHasIn($relation, $operator = '>=', $count = 1)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query.\n             *\n             * @param  string  $relation\n             * @param  string  $boolean\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function doesntHaveIn($relation, $boolean = 'and', Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with an \"or\".\n             *\n             * @return Closure\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orDoesntHaveIn()\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with where clauses.\n             *\n             * @param  string  $relation\n             * @param  \\Closure|null  $callback\n             * @param  string  $operator\n             * @param  int  $count\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function whereHasIn($relation, Closure $callback = null, $operator = '>=', $count = 1)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with where clauses and an \"or\".\n             *\n             * @param  string  $relation\n             * @param  \\Closure|null  $callback\n             * @param  string  $operator\n             * @param  int  $count\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orWhereHasIn($relation, Closure $callback = null, $operator = '>=', $count = 1)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with where clauses.\n             *\n             * @param  string  $relation\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function whereDoesntHaveIn($relation, Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a relationship count / whereIn condition to the query with where clauses and an \"or\".\n             *\n             * @param  string  $relation\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orWhereDoesntHaveIn($relation, Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  string  $operator\n             * @param  int  $count\n             * @param  string  $boolean\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function hasMorphIn($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with an \"or\".\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  string  $operator\n             * @param  int  $count\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orHasMorphIn($relation, $types, $operator = '>=', $count = 1)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  string  $boolean\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function doesntHaveMorphIn($relation, $types, $boolean = 'and', Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with an \"or\".\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orDoesntHaveMorphIn($relation, $types)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with where clauses.\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             *\n             * @return Closure\n             */\n            public function whereHasMorphIn()\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with where clauses.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  \\Closure|null  $callback\n             * @param  string  $operator\n             * @param  int  $count\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orWhereHasMorphIn($relation, $types, Closure $callback = null, $operator = '>=', $count = 1)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with where clauses.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function whereDoesntHaveMorphIn($relation, $types, Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship count / whereIn condition to the query with where clauses and an \"or\".\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  \\Closure|null  $callback\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             *\n             * @see \\BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin\n             */\n            public function orWhereDoesntHaveMorphIn($relation, $types, Closure $callback = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a basic where clause to a relationship query.\n             *\n             * @param  string  $relation\n             * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n             * @param  mixed  $operator\n             * @param  mixed  $value\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             */\n            public function whereRelationIn($relation, $column, $operator = null, $value = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add an \"or where\" clause to a relationship query.\n             *\n             * @param  string  $relation\n             * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n             * @param  mixed  $operator\n             * @param  mixed  $value\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             */\n            public function orWhereRelationIn($relation, $column, $operator = null, $value = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship condition to the query with a where clause.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n             * @param  mixed  $operator\n             * @param  mixed  $value\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             */\n            public function whereMorphRelationIn($relation, $types, $column, $operator = null, $value = null)\n            {\n                return $this;\n            }\n\n            /**\n             * Add a polymorphic relationship condition to the query with an \"or where\" clause.\n             *\n             * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n             * @param  string|array  $types\n             * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n             * @param  mixed  $operator\n             * @param  mixed  $value\n             * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n             */\n            public function orWhereMorphRelationIn($relation, $types, $column, $operator = null, $value = null)\n            {\n                return $this;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"biiiiiigmonster/hasin\",\n    \"description\": \"Laravel framework relation has in implement\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"laravel\",\n        \"orm\",\n        \"relation\",\n        \"whereHas\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"YunFeng Lu\",\n            \"email\": \"603707288@qq.com\"\n        }\n    ],\n    \"require\": {\n        \"laravel/framework\": \"^12|^13.0\"\n    },\n    \"require-dev\": {\n        \"laravel/pint\": \"^1.1\",\n        \"orchestra/testbench\": \"^10.0|^11.0\",\n        \"pestphp/pest\": \"^3.0|^4.4\",\n        \"pestphp/pest-plugin-laravel\": \"^3.0|^4.1\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"BiiiiiigMonster\\\\Hasin\\\\\": \"src\",\n            \"BiiiiiigMonster\\\\Hasin\\\\Database\\\\Factories\\\\\": \"database/factories\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"BiiiiiigMonster\\\\Hasin\\\\Tests\\\\\": \"tests\"\n        }\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"BiiiiiigMonster\\\\Hasin\\\\HasinServiceProvider\"\n            ]\n        }\n    },\n    \"scripts\": {\n        \"test\": \"vendor/bin/pest\",\n        \"format\": \"vendor/bin/pint\"\n    },\n    \"config\": {\n        \"sort-packages\": true,\n        \"allow-plugins\": true\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "database/factories/CommentFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass CommentFactory extends Factory\n{\n    protected $model = Comment::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'content' => $this->faker->sentence,\n            'status' => $this->faker->numberBetween(0, 9),\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/CountryFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Country;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass CountryFactory extends Factory\n{\n    protected $model = Country::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'name' => $this->faker->country\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/HistoryFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\History;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass HistoryFactory extends Factory\n{\n    protected $model = History::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'content' => $this->faker->address\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/ImageFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Image;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass ImageFactory extends Factory\n{\n    protected $model = Image::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'url' => $this->faker->url\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/PhoneFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Phone;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass PhoneFactory extends Factory\n{\n    protected $model = Phone::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'phone_number' => $this->faker->phoneNumber\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/PostFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass PostFactory extends Factory\n{\n    protected $model = Post::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'title' => $this->faker->title,\n            'votes' => $this->faker->numberBetween(0, 100),\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/RoleFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Role;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass RoleFactory extends Factory\n{\n    protected $model = Role::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'name' => $this->faker->name\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/SupplierFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Supplier;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass SupplierFactory extends Factory\n{\n    protected $model = Supplier::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'name' => $this->faker->name\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/TagFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Tag;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass TagFactory extends Factory\n{\n    protected $model = Tag::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'name' => $this->faker->name\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/UserFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass UserFactory extends Factory\n{\n    protected $model = User::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'username' => $this->faker->userName,\n            'age' => $this->faker->numberBetween(10, 30),\n        ];\n    }\n}\n"
  },
  {
    "path": "database/factories/VideoFactory.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Factories;\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Video;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass VideoFactory extends Factory\n{\n    protected $model = Video::class;\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            'name' => $this->faker->name\n        ];\n    }\n}\n"
  },
  {
    "path": "database/migrations/create_hasin_test_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class () extends Migration {\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('histories', function (Blueprint $table) {\n            $table->id();\n            $table->bigInteger('user_id')->default(0);\n            $table->string('content');\n            $table->timestamps();\n        });\n        Schema::create('comments', function (Blueprint $table) {\n            $table->id();\n            $table->morphs('commentable');\n            $table->string('content');\n            $table->tinyInteger('status')->default(0);\n            $table->timestamps();\n        });\n        Schema::create('countries', function (Blueprint $table) {\n            $table->id();\n            $table->string('name')->default('');\n            $table->timestamps();\n        });\n        Schema::create('images', function (Blueprint $table) {\n            $table->id();\n            $table->string('url')->default('');\n            $table->morphs('imageable');\n            $table->timestamps();\n        });\n        Schema::create('phones', function (Blueprint $table) {\n            $table->id();\n            $table->bigInteger('user_id')->default(0);\n            $table->string('phone_number')->default('');\n            $table->timestamps();\n        });\n        Schema::create('roles', function (Blueprint $table) {\n            $table->id();\n            $table->string('name');\n            $table->timestamps();\n        });\n        Schema::create('role_user', function (Blueprint $table) {\n            $table->id();\n            $table->bigInteger('user_id')->default(0);\n            $table->bigInteger('role_id')->default(0);\n            $table->timestamps();\n        });\n        Schema::create('suppliers', function (Blueprint $table) {\n            $table->id();\n            $table->string('name')->default('');\n            $table->timestamps();\n        });\n        Schema::create('tags', function (Blueprint $table) {\n            $table->id();\n            $table->string('name')->default('');\n            $table->timestamps();\n        });\n        Schema::create('taggables', function (Blueprint $table) {\n            $table->id();\n            $table->bigInteger('tag_id')->default(0);\n            $table->morphs('taggable');\n            $table->timestamps();\n        });\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->string('username')->default('');\n            $table->tinyInteger('age')->default(0);\n            $table->bigInteger('country_id')->default(0);\n            $table->bigInteger('supplier_id')->default(0);\n            $table->timestamps();\n        });\n        Schema::create('videos', function (Blueprint $table) {\n            $table->id();\n            $table->string('name')->default('');\n            $table->timestamps();\n        });\n        Schema::create('posts', function (Blueprint $table) {\n            $table->id();\n            $table->bigInteger('user_id')->default(0);\n            $table->string('title')->default('');\n            $table->integer('votes')->default(0);\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('histories');\n        Schema::dropIfExists('comments');\n        Schema::dropIfExists('countries');\n        Schema::dropIfExists('images');\n        Schema::dropIfExists('phones');\n        Schema::dropIfExists('roles');\n        Schema::dropIfExists('role_user');\n        Schema::dropIfExists('suppliers');\n        Schema::dropIfExists('tags');\n        Schema::dropIfExists('taggables');\n        Schema::dropIfExists('users');\n        Schema::dropIfExists('videos');\n        Schema::dropIfExists('posts');\n    }\n};\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/10.0/phpunit.xsd\"\n    backupGlobals=\"false\"\n    bootstrap=\"vendor/autoload.php\"\n    colors=\"true\"\n    processIsolation=\"false\"\n    stopOnFailure=\"false\"\n    executionOrder=\"random\"\n    failOnWarning=\"true\"\n    failOnRisky=\"true\"\n    failOnEmptyTestSuite=\"true\"\n    beStrictAboutOutputDuringTests=\"true\"\n    cacheDirectory=\".phpunit.cache\"\n    backupStaticProperties=\"false\"\n>\n    <testsuites>\n        <testsuite name=\"Hasin Test Suite\">\n            <directory suffix=\"Test.php\">tests</directory>\n        </testsuite>\n    </testsuites>\n    <coverage>\n        <report>\n            <html outputDirectory=\"build/coverage\"/>\n            <text outputFile=\"build/coverage.txt\"/>\n            <clover outputFile=\"build/logs/clover.xml\"/>\n        </report>\n    </coverage>\n    <source>\n        <include>\n            <directory suffix=\".php\">./src</directory>\n        </include>\n    </source>\n    <logging>\n        <junit outputFile=\"build/report.junit.xml\"/>\n    </logging>\n    <php>\n        <env name=\"DB_HOST\" value=\"127.0.0.1\"/>\n        <env name=\"DB_PORT\" value=\"3306\"/>\n        <env name=\"DB_DATABASE\" value=\"laravel\"/>\n        <env name=\"DB_USERNAME\" value=\"root\"/>\n        <env name=\"DB_PASSWORD\" value=\"root\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "pint.json",
    "content": "{\n    \"preset\": \"psr12\",\n    \"exclude\": [\n        \"build\"\n    ]\n}\n"
  },
  {
    "path": "src/Database/Eloquent/BuilderMixin.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Eloquent;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Support\\Str;\n\nclass BuilderMixin\n{\n    /**\n     * Add a relationship count / whereIn condition to the query.\n     *\n     * @return Closure\n     */\n    public function hasIn(): Closure\n    {\n        return function ($relation, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            if (is_string($relation)) {\n                if (str_contains($relation, '.')) {\n                    return $this->hasInNested($relation, $operator, $count, $boolean, $callback);\n                }\n\n                $relation = $this->getRelationWithoutConstraints($relation);\n            }\n\n            if ($relation instanceof MorphTo) {\n                return $this->hasMorphIn($relation, ['*'], $operator, $count, $boolean, $callback);\n            }\n\n            // If we only need to check for the existence of the relation, then we can optimize\n            // the subquery to only run a \"where in\" clause instead of this full \"count\"\n            // clause. This will make these queries run much faster compared with a count.\n            $method = $this->canUseExistsForExistenceCheck($operator, $count)\n                            ? 'getRelationExistenceInQuery'\n                            : 'getRelationExistenceCountQuery';\n\n            $hasInQuery = $relation->{$method}(\n                $relation->getRelated()->newQueryWithoutRelationships(),\n                $this\n            );\n\n            // Next we will call any given callback as an \"anonymous\" scope so they can get the\n            // proper logical grouping of the where clauses if needed by this Eloquent query\n            // builder. Then, we will be ready to finalize and return this query instance.\n            if ($callback) {\n                $hasInQuery->callScope($callback);\n            }\n\n            return $this->addHasInWhere(\n                $hasInQuery,\n                $relation,\n                $operator,\n                $count,\n                $boolean\n            );\n        };\n    }\n\n    /**\n     * Add nested relationship count / whereIn conditions to the query.\n     *\n     * Sets up recursive call to whereHas until we finish the nested relation.\n     *\n     * @return Closure\n     */\n    protected function hasInNested(): Closure\n    {\n        return function ($relations, $operator = '>=', $count = 1, $boolean = 'and', $callback = null): Builder {\n            /** @var Builder $this */\n            $relations = explode('.', $relations);\n\n            $doesntHave = $operator === '<' && $count === 1;\n\n            if ($doesntHave) {\n                $operator = '>=';\n                $count = 1;\n            }\n\n            $closure = function ($q) use (&$closure, &$relations, $operator, $count, $callback) {\n                // In order to nest \"hasIn\", we need to add count relation constraints on the\n                // callback Closure. We'll do this by simply passing the Closure its own\n                // reference to itself so it calls itself recursively on each segment.\n                count($relations) > 1\n                    ? $q->whereHasIn(array_shift($relations), $closure)\n                    : $q->hasIn(array_shift($relations), $operator, $count, 'and', $callback);\n            };\n\n            return $this->hasIn(array_shift($relations), $doesntHave ? '<' : '>=', 1, $boolean, $closure);\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with an \"or\".\n     *\n     * @return Closure\n     */\n    public function orHasIn(): Closure\n    {\n        return function ($relation, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasIn($relation, $operator, $count, 'or');\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query.\n     *\n     * @return Closure\n     */\n    public function doesntHaveIn(): Closure\n    {\n        return function ($relation, $boolean = 'and', ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->hasIn($relation, '<', 1, $boolean, $callback);\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with an \"or\".\n     *\n     * @return Closure\n     */\n    public function orDoesntHaveIn(): Closure\n    {\n        return function ($relation): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveIn($relation, 'or');\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with where clauses.\n     *\n     * @return Closure\n     */\n    public function whereHasIn(): Closure\n    {\n        return function ($relation, ?Closure $callback = null, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasIn($relation, $operator, $count, 'and', $callback);\n        };\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with whereIn clauses.\n     *\n     * Also load the relationship with same condition.\n     *\n     * @return Closure\n     */\n    public function withWhereHasIn(): Closure\n    {\n        return function ($relation, ?Closure $callback = null, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->whereHasIn(Str::before($relation, ':'), $callback, $operator, $count)\n                ->with($callback ? [$relation => fn ($query) => $callback($query)] : $relation);\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with where clauses and an \"or\".\n     *\n     * @return Closure\n     */\n    public function orWhereHasIn(): Closure\n    {\n        return function ($relation, ?Closure $callback = null, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasIn($relation, $operator, $count, 'or', $callback);\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with where clauses.\n     *\n     * @return Closure\n     */\n    public function whereDoesntHaveIn(): Closure\n    {\n        return function ($relation, ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveIn($relation, 'and', $callback);\n        };\n    }\n\n    /**\n     * Add a relationship count / whereIn condition to the query with where clauses and an \"or\".\n     *\n     * @return Closure\n     */\n    public function orWhereDoesntHaveIn(): Closure\n    {\n        return function ($relation, ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveIn($relation, 'or', $callback);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query.\n     *\n     * @return Closure\n     */\n    public function hasMorphIn(): Closure\n    {\n        return function ($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            if (is_string($relation)) {\n                $relation = $this->getRelationWithoutConstraints($relation);\n            }\n\n            $types = (array) $types;\n\n            if ($types === ['*']) {\n                $types = $this->model->newModelQuery()->distinct()->pluck($relation->getMorphType())->filter()->all();\n            }\n\n            foreach ($types as &$type) {\n                $type = Relation::getMorphedModel($type) ?? $type;\n            }\n\n            return $this->where(function ($query) use ($relation, $callback, $operator, $count, $types) {\n                foreach ($types as $type) {\n                    $query->orWhere(function ($query) use ($relation, $callback, $operator, $count, $type) {\n                        $belongsTo = $this->getBelongsToRelation($relation, $type);\n\n                        if ($callback) {\n                            $callback = function ($query) use ($callback, $type) {\n                                return $callback($query, $type);\n                            };\n                        }\n\n                        $query->where($this->qualifyColumn($relation->getMorphType()), '=', (new $type())->getMorphClass())\n                            ->whereHasIn($belongsTo, $callback, $operator, $count);\n                    });\n                }\n            }, null, null, $boolean);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with an \"or\".\n     *\n     * @return Closure\n     */\n    public function orHasMorphIn(): Closure\n    {\n        return function ($relation, $types, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasMorphIn($relation, $types, $operator, $count, 'or');\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query.\n     *\n     * @return Closure\n     */\n    public function doesntHaveMorphIn(): Closure\n    {\n        return function ($relation, $types, $boolean = 'and', ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->hasMorphIn($relation, $types, '<', 1, $boolean, $callback);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with an \"or\".\n     *\n     * @return Closure\n     */\n    public function orDoesntHaveMorphIn(): Closure\n    {\n        return function ($relation, $types): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveMorphIn($relation, $types, 'or');\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with where clauses.\n     *\n     * @return Closure\n     */\n    public function whereHasMorphIn(): Closure\n    {\n        return function ($relation, $types, ?Closure $callback = null, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasMorphIn($relation, $types, $operator, $count, 'and', $callback);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with where clauses and an \"or\".\n     *\n     * @return Closure\n     */\n    public function orWhereHasMorphIn(): Closure\n    {\n        return function ($relation, $types, ?Closure $callback = null, $operator = '>=', $count = 1): Builder {\n            /** @var Builder $this */\n            return $this->hasMorphIn($relation, $types, $operator, $count, 'or', $callback);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with where clauses.\n     *\n     * @return Closure\n     */\n    public function whereDoesntHaveMorphIn(): Closure\n    {\n        return function ($relation, $types, ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveMorphIn($relation, $types, 'and', $callback);\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship count / whereIn condition to the query with where clauses and an \"or\".\n     *\n     * @return Closure\n     */\n    public function orWhereDoesntHaveMorphIn(): Closure\n    {\n        return function ($relation, $types, ?Closure $callback = null): Builder {\n            /** @var Builder $this */\n            return $this->doesntHaveMorphIn($relation, $types, 'or', $callback);\n        };\n    }\n\n    /**\n     * Add a basic where clause to a relationship query.\n     *\n     * @return Closure\n     */\n    public function whereRelationIn(): Closure\n    {\n        return function ($relation, $column, $operator = null, $value = null): Builder {\n            return $this->whereHasIn($relation, function ($query) use ($column, $operator, $value) {\n                if ($column instanceof Closure) {\n                    $column($query);\n                } else {\n                    $query->where($column, $operator, $value);\n                }\n            });\n        };\n    }\n\n    /**\n     * Add an \"or where\" clause to a relationship query.\n     *\n     * @return Closure\n     */\n    public function orWhereRelationIn(): Closure\n    {\n        return function ($relation, $column, $operator = null, $value = null): Builder {\n            return $this->orWhereHasIn($relation, function ($query) use ($column, $operator, $value) {\n                if ($column instanceof Closure) {\n                    $column($query);\n                } else {\n                    $query->where($column, $operator, $value);\n                }\n            });\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship condition to the query with a where clause.\n     *\n     * @return Closure\n     */\n    public function whereMorphRelationIn(): Closure\n    {\n        return function ($relation, $types, $column, $operator = null, $value = null): Builder {\n            return $this->whereHasMorphIn($relation, $types, function ($query) use ($column, $operator, $value) {\n                $query->where($column, $operator, $value);\n            });\n        };\n    }\n\n    /**\n     * Add a polymorphic relationship condition to the query with an \"or where\" clause.\n     *\n     * @return Closure\n     */\n    public function orWhereMorphRelationIn(): Closure\n    {\n        return function ($relation, $types, $column, $operator = null, $value = null): Builder {\n            return $this->orWhereHasMorphIn($relation, $types, function ($query) use ($column, $operator, $value) {\n                $query->where($column, $operator, $value);\n            });\n        };\n    }\n\n    /**\n     * Add the \"hasin\" condition whereIn clause to the query.\n     *\n     * @return Closure\n     */\n    protected function addHasInWhere(): Closure\n    {\n        return function (Builder $hasInQuery, Relation $relation, $operator, $count, $boolean): Builder {\n            /** @var Builder $this */\n            $hasInQuery->mergeConstraintsFrom($relation->getQuery());\n\n            return $this->canUseExistsForExistenceCheck($operator, $count)\n                ? $this->whereIn($relation->getRelationWhereInKey(), $hasInQuery->toBase(), $boolean, $operator === '<' && $count === 1)\n                : $this->addWhereCountQuery($hasInQuery->toBase(), $operator, $count, $boolean);\n        };\n    }\n}\n"
  },
  {
    "path": "src/Database/Eloquent/RelationMixin.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Database\\Eloquent;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOneOrMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOneOrManyThrough;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOneOrMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;\nuse LogicException;\n\nclass RelationMixin\n{\n    public function getRelationExistenceInQuery(): Closure\n    {\n        return function (Builder $query, Builder $parentQuery, $columns = ['*']): Builder {\n            $relation = function (Builder $query, Builder $parentQuery, $columns = ['*']): Builder {\n                return $query->select($columns);\n            };\n            // basic builder\n            $belongsTo = function (Builder $query, Builder $parentQuery) use ($relation): Builder {\n                $columns = $query->qualifyColumn($this->ownerKey);\n\n                $relationQuery = $relation($query, $parentQuery, $columns);\n\n                if ($parentQuery->getQuery()->from == $query->getQuery()->from) {\n                    $relationQuery->from(\n                        $query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()\n                    );\n\n                    $relationQuery->getModel()->setTable($hash);\n                }\n\n                return $relationQuery;\n            };\n            $belongsToMany = function (Builder $query, Builder $parentQuery) use ($relation): Builder {\n                $columns = $this->getExistenceCompareKey();\n                if ($parentQuery->getQuery()->from == $query->getQuery()->from) {\n                    $query->select($columns);\n\n                    $query->from($this->related->getTable().' as '.$hash = $this->getRelationCountHash());\n\n                    $this->related->setTable($hash);\n                }\n\n                $this->performJoin($query);\n\n                return $relation($query, $parentQuery, $columns);\n            };\n            $hasOneOrMany = function (Builder $query, Builder $parentQuery) use ($relation): Builder {\n                $columns = $this->getExistenceCompareKey();\n                if ($query->getQuery()->from == $parentQuery->getQuery()->from) {\n                    $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());\n\n                    $query->getModel()->setTable($hash);\n                }\n\n                return $relation($query, $parentQuery, $columns);\n            };\n            $hasOneOrManyThrough = function (Builder $query, Builder $parentQuery) use ($relation): Builder {\n                $columns = $this->getQualifiedFirstKeyName();\n                if ($parentQuery->getQuery()->from === $query->getQuery()->from) {\n                    $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());\n\n                    $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondKey);\n\n                    if ($this->throughParentSoftDeletes()) {\n                        $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn());\n                    }\n\n                    $query->getModel()->setTable($hash);\n\n                    return $relation($query, $parentQuery, $columns);\n                }\n\n                if ($parentQuery->getQuery()->from === $this->throughParent->getTable()) {\n                    $table = $this->throughParent->getTable().' as '.$hash = $this->getRelationCountHash();\n\n                    $query->join($table, $hash.'.'.$this->secondLocalKey, '=', $this->getQualifiedFarKeyName());\n\n                    if ($this->throughParentSoftDeletes()) {\n                        $query->whereNull($hash.'.'.$this->throughParent->getDeletedAtColumn());\n                    }\n\n                    return $relation($query, $parentQuery, $columns);\n                }\n\n                $this->performJoin($query);\n\n                return $relation($query, $parentQuery, $columns);\n            };\n            // extended builder\n            $hasOne = function (Builder $query, Builder $parentQuery) use ($hasOneOrMany): Builder {\n                if ($this->isOneOfMany()) {\n                    $this->mergeOneOfManyJoinsTo($query);\n                }\n\n                return $hasOneOrMany($query, $parentQuery);\n            };\n            $morphOneOrMany = function (Builder $query, Builder $parentQuery) use ($hasOneOrMany): Builder {\n                return $hasOneOrMany($query, $parentQuery)->where(\n                    $query->qualifyColumn($this->getMorphType()),\n                    $this->morphClass\n                );\n            };\n            $morphOne = function (Builder $query, Builder $parentQuery) use ($morphOneOrMany): Builder {\n                if ($this->isOneOfMany()) {\n                    $this->mergeOneOfManyJoinsTo($query);\n                }\n\n                return $morphOneOrMany($query, $parentQuery);\n            };\n            $morphToMany = function (Builder $query, Builder $parentQuery) use ($belongsToMany): Builder {\n                return $belongsToMany($query, $parentQuery)->where(\n                    $this->qualifyPivotColumn($this->morphType),\n                    $this->morphClass\n                );\n            };\n\n            return match (true) {\n                // extended relation\n                $this instanceof HasOne => $hasOne($query, $parentQuery),\n                $this instanceof MorphOne => $morphOne($query, $parentQuery),\n                $this instanceof MorphOneOrMany => $morphOneOrMany($query, $parentQuery),\n                $this instanceof MorphToMany => $morphToMany($query, $parentQuery),\n                // basic relation\n                $this instanceof BelongsTo => $belongsTo($query, $parentQuery),\n                $this instanceof BelongsToMany => $belongsToMany($query, $parentQuery),\n                $this instanceof HasOneOrMany => $hasOneOrMany($query, $parentQuery),\n                $this instanceof HasOneOrManyThrough => $hasOneOrManyThrough($query, $parentQuery),\n                default => throw new LogicException(\n                    sprintf('%s must be a relationship instance.', $this::class)\n                )\n            };\n        };\n    }\n\n    public function getRelationWhereInKey(): Closure\n    {\n        return fn (): string => match (true) {\n            $this instanceof BelongsTo => $this->getQualifiedForeignKeyName(),\n            $this instanceof HasOneOrMany, $this instanceof BelongsToMany => $this->getQualifiedParentKeyName(),\n            $this instanceof HasOneOrManyThrough => $this->getQualifiedLocalKeyName(),\n            default => throw new LogicException(\n                sprintf('%s must be a relationship instance.', $this::class)\n            )\n        };\n    }\n}\n"
  },
  {
    "path": "src/HasinServiceProvider.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin;\n\nuse BiiiiiigMonster\\Hasin\\Database\\Eloquent\\BuilderMixin;\nuse BiiiiiigMonster\\Hasin\\Database\\Eloquent\\RelationMixin;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass HasinServiceProvider extends ServiceProvider\n{\n    /**\n     * @throws \\ReflectionException\n     */\n    public function register()\n    {\n        // Eloquent\\Builder mixin, provides hasin series implementation.\n        Builder::mixin(new BuilderMixin());\n        // Eloquent\\Relation mixin, support for the bottom layer of hasin.\n        Relation::mixin(new RelationMixin());\n    }\n}\n"
  },
  {
    "path": "tests/Features/DoesntHaveInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('doesntHaveIn same as doesntHave', function () {\n    $doesntHave = User::doesntHave('posts')->orderBy('id')->pluck('id');\n    $doesntHaveIn = User::doesntHaveIn('posts')->orderBy('id')->pluck('id');\n\n    expect($doesntHave)->toEqual($doesntHaveIn);\n});\n\ntest('nested doesntHaveIn same as nested doesntHave', function () {\n    $doesntHave = User::doesntHave('posts.comments')->orderBy('id')->pluck('id');\n    $doesntHaveIn = User::doesntHaveIn('posts.comments')->orderBy('id')->pluck('id');\n\n    expect($doesntHave)->toEqual($doesntHaveIn);\n});\n"
  },
  {
    "path": "tests/Features/DoesntHaveMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('doesntHaveMorphIn same as doesntHaveMorph', function () {\n    $doesntHaveMorph = Comment::doesntHaveMorph('commentable', [Post::class])->orderBy('id')->pluck('id');\n    $doesntHaveMorphIn = Comment::doesntHaveMorphIn('commentable', [Post::class])->orderBy('id')->pluck('id');\n\n    expect($doesntHaveMorph)->toEqual($doesntHaveMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/HasInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Country;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Image;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Supplier;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Video;\n\ntest('HasMany: hasIn same as has', function () {\n    $has = User::has('posts')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('posts')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('HasOne: hasIn same as has', function () {\n    $has = User::has('phone')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('phone')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('BelongsTo: hasIn same as has', function () {\n    $has = User::has('country')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('country')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('BelongsToMany: hasIn same as has', function () {\n    $has = User::has('roles')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('roles')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('HasOneThrough: hasIn same as has', function () {\n    $has = Supplier::has('userHistory')->orderBy('id')->pluck('id');\n    $hasIn = Supplier::hasIn('userHistory')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('HasManyThrough: hasIn same as has', function () {\n    $has = Country::has('posts')->orderBy('id')->pluck('id');\n    $hasIn = Country::hasIn('posts')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('MorphOne: hasIn same as has', function () {\n    $has = User::has('image')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('image')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('MorphTo: hasIn same as has', function () {\n    $has = Image::has('imageable')->orderBy('id')->pluck('id');\n    $hasIn = Image::hasIn('imageable')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('MorphMany: hasIn same as has', function () {\n    $has = Video::has('comments')->orderBy('id')->pluck('id');\n    $hasIn = Video::hasIn('comments')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('MorphToMany: hasIn same as has', function () {\n    $has = Video::has('tags')->orderBy('id')->pluck('id');\n    $hasIn = Video::hasIn('tags')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('hasIn(gte 2) same as has(gte 2)', function () {\n    $has = User::has('posts', '>=', 2)->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('posts', '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('nested hasIn same as nested has', function () {\n    $has = User::has('posts.comments')->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('posts.comments')->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n\ntest('nested hasIn(gte 2) same as nested has(gte 2)', function () {\n    $has = User::has('posts.comments', '>=', 2)->orderBy('id')->pluck('id');\n    $hasIn = User::hasIn('posts.comments', '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($has)->toEqual($hasIn);\n});\n"
  },
  {
    "path": "tests/Features/HasMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('hasMorphIn same as hasMorph', function () {\n    $hasMorph = Comment::hasMorph('commentable', [Post::class])->orderBy('id')->pluck('id');\n    $hasMorphIn = Comment::hasMorphIn('commentable', [Post::class])->orderBy('id')->pluck('id');\n\n    expect($hasMorph)->toEqual($hasMorphIn);\n});\n\ntest('hasMorphIn(gte 2) same as hasMorph(gte 2)', function () {\n    $hasMorph = Comment::hasMorph('commentable', [Post::class], '>=', 2)->orderBy('id')->pluck('id');\n    $hasMorphIn = Comment::hasMorphIn('commentable', [Post::class], '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($hasMorph)->toEqual($hasMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/OrDoesntHaveInTest.php",
    "content": "<?php\n\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('orDoesntHaveIn same as orDoesntHave', function () {\n    $orDoesntHave = User::where('age', '>', 18)->orDoesntHave('posts')->orderBy('id')->pluck('id');\n    $orDoesntHaveIn = User::where('age', '>', 18)->orDoesntHaveIn('posts')->orderBy('id')->pluck('id');\n\n    expect($orDoesntHave)->toEqual($orDoesntHaveIn);\n});\n\ntest('nested orDoesntHaveIn same as nested orDoesntHave', function () {\n    $orDoesntHave = User::where('age', '>', 18)->orDoesntHave('posts.comments')->orderBy('id')->pluck('id');\n    $orDoesntHaveIn = User::where('age', '>', 18)->orDoesntHaveIn('posts.comments')->orderBy('id')->pluck('id');\n\n    expect($orDoesntHave)->toEqual($orDoesntHaveIn);\n});\n"
  },
  {
    "path": "tests/Features/OrDoesntHaveMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('orDoesntHaveMorphIn same as orDoesntHaveMorph', function () {\n    $orDoesntHaveMorph = Comment::where('status', '>', 2)->orDoesntHaveMorph('commentable', [Post::class])->orderBy('id')->pluck('id');\n    $orDoesntHaveMorphIn = Comment::where('status', '>', 2)->orDoesntHaveMorphIn('commentable', [Post::class])->orderBy('id')->pluck('id');\n\n    expect($orDoesntHaveMorph)->toEqual($orDoesntHaveMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/OrHasInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('orHasIn same as orHas', function () {\n    $orHas = User::where('age', '>', 18)->orHas('posts')->orderBy('id')->pluck('id');\n    $orHasIn = User::where('age', '>', 18)->orHasIn('posts')->orderBy('id')->pluck('id');\n\n    expect($orHas)->toEqual($orHasIn);\n});\n\ntest('orHasIn(gte 2) same as orHas(gte 2)', function () {\n    $orHas = User::where('age', '>', 18)->orHas('posts', '>=', 2)->orderBy('id')->pluck('id');\n    $orHasIn = User::where('age', '>', 18)->orHasIn('posts', '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($orHas)->toEqual($orHasIn);\n});\n\ntest('nested orHasIn same as nested orHas', function () {\n    $orHas = User::where('age', '>', 18)->orHas('posts.comments')->orderBy('id')->pluck('id');\n    $orHasIn = User::where('age', '>', 18)->orHasIn('posts.comments')->orderBy('id')->pluck('id');\n\n    expect($orHas)->toEqual($orHasIn);\n});\n\ntest('nested orHasIn(gte 2) same as nested orHas(gte 2)', function () {\n    $orHas = User::where('age', '>', 18)->orHas('posts.comments', '>=', 2)->orderBy('id')->pluck('id');\n    $orHasIn = User::where('age', '>', 18)->orHasIn('posts.comments', '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($orHas)->toEqual($orHasIn);\n});\n"
  },
  {
    "path": "tests/Features/OrHasMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('orHasMorphIn same as orHasMorph', function () {\n    $orHasMorph = Comment::where('status', '>', 2)->orHasMorph('commentable', [Post::class])->orderBy('id')->pluck('id');\n    $orHasMorphIn = Comment::where('status', '>', 2)->orHasMorphIn('commentable', [Post::class])->orderBy('id')->pluck('id');\n\n    expect($orHasMorph)->toEqual($orHasMorphIn);\n});\n\ntest('orHasMorphIn(gte 2) same as orHasMorph(gte 2)', function () {\n    $orHasMorph = Comment::where('status', '>', 2)->orHasMorph('commentable', [Post::class], '>=', 2)->orderBy('id')->pluck('id');\n    $orHasMorphIn = Comment::where('status', '>', 2)->orHasMorphIn('commentable', [Post::class], '>=', 2)->orderBy('id')->pluck('id');\n\n    expect($orHasMorph)->toEqual($orHasMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereDoesntHaveInTest.php",
    "content": "<?php\n\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('orWhereDoesntHaveIn same as orWhereDoesntHave', function () {\n    $orWhereDoesntHave = User::where('age', '>', 18)->orWhereDoesntHave('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n    $orWhereDoesntHaveIn = User::where('age', '>', 18)->orWhereDoesntHaveIn('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereDoesntHave)->toEqual($orWhereDoesntHaveIn);\n});\n\ntest('nested orWhereDoesntHaveIn same as nested orWhereDoesntHave', function () {\n    $orWhereDoesntHave = User::where('age', '>', 18)->orWhereDoesntHave('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n    $orWhereDoesntHaveIn = User::where('age', '>', 18)->orWhereDoesntHaveIn('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereDoesntHave)->toEqual($orWhereDoesntHaveIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereDoesntHaveMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('orWhereDoesntHaveMorphIn same as orWhereDoesntHaveMorph', function () {\n    $orWhereDoesntHaveMorph = Comment::where('status', '>', 2)->orWhereDoesntHaveMorph('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n    $orWhereDoesntHaveMorphIn = Comment::where('status', '>', 2)->orWhereDoesntHaveMorphIn('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereDoesntHaveMorph)->toEqual($orWhereDoesntHaveMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereHasInTest.php",
    "content": "<?php\n\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('orWhereHasIn same as orWhereHas', function () {\n    $orWhereHas = User::where('age', '>', 18)->orWhereHas('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n    $orWhereHasIn = User::where('age', '>', 18)->orWhereHasIn('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereHas)->toEqual($orWhereHasIn);\n});\n\ntest('nested orWhereHasIn same as nested orWhereHas', function () {\n    $orWhereHas = User::where('age', '>', 18)->orWhereHas('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n    $orWhereHasIn = User::where('age', '>', 18)->orWhereHasIn('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereHas)->toEqual($orWhereHasIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereHasMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('orWhereHasMorphIn same as orWhereHasMorph', function () {\n    $orWhereHasMorph = Comment::where('status', '>', 2)->orWhereHasMorph('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n    $orWhereHasMorphIn = Comment::where('status', '>', 2)->orWhereHasMorphIn('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n\n    expect($orWhereHasMorph)->toEqual($orWhereHasMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereMorphRelationInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('orWhereMorphRelationIn same as orWhereMorphRelationIn', function () {\n    $orWhereMorphRelation = Comment::where('status', '>=', 2)\n        ->orWhereMorphRelation('commentable', [Post::class], 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n    $orWhereMorphRelationIn = Comment::where('status', '>=', 2)\n        ->orWhereMorphRelationIn('commentable', [Post::class], 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n\n    expect($orWhereMorphRelation)->toEqual($orWhereMorphRelationIn);\n});\n"
  },
  {
    "path": "tests/Features/OrWhereRelationInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('orWhereRelationIn same as orWhereRelation', function () {\n    $orWhereRelation = User::where('age', '>', 18)\n        ->orWhereRelation('posts', 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n    $orWhereRelationIn = User::where('age', '>', 18)\n        ->orWhereRelationIn('posts', 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n\n    expect($orWhereRelation)->toEqual($orWhereRelationIn);\n});\n\ntest('nested whereRelationIn same as nested whereRelation', function () {\n    $orWhereRelation = User::where('age', '>', 18)\n        ->orWhereRelation('posts.comments', 'status', '>=', '2')\n        ->orderBy('id')->pluck('id');\n    $orWhereRelationIn = User::where('age', '>', 18)\n        ->orWhereRelationIn('posts.comments', 'status', '>=', '2')\n        ->orderBy('id')->pluck('id');\n\n    expect($orWhereRelation)->toEqual($orWhereRelationIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereDoesntHaveInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('whereDoesntHaveIn same as whereDoesntHave', function () {\n    $whereDoesntHave = User::whereDoesntHave('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n    $whereDoesntHaveIn = User::whereDoesntHaveIn('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n\n    expect($whereDoesntHave)->toEqual($whereDoesntHaveIn);\n});\n\ntest('nested whereDoesntHaveIn same as nested whereDoesntHave', function () {\n    $whereDoesntHave = User::whereDoesntHave('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n        ;\n    })->orderBy('id')->pluck('id');\n    $whereDoesntHaveIn = User::whereDoesntHaveIn('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n\n    expect($whereDoesntHave)->toEqual($whereDoesntHaveIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereDoesntHaveMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('whereDoesntHaveMorphIn same as whereDoesntHaveMorph', function () {\n    $whereDoesntHaveMorph = Comment::whereDoesntHaveMorph('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n    $whereDoesntHaveMorphIn = Comment::whereDoesntHaveMorphIn('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n\n    expect($whereDoesntHaveMorph)->toEqual($whereDoesntHaveMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereHasInTest.php",
    "content": "<?php\n\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('whereHasIn same as whereHas', function () {\n    $whereHas = User::whereHas('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n    $whereHasIn = User::whereHasIn('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->pluck('id');\n\n    expect($whereHas)->toEqual($whereHasIn);\n});\n\ntest('nested whereHasIn same as nested whereHas', function () {\n    $whereHas = User::whereHas('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n    $whereHasIn = User::whereHasIn('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->pluck('id');\n\n    expect($whereHas)->toEqual($whereHasIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereHasMorphInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('whereHasMorphIn same as whereHasMorph', function () {\n    $whereHasMorph = Comment::whereHasMorph('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n    $whereHasMorphIn = Comment::whereHasMorphIn('commentable', [Post::class], function ($query) {\n        $query->where('title', 'like', '%code%');\n    })->orderBy('id')->pluck('id');\n\n    expect($whereHasMorph)->toEqual($whereHasMorphIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereMorphRelationInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\n\ntest('whereMorphRelationIn same as whereMorphRelation', function () {\n    $whereMorphRelation = Comment::whereMorphRelation('commentable', [Post::class], 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n    $whereMorphRelationIn = Comment::whereMorphRelationIn('commentable', [Post::class], 'title', 'like', '%code%')\n        ->orderBy('id')->pluck('id');\n\n    expect($whereMorphRelation)->toEqual($whereMorphRelationIn);\n});\n"
  },
  {
    "path": "tests/Features/WhereRelationInTest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('whereRelationIn same as whereRelation', function () {\n    $whereRelation = User::whereRelation('posts', 'title', 'like', '%code%')->orderBy('id')->pluck('id');\n    $whereRelationIn = User::whereRelationIn('posts', 'title', 'like', '%code%')->orderBy('id')->pluck('id');\n\n    expect($whereRelation)->toEqual($whereRelationIn);\n});\n\ntest('nested whereRelationIn same as nested whereRelation', function () {\n    $whereRelation = User::whereRelation('posts.comments', 'status', '>=', '2')->orderBy('id')->pluck('id');\n    $whereRelationIn = User::whereRelationIn('posts.comments', 'status', '>=', '2')->orderBy('id')->pluck('id');\n\n    expect($whereRelation)->toEqual($whereRelationIn);\n});\n"
  },
  {
    "path": "tests/Features/WithWhereHasInTest.php",
    "content": "<?php\n\n\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\n\ntest('withWhereHasIn same as withWhereHas', function () {\n    $whereHas = User::withWhereHas('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->get();\n    $whereHasIn = User::withWhereHasIn('posts', function ($query) {\n        $query->where('votes', '>', 20);\n    })->orderBy('id')->get();\n\n    expect($whereHas->pluck('id'))->toEqual($whereHasIn->pluck('id'))\n        ->and($whereHas->pluck('posts.id'))->toEqual($whereHasIn->pluck('posts.id'));\n});\n\ntest('nested withWhereHasIn same as nested withWhereHas', function () {\n    $whereHas = User::withWhereHas('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->get();\n    $whereHasIn = User::withWhereHasIn('posts.comments', function ($query) {\n        $query->where('status', '>', 2);\n    })->orderBy('id')->get();\n\n    expect($whereHas->pluck('id'))->toEqual($whereHasIn->pluck('id'))\n        ->and($whereHas->pluck('posts.id'))->toEqual($whereHasIn->pluck('posts.id'))\n        ->and($whereHas->pluck('posts.comments.id'))->toEqual($whereHasIn->pluck('posts.comments.id'));\n});\n"
  },
  {
    "path": "tests/Models/Comment.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\n\nclass Comment extends Model\n{\n    use HasFactory;\n\n    public function commentable(): MorphTo\n    {\n        return $this->morphTo();\n    }\n}\n"
  },
  {
    "path": "tests/Models/Country.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough;\n\nclass Country extends Model\n{\n    use HasFactory;\n\n    public function posts(): HasManyThrough\n    {\n        return $this->hasManyThrough(Post::class, User::class);\n    }\n}\n"
  },
  {
    "path": "tests/Models/History.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass History extends Model\n{\n    use HasFactory;\n}\n"
  },
  {
    "path": "tests/Models/Image.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\n\nclass Image extends Model\n{\n    use HasFactory;\n\n    public function imageable(): MorphTo\n    {\n        return $this->morphTo();\n    }\n}\n"
  },
  {
    "path": "tests/Models/Phone.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Phone extends Model\n{\n    use HasFactory;\n}\n"
  },
  {
    "path": "tests/Models/Post.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;\n\nclass Post extends Model\n{\n    use HasFactory;\n\n    public function user(): BelongsTo\n    {\n        return $this->belongsTo(User::class);\n    }\n\n    public function image(): MorphOne\n    {\n        return $this->morphOne(Image::class, 'imageable');\n    }\n\n    public function comments(): MorphMany\n    {\n        return $this->morphMany(Comment::class, 'commentable');\n    }\n\n    public function tags(): MorphToMany\n    {\n        return $this->morphToMany(Tag::class, 'taggable')->using(Taggable::class);\n    }\n}\n"
  },
  {
    "path": "tests/Models/Role.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\n\nclass Role extends Model\n{\n    use HasFactory;\n\n    public function users(): BelongsToMany\n    {\n        return $this->belongsToMany(User::class)->using(RoleUser::class)->withTimestamps();\n    }\n}\n"
  },
  {
    "path": "tests/Models/RoleUser.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Relations\\Pivot;\n\nclass RoleUser extends Pivot\n{\n    use HasFactory;\n}\n"
  },
  {
    "path": "tests/Models/Supplier.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOneThrough;\n\nclass Supplier extends Model\n{\n    use HasFactory;\n\n    public function userHistory(): HasOneThrough\n    {\n        return $this->hasOneThrough(History::class, User::class);\n    }\n}\n"
  },
  {
    "path": "tests/Models/Tag.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;\n\nclass Tag extends Model\n{\n    use HasFactory;\n\n    public function posts(): MorphToMany\n    {\n        return $this->morphToMany(Post::class, 'taggable')->using(Taggable::class);\n    }\n\n    public function videos(): MorphToMany\n    {\n        return $this->morphToMany(Video::class, 'taggable')->using(Taggable::class);\n    }\n}\n"
  },
  {
    "path": "tests/Models/Taggable.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphPivot;\n\nclass Taggable extends MorphPivot\n{\n    use HasFactory;\n}\n"
  },
  {
    "path": "tests/Models/User.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOne;\n\nclass User extends Model\n{\n    use HasFactory;\n\n    public function country(): BelongsTo\n    {\n        return $this->belongsTo(Country::class);\n    }\n\n    public function supplier(): BelongsTo\n    {\n        return $this->belongsTo(Supplier::class);\n    }\n\n    public function phone(): HasOne\n    {\n        return $this->hasOne(Phone::class);\n    }\n\n    public function history(): HasOne\n    {\n        return $this->hasOne(History::class);\n    }\n\n    public function posts(): HasMany\n    {\n        return $this->hasMany(Post::class);\n    }\n\n    public function roles(): BelongsToMany\n    {\n        return $this->belongsToMany(Role::class)->using(RoleUser::class)->withTimestamps();\n    }\n\n    public function image(): MorphOne\n    {\n        return $this->morphOne(Image::class, 'imageable');\n    }\n}\n"
  },
  {
    "path": "tests/Models/Video.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;\n\nclass Video extends Model\n{\n    use HasFactory;\n\n    public function comments(): MorphMany\n    {\n        return $this->morphMany(Comment::class, 'commentable');\n    }\n\n    public function tags(): MorphToMany\n    {\n        return $this->morphToMany(Tag::class, 'taggable')->using(Taggable::class);\n    }\n}\n"
  },
  {
    "path": "tests/Pest.php",
    "content": "<?php\n\nuse BiiiiiigMonster\\Hasin\\Tests\\TestCase;\n\nuses(TestCase::class)->in(__DIR__);\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace BiiiiiigMonster\\Hasin\\Tests;\n\nuse BiiiiiigMonster\\Hasin\\HasinServiceProvider;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Comment;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Country;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\History;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Image;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Phone;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Post;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Role;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Supplier;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Tag;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\User;\nuse BiiiiiigMonster\\Hasin\\Tests\\Models\\Video;\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Orchestra\\Testbench\\TestCase as Orchestra;\n\nclass TestCase extends Orchestra\n{\n    private Migration $migration;\n\n    protected function getPackageProviders($app)\n    {\n        return [\n            HasinServiceProvider::class,\n        ];\n    }\n\n    protected function defineDatabaseMigrations()\n    {\n        $this->migration->up();\n    }\n\n    protected function destroyDatabaseMigrations()\n    {\n        $this->migration->down();\n    }\n\n    protected function defineDatabaseSeeders()\n    {\n        $tags = Tag::factory(20)->create();\n        $countries = Country::factory(15)->create();\n        $suppliers = Supplier::factory(15)->create();\n        $roles = Role::factory(10)->create();\n\n        $users = User::factory(15)\n            ->has(History::factory())\n            ->has(Phone::factory())\n            ->has(Image::factory(3))\n            ->hasAttached($roles->random(5))\n            ->sequence(fn () => ['country_id' => $countries->pluck('id')->random()])\n            ->sequence(fn () => ['supplier_id' => $suppliers->pluck('id')->random()])\n            ->create();\n\n        $posts = Post::factory(15)\n            ->sequence(fn () => ['user_id' => $users->pluck('id')->random()])\n            ->hasAttached($tags->random(15))\n            ->create();\n\n        $videos = Video::factory(15)->hasAttached($tags->random(15))->create();\n\n        $posts->random(5)->map(function ($post) {\n            Comment::factory(3)->for($post, 'commentable')->create();\n            Image::factory(2)->for($post, 'imageable')->create();\n        });\n\n        $videos->random(5)->map(function ($video) {\n            Comment::factory(3)->for($video, 'commentable')->create();\n        });\n    }\n\n    public function getEnvironmentSetUp($app)\n    {\n        config()->set('database.connections.mysql.prefix', 'hasin_test_');\n\n        Schema::defaultStringLength(191);\n        Factory::guessFactoryNamesUsing(\n            fn (string $modelName) => 'BiiiiiigMonster\\\\Hasin\\\\Database\\\\Factories\\\\'.class_basename($modelName).'Factory'\n        );\n\n        $this->migration = include __DIR__.'/../database/migrations/create_hasin_test_table.php';\n    }\n}\n"
  }
]