├── .styleci.yml ├── changelog.md ├── composer.json ├── contributing.md ├── license.md ├── phpunit.xml ├── readme.md └── src ├── EloquentJsonMacros.php ├── EloquentJsonMacrosServiceProvider.php └── Macros ├── jsonContains.php ├── json_array_append.php ├── json_array_insert.php ├── json_insert.php ├── json_remove.php ├── json_replace.php ├── json_set.php ├── orJsonContains.php ├── orWhereJsonContainsPath.php ├── orWhereJsonDepth.php ├── orWhereJsonExtract.php ├── orWhereJsonLength.php ├── selectJsonDepth.php ├── selectJsonLength.php ├── whereJsonContainsPath.php ├── whereJsonDepth.php ├── whereJsonExtract.php └── whereJsonLength.php /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `EloquentJsonMacros` will be documented in this file. 4 | 5 | ## Version 1.0 6 | 7 | ### Added 8 | - Everything 9 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aidynmakhataev/eloquent-json-macros", 3 | "description": "A Laravel Eloquent Builder macros for MySQL JSON functions", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Aidyn Makhataev", 8 | "email": "makataev.7@gmail.com", 9 | "homepage": "https://github.com/AidynMakhataev" 10 | } 11 | ], 12 | "homepage": "https://github.com/AidynMakhataev/eloquent-json-macros", 13 | "keywords": ["Laravel", "EloquentJsonMacros", "Eloquent Json"], 14 | "require": { 15 | "illuminate/support": "~5" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "~6.0", 19 | "orchestra/testbench": "~3.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "AidynMakhataev\\EloquentJsonMacros\\": "src/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "AidynMakhataev\\EloquentJsonMacros\\Tests\\": "tests" 29 | } 30 | }, 31 | "extra": { 32 | "laravel": { 33 | "providers": [ 34 | "AidynMakhataev\\EloquentJsonMacros\\EloquentJsonMacrosServiceProvider" 35 | ] 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome and will be fully credited. 4 | 5 | Contributions are accepted via Pull Requests on [Github](https://github.com/aidynmakhataev/eloquentjsonmacros). 6 | 7 | # Things you could do 8 | If you want to contribute but do not know where to start, this list provides some starting points. 9 | - Add license text 10 | - Remove rewriteRules.php 11 | - Set up TravisCI, StyleCI, ScrutinizerCI 12 | - Write a comprehensive ReadMe 13 | 14 | ## Pull Requests 15 | 16 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 17 | 18 | - **Document any change in behaviour** - Make sure the `readme.md` and any other relevant documentation are kept up-to-date. 19 | 20 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 21 | 22 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 23 | 24 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 25 | 26 | 27 | **Happy coding**! 28 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # The license 2 | 3 | Copyright (c) author name 4 | 5 | ...Add your license text here... -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | src/ 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

Laravel Eloquent JSON Macros

2 | 3 |

This package helps you to use MySQL JSON functions in Eloquent style and as helper functions.

4 | 5 |

6 | Latest Stable Version 7 | Latest Unstable Version 8 | 9 | Total Downloads 10 | License 11 |

12 | 13 | ## Installation 14 | 15 | You can install the package using composer 16 | 17 | ```sh 18 | $ composer require aidynmakhataev/eloquent-json-macros 19 | ``` 20 | 21 | ## Features 22 | 23 | - Support macros: 24 | - [`jsonContains`](#jsonContains) 25 | - [`orJsonContains`](#orJsonContains) 26 | - [`whereJsonContainsPath`](#whereJsonContainsPath) 27 | - [`orWhereJsonContainsPath`](#orWhereJsonContainsPath) 28 | - [`whereJsonDepth`](#whereJsonDepth) 29 | - [`orWhereJsonDepth`](#orWhereJsonDepth) 30 | - [`whereJsonExtract`](#whereJsonExtract) 31 | - [`orWhereJsonExtract`](#orWhereJsonExtract) 32 | - [`whereJsonLength`](#whereJsonLength) 33 | - [`orWhereJsonLength`](#orWhereJsonLength) 34 | - [`selectJsonDepth`](#selectJsonDepth) 35 | - [`selectJsonLength`](#selectJsonLength) 36 | 37 | - Available helpers: 38 | - json_array_append 39 | - json_array_insert 40 | - json_insert 41 | - json_remove 42 | - json_replace 43 | - json_set 44 | 45 | ## Usage 46 | 47 | Let's say we have a table `events` with json columns - `browser` and `members`; 48 | 49 | ###### Browser (dummy json object) 50 | ```json 51 | {"os": "Windows", "name": "Safari", "resolution": {"x": 1920, "y": 1080}} 52 | ``` 53 | 54 | ###### Members (dummy json array) 55 | 56 | ```json 57 | [{"id": 6, "info": {"job": "Electrolytic Plating Machine Operator", "email": "prohaska.mervin@example.net", "card_type": "Visa"}, "name": "Prof. Eldridge Legros"}, {"id": 8, "info": {"job": "Urban Planner", "email": "casandra54@example.org", "card_type": "Master Card"}, "name": "Ms. Alayna Ziemann DDS"}] 58 | ``` 59 | 60 | 61 | 62 | ### `jsonContains` 63 | 64 | Add where 'JSON_CONTAINS' clause to the query for indicates whether JSON document contains specific object at path 65 | 66 | More on: [https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-contains](https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-contains) 67 | 68 | ##### Example (for `browser`json object column) 69 | ```php 70 | use App\Models\Event; 71 | 72 | Event::jsonContains('browser->os', 'Windows')->get(); 73 | Event::jsonContains('browser->resolution.x', 1920)->get(); 74 | 75 | ``` 76 | 77 | ##### Example (for `member`json array column) 78 | 79 | ```php 80 | use App\Models\Event; 81 | 82 | Event::jsonContains('members->[*].id', 6)->get(); 83 | Event::jsonContains('members->[1].info.email', 'casandra54@example.org')->get(); 84 | 85 | ``` 86 | 87 | ### `orJsonContains` 88 | 89 | Add an orWhere 'JSON_CONTAINS' clause to the query for indicates whether JSON document contains specific object at path 90 | 91 | Usage will be same as in [`jsonContains`](#jsonContains) macro; 92 | 93 | ### `whereJsonContainsPath` 94 | 95 | Add a where 'JSON_CONTAINS_PATH' clause to the query for indicates whether JSON document contains any data at path 96 | 97 | More on: [https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-contains-path](https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-contains-path) 98 | 99 | ##### Example (for `browser`json object column) 100 | 101 | For single path 102 | ```php 103 | Event::whereJsonContainsPath('browser', 'resolution')->get(); 104 | 105 | ``` 106 | For multiple path 107 | 108 | ```php 109 | Event::whereJsonContainsPath('browser', ['resolution', 'os'])->get(); 110 | 111 | ``` 112 | 113 | You can also optionally pass a third parameter ('one' or 'all'), by default used 'one' 114 | 115 | ```php 116 | Event::whereJsonContainsPath('browser', ['resolution', 'test'], 'all')->get(); 117 | 118 | ``` 119 | 120 | 121 | ##### Example (for `member`json array column) 122 | 123 | ```php 124 | Event::whereJsonContainsPath('members', '[*].info')->get(); 125 | Event::whereJsonContainsPath('members', ['[*].info', '[1].test'])->get(); 126 | ``` 127 | 128 | ### `orWhereJsonContainsPath` 129 | Add an orWhere 'JSON_CONTAINS_PATH' clause to the query for indicates whether JSON document contains any data at path 130 | 131 | Usage will be same as in [`whereJsonContainsPath`](#whereJsonContainsPath) macro; 132 | 133 | 134 | ### `whereJsonDepth` 135 | Add a where 'JSON_DEPTH' clause to the query for indicates depth of JSON document 136 | 137 | More on: [https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html#function_json-depth](https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html#function_json-depth) 138 | 139 | ##### Example (for `browser`json object column) 140 | ```php 141 | Event::whereJsonDepth('browser->resolution', '>', 1)->get(); 142 | Event::whereJsonDepth('browser->os', 2)->get(); 143 | Event::whereJsonDepth('browser->resolution.x', '<=', 1)->get(); 144 | 145 | ``` 146 | 147 | ##### Example (for `member`json array column) 148 | 149 | ```php 150 | Event::whereJsonDepth('members->[*].info.job', '>=', 1)->get(); 151 | Event::whereJsonDepth('members->[1].info.phones[0].fax', '>', 0)->get(); 152 | 153 | ``` 154 | 155 | ### `orWhereJsonDepth` 156 | 157 | Add an orWhere 'JSON_DEPTH' clause to the query for indicates depth of JSON document 158 | 159 | Usage will be same as in [`whereJsonDepth`](#whereJsonDepth) macro; 160 | 161 | ### `whereJsonExtract` 162 | 163 | Add a where "JSON_EXTRACT" clause to the query. 164 | 165 | More on: [https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-extract](https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-extract) 166 | 167 | ##### Example (for `browser`json object column) 168 | ```php 169 | Event::whereJsonExtract('browser->resolution.x', '>', 1500)->get(); 170 | Event::whereJsonExtract('browser->name', 'Mozilla Firefox')->get(); 171 | 172 | ``` 173 | 174 | ##### Example (for `member`json array column) 175 | 176 | ```php 177 | Event::whereJsonExtract('members->[0].id', '>=', 9)->get(); 178 | Event::whereJsonExtract('members->[*].info.job', 'LIKE', '%Cleaners%')->get(); 179 | 180 | ``` 181 | 182 | ### `orWhereJsonExtract` 183 | 184 | Add an orWhere "JSON_EXTRACT" clause to the query. 185 | 186 | Usage will be same as in [`whereJsonExtract`](#whereJsonExtract) macro; 187 | 188 | ### `whereJsonLength` 189 | Add a where 'JSON_LENGTH' clause to the query. 190 | 191 | More on: [https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html#function_json-length](https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html#function_json-length) 192 | 193 | ##### Example (for `browser`json object column) 194 | ```php 195 | Event::whereJsonLength('browser->resolution', '>', 1)->get(); 196 | Event::whereJsonLength('browser->os', 4)->get(); 197 | Event::whereJsonLength('browser->resolution.x', '>=', 1)->get(); 198 | 199 | ``` 200 | 201 | ##### Example (for `member`json array column) 202 | 203 | ```php 204 | Event::whereJsonLength('members->[*]', '>=', 1)->get(); 205 | Event::whereJsonLength('members->[1].info.phones[*].fax', '>', 0)->get(); 206 | 207 | ``` 208 | 209 | ### `orWhereJsonLength` 210 | 211 | Add an orWhere 'JSON_LENGTH' clause to the query 212 | 213 | Usage will be same as in [`whereJsonLength`](#whereJsonLength) macro; 214 | 215 | 216 | 217 | ### TODO EXPLANATION FOR OTHER MACROS AND HELPERS 218 | 219 | ## Contributing 220 | 221 | 1. Fork it () 222 | 2. Create your feature branch (`git checkout -b feature/fooBar`) 223 | 3. Commit your changes (`git commit -am 'Add some fooBar'`) 224 | 4. Push to the branch (`git push origin feature/fooBar`) 225 | 5. Create a new Pull Request 226 | 227 | 228 | ## Security 229 | 230 | If you discover any security related issues, please email makataev.7@gmail.com instead of using the issue tracker. 231 | 232 | 233 | ## License 234 | 235 | MIT -------------------------------------------------------------------------------- /src/EloquentJsonMacros.php: -------------------------------------------------------------------------------- 1 | ')) { 62 | list($column, $jsonPath) = explode('->', $path); 63 | } else { 64 | list($column, $jsonPath) = ['', $path]; 65 | } 66 | switch ($type) { 67 | case 'json_extract': 68 | return [$column, self::formatJsonPath($jsonPath)]; 69 | break; 70 | default: 71 | if (strlen($column) > 0) { 72 | return "$column->'".self::formatJsonPath($jsonPath)."'"; 73 | } 74 | 75 | return $path; 76 | 77 | break; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/EloquentJsonMacrosServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapWithKeys(function ($path) { 19 | return [$path => pathinfo($path, PATHINFO_FILENAME)]; 20 | }) 21 | ->reject(function ($macro) { 22 | return Collection::hasMacro($macro); 23 | }) 24 | ->each(function ($macro, $path) { 25 | require_once $path; 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Macros/jsonContains.php: -------------------------------------------------------------------------------- 1 | whereRaw("JSON_CONTAINS($path, $needle)"); 20 | }); 21 | -------------------------------------------------------------------------------- /src/Macros/json_array_append.php: -------------------------------------------------------------------------------- 1 | $item) { 20 | $path[$key] = "'".EloquentJsonMacros::formatJsonPath($item)."'"; 21 | } 22 | $path = implode(',', $path); 23 | } else { 24 | $path = "'".EloquentJsonMacros::formatJsonPath($path)."'"; 25 | } 26 | 27 | $raw = DB::raw("JSON_REMOVE($column, $path)"); 28 | 29 | return $raw; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Macros/json_replace.php: -------------------------------------------------------------------------------- 1 | orWhereRaw("JSON_CONTAINS($path, $needle)"); 20 | }); 21 | -------------------------------------------------------------------------------- /src/Macros/orWhereJsonContainsPath.php: -------------------------------------------------------------------------------- 1 | $item) { 18 | $path[$key] = "'".EloquentJsonMacros::formatJsonPath($item)."'"; 19 | } 20 | $path = implode(',', $path); 21 | } else { 22 | $path = "'".EloquentJsonMacros::formatJsonPath($path)."'"; 23 | } 24 | 25 | return $this->orWhereRaw("JSON_CONTAINS_PATH($column, '$oneOrAll', $path)"); 26 | }); 27 | -------------------------------------------------------------------------------- /src/Macros/orWhereJsonDepth.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->orWhereRaw("JSON_DEPTH($path) $operator :value", [ 23 | 'value' => $value 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Macros/orWhereJsonExtract.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->whereRaw("JSON_UNQUOTE(JSON_EXTRACT($column, '$path')) $operator :value", [ 23 | 'value' => $value 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Macros/orWhereJsonLength.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->orWhereRaw("JSON_LENGTH($path) $operator :value", [ 23 | 'value' => $value 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Macros/selectJsonDepth.php: -------------------------------------------------------------------------------- 1 | selectRaw("JSON_DEPTH($path) AS $resultName"); 18 | }); 19 | -------------------------------------------------------------------------------- /src/Macros/selectJsonLength.php: -------------------------------------------------------------------------------- 1 | selectRaw("JSON_LENGTH($path) AS $resultName"); 18 | }); 19 | -------------------------------------------------------------------------------- /src/Macros/whereJsonContainsPath.php: -------------------------------------------------------------------------------- 1 | $item) { 18 | $path[$key] = "'".EloquentJsonMacros::formatJsonPath($item)."'"; 19 | } 20 | $path = implode(',', $path); 21 | } else { 22 | $path = "'".EloquentJsonMacros::formatJsonPath($path)."'"; 23 | } 24 | 25 | return $this->whereRaw("JSON_CONTAINS_PATH($column, '$oneOrAll', $path)"); 26 | }); 27 | -------------------------------------------------------------------------------- /src/Macros/whereJsonDepth.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->whereRaw("JSON_DEPTH($path) $operator :value", [ 23 | 'value' => $value 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Macros/whereJsonExtract.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->whereRaw("JSON_UNQUOTE(JSON_EXTRACT($column, '$path')) $operator :value", [ 23 | 'value' => $value 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Macros/whereJsonLength.php: -------------------------------------------------------------------------------- 1 | getQuery()->prepareValueAndOperator( 19 | $value, $operator, func_num_args() === 2 20 | ); 21 | 22 | return $this->whereRaw("JSON_LENGTH($path) $operator '$value'"); 23 | }); 24 | --------------------------------------------------------------------------------