From fa14e03136d31c23046ca82b59e1b49619630fbe Mon Sep 17 00:00:00 2001 From: Nahid Bin Azhar Date: Sun, 23 Aug 2020 00:28:09 +0600 Subject: [PATCH 1/2] Migrate all features from the QArray --- composer.json | 14 +- config/jsonq.php | 7 - examples/index.php | 13 +- helpers/jsonq.php | 11 + src/Condition.php | 280 ------- .../ConditionNotAllowedException.php | 11 - src/Exceptions/FileNotFoundException.php | 11 - src/Exceptions/InvalidJsonException.php | 11 - src/Exceptions/InvalidNodeException.php | 11 - src/Exceptions/NullValueException.php | 11 - src/Facades/Jsonq.php | 18 - src/JsonQueriable.php | 650 --------------- src/Jsonq.php | 745 +----------------- src/JsonqServiceProvider.php | 83 -- src/Results/ValueNotFound.php | 9 - tests/Facades/Jsonq.php | 44 -- tests/JsonqServiceProviderTest.php | 19 - tests/TestCase.php | 24 - 18 files changed, 62 insertions(+), 1910 deletions(-) delete mode 100644 config/jsonq.php create mode 100644 helpers/jsonq.php delete mode 100644 src/Condition.php delete mode 100644 src/Exceptions/ConditionNotAllowedException.php delete mode 100644 src/Exceptions/FileNotFoundException.php delete mode 100644 src/Exceptions/InvalidJsonException.php delete mode 100644 src/Exceptions/InvalidNodeException.php delete mode 100644 src/Exceptions/NullValueException.php delete mode 100644 src/Facades/Jsonq.php delete mode 100644 src/JsonQueriable.php delete mode 100644 src/JsonqServiceProvider.php delete mode 100644 src/Results/ValueNotFound.php delete mode 100644 tests/Facades/Jsonq.php delete mode 100644 tests/JsonqServiceProviderTest.php delete mode 100644 tests/TestCase.php diff --git a/composer.json b/composer.json index 12fdb56..319e3ad 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "keywords": ["json", "jsonq", "query"], "homepage": "https://github.com/nahid/jsonq", "type": "library", - "license": "CC0-1.0", + "license": "MIT", "authors": [ { "name": "Nahid Bin Azhar", @@ -12,17 +12,21 @@ } ], "require": { - "php": ">=5.5.0" + "php": ">=5.6", + "ext-json": "*", + "nahid/qarray": "^2.0" }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.0", - "symfony/var-dumper": "^3.4", - "graham-campbell/testbench": "^3.1" + "symfony/var-dumper": "^3.4" }, "autoload": { "psr-4": { "Nahid\\JsonQ\\": "src/" - } + }, + "files": [ + "helpers/jsonq.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/config/jsonq.php b/config/jsonq.php deleted file mode 100644 index f1020c5..0000000 --- a/config/jsonq.php +++ /dev/null @@ -1,7 +0,0 @@ -[ - 'storage_path'=>database_path() - ] -]; \ No newline at end of file diff --git a/examples/index.php b/examples/index.php index 28bd17f..295f135 100755 --- a/examples/index.php +++ b/examples/index.php @@ -15,15 +15,20 @@ //}); // -$jq = new Jsonq('data.json'); +//$jq = new Jsonq('data.json'); try { - $result = $jq->from('users') + $data = file_get_contents('data.json'); + // This will remove unwanted characters. +// Check http://www.php.net/chr for details + + $result = jsonq($data) + ->from('users') ->where('visits.year', '=', 2010) - ->sum('visits.year'); + ->get(); dump($result); } catch (\Nahid\JsonQ\Exceptions\ConditionNotAllowedException $e) { } catch (\Nahid\JsonQ\Exceptions\NullValueException $e) { -} \ No newline at end of file +} diff --git a/helpers/jsonq.php b/helpers/jsonq.php new file mode 100644 index 0000000..b2318c0 --- /dev/null +++ b/helpers/jsonq.php @@ -0,0 +1,11 @@ +collect($json->parseData($jsonData)); + } +} diff --git a/src/Condition.php b/src/Condition.php deleted file mode 100644 index b98b656..0000000 --- a/src/Condition.php +++ /dev/null @@ -1,280 +0,0 @@ - $comparable; - } - - /** - * Strict less than - * - * @param mixed $value - * @param mixed $comparable - * - * @return bool - */ - public static function lessThan($value, $comparable) - { - return $value < $comparable; - } - - /** - * Greater or equal - * - * @param mixed $value - * @param mixed $comparable - * - * @return bool - */ - public static function greaterThanOrEqual($value, $comparable) - { - return $value >= $comparable; - } - - /** - * Less or equal - * - * @param mixed $value - * @param mixed $comparable - * - * @return bool - */ - public static function lessThanOrEqual($value, $comparable) - { - return $value <= $comparable; - } - - /** - * In array - * - * @param mixed $value - * @param array $comparable - * - * @return bool - */ - public static function in($value, $comparable) - { - return (is_array($comparable) && in_array($value, $comparable)); - } - - /** - * Not in array - * - * @param mixed $value - * @param array $comparable - * - * @return bool - */ - public static function notIn($value, $comparable) - { - return (is_array($comparable) && !in_array($value, $comparable)); - } - - /** - * Is null equal - * - * @param mixed $value - * - * @return bool - */ - public static function isNull($value, $comparable) - { - return is_null($value); - } - - /** - * Is not null equal - * - * @param mixed $value - * - * @return bool - */ - public static function isNotNull($value, $comparable) - { - return !is_null($value); - } - - /** - * Start With - * - * @param mixed $value - * @param string $comparable - * - * @return bool - */ - public static function startWith($value, $comparable) - { - if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) { - return false; - } - - if (preg_match("/^$comparable/", $value)) { - return true; - } - - return false; - } - - /** - * End with - * - * @param mixed $value - * @param string $comparable - * - * @return bool - */ - public static function endWith($value, $comparable) - { - if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) { - return false; - } - - if (preg_match("/$comparable$/", $value)) { - return true; - } - - return false; - } - - /** - * Match with pattern - * - * @param mixed $value - * @param string $comparable - * - * @return bool - */ - public static function match($value, $comparable) - { - if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) { - return false; - } - - $comparable = trim($comparable); - - if (preg_match("/^$comparable$/", $value)) { - return true; - } - - return false; - } - - /** - * Contains substring in string - * - * @param string $value - * @param string $comparable - * - * @return bool - */ - public static function contains($value, $comparable) - { - return (strpos($value, $comparable) !== false); - } - - /** - * Dates equal - * - * @param string $value - * @param string $comparable - * - * @return bool - */ - public static function dateEqual($value, $comparable, $format = 'Y-m-d') - { - $date = date($format, strtotime($value)); - return $date == $comparable; - } - - /** - * Months equal - * - * @param string $value - * @param string $comparable - * - * @return bool - */ - public static function monthEqual($value, $comparable) - { - $month = date('m', strtotime($value)); - return $month == $comparable; - } - - /** - * Years equal - * - * @param string $value - * @param string $comparable - * - * @return bool - */ - public static function yearEqual($value, $comparable) - { - $year = date('Y', strtotime($value)); - return $year == $comparable; - } -} diff --git a/src/Exceptions/ConditionNotAllowedException.php b/src/Exceptions/ConditionNotAllowedException.php deleted file mode 100644 index 50fa64a..0000000 --- a/src/Exceptions/ConditionNotAllowedException.php +++ /dev/null @@ -1,11 +0,0 @@ - 'equal', - 'eq' => 'equal', - '==' => 'strictEqual', - 'seq' => 'strictEqual', - '!=' => 'notEqual', - 'neq' => 'notEqual', - '!==' => 'strictNotEqual', - 'sneq' => 'strictNotEqual', - '>' => 'greaterThan', - 'gt' => 'greaterThan', - '<' => 'lessThan', - 'lt' => 'lessThan', - '>=' => 'greaterThanOrEqual', - 'gte' => 'greaterThanOrEqual', - '<=' => 'lessThanOrEqual', - 'lte' => 'lessThanOrEqual', - 'in' => 'in', - 'notin' => 'notIn', - 'null' => 'isNull', - 'notnull' => 'isNotNull', - 'startswith' => 'startWith', - 'endswith' => 'endWith', - 'match' => 'match', - 'contains' => 'contains', - 'dates' => 'dateEqual', - 'month' => 'monthEqual', - 'year' => 'yearEqual', - ]; - - - /** - * import data from file - * - * @param string|null $file - * @return bool - * @throws FileNotFoundException - * @throws InvalidJsonException - */ - public function import($file = null) - { - if (!is_null($file)) { - if (is_string($file) && file_exists($file)) { - $this->_map = $this->getDataFromFile($file); - $this->_baseContents = $this->_map; - return true; - } - } - - throw new FileNotFoundException(); - } - - /** - * Prepare data from desire conditions - * - * @return $this - * @throws ConditionNotAllowedException - */ - protected function prepare() - { - if ($this->_isProcessed) { - return $this; - } - - if (count($this->_conditions) > 0) { - $calculatedData = $this->processConditions(); - $this->_map = $this->objectToArray($calculatedData); - - $this->_conditions = []; - $this->_node = ''; - $this->_isProcessed = true; - return $this; - } - - $this->_isProcessed = true; - $this->_map = $this->objectToArray($this->getData()); - return $this; - } - - /** - * Our system will cache processed data and prevend multiple time processing. If - * you want to reprocess this method can help you - * - * @return $this - */ - public function reProcess() - { - $this->_isProcessed = false; - return $this; - } - - /** - * Parse object to array - * - * @param object $obj - * @return array|mixed - */ - protected function objectToArray($obj) - { - if (!is_array($obj) && !is_object($obj)) { - return $obj; - } - - if (is_array($obj)) { - return $obj; - } - - if (is_object($obj)) { - $obj = get_object_vars($obj); - } - - return array_map([$this, 'objectToArray'], $obj); - } - - /** - * Check given value is multidimensional array - * - * @param array $arr - * @return bool - */ - protected function isMultiArray($arr) - { - if (!is_array($arr)) { - return false; - } - - rsort($arr); - - return isset($arr[0]) && is_array($arr[0]); - } - - /** - * Check given value is valid JSON - * - * @param string $value - * @param bool $isReturnMap - * - * @return bool|array - */ - public function isJson($value, $isReturnMap = false) - { - if (is_array($value) || is_object($value)) { - return false; - } - - $data = json_decode($value, true); - - if (json_last_error() !== JSON_ERROR_NONE) { - return false; - } - - return $isReturnMap ? $data : true; - } - - - public function takeColumn($array) - { - return $this->selectColumn($this->exceptColumn($array)); - } - - /** - * selecting specific column - * - * @param $array - * @return array - */ - protected function selectColumn($array) - { - $keys = $this->_select; - - if (count($keys) == 0) { - return $array; - } - - return array_intersect_key($array, array_flip((array) $keys)); - } - - /** - * selecting specific column - * - * @param $array - * @return array - */ - protected function exceptColumn($array) - { - $keys = $this->_except; - - if (count($keys) == 0) { - return $array; - } - - return array_diff_key($array, array_flip((array) $keys)); - } - - - /** - * Prepare data for result - * - * @param mixed $data - * @param bool $isObject - * @return array|mixed - */ - protected function prepareResult($data, $isObject) - { - $output = []; - - if (is_null($data) || is_scalar($data)) { - return $data; - } - - if ($this->isMultiArray($data)) { - foreach ($data as $key => $val) { - $val = $this->takeColumn($val); - $output[$key] = $isObject ? (object) $val : $val; - } - } else { - $output = json_decode(json_encode($this->takeColumn($data)), $isObject); - } - - return $output; - } - - /** - * Read JSON data from file - * - * @param string $file - * @param string $type - * @return bool|string|array - * @throws FileNotFoundException - * @throws InvalidJsonException - */ - protected function getDataFromFile($file, $type = 'application/json') - { - if (file_exists($file)) { - $opts = [ - 'http' => [ - 'header' => 'Content-Type: '.$type.'; charset=utf-8', - ], - ]; - - $context = stream_context_create($opts); - $data = file_get_contents($file, 0, $context); - $json = $this->isJson($data, true); - - if (!$json) { - throw new InvalidJsonException(); - } - - return $json; - } - - throw new FileNotFoundException(); - } - - - - /** - * Get data from nested array - * - * @param $map array - * @param $node string - * @return bool|array|mixed - */ - protected function getFromNested($map, $node) - { - if (empty($node) || $node == '.') { - return $map; - } - - if ($node) { - $terminate = false; - $path = explode('.', $node); - - foreach ($path as $val) { - if (!is_array($map)) return $map; - - if (!array_key_exists($val, $map)) { - $terminate = true; - break; - } - - $map = &$map[$val]; - } - - if ($terminate) { - return new ValueNotFound(); - } - - return $map; - } - - return new ValueNotFound(); - } - - /** - * get data from node path - * - * @return mixed - */ - protected function getData() - { - return $this->getFromNested($this->_map, $this->_node); - } - - /** - * process AND and OR conditions - * - * @return array|string|object - * @throws ConditionNotAllowedException - */ - protected function processConditions() - { - $data = $this->getData(); - $conditions = $this->_conditions; - $result = array_filter($data, function ($val) use ($conditions) { - $res = false; - foreach ($conditions as $cond) { - $tmp = true; - foreach ($cond as $rule) { - $function = self::$_rulesMap[$rule['condition']]; - if (!is_callable($function)) { - if (!method_exists(Condition::class, $function)) { - throw new ConditionNotAllowedException("Exception: $function condition not allowed"); - } - - $function = [Condition::class, $function]; - } - - $value = $this->getFromNested($val, $rule['key']); - $return = $value instanceof ValueNotFound ? false : call_user_func_array($function, [$value, $rule['value']]); - $tmp &= $return; - } - $res |= $tmp; - } - return $res; - }); - - return $result; - } - - /** - * make WHERE clause - * - * @param string $key - * @param string $condition - * @param mixed $value - * @return $this - */ - public function where($key, $condition = null, $value = null) - { - if (!is_null($condition) && is_null($value)) { - $value = $condition; - $condition = '='; - } - - if (count($this->_conditions) < 1) { - array_push($this->_conditions, []); - } - return $this->makeWhere($key, $condition, $value); - } - - /** - * make WHERE clause with OR - * - * @param string $key - * @param string $condition - * @param mixed $value - * @return $this - */ - public function orWhere($key = null, $condition = null, $value = null) - { - if (!is_null($condition) && is_null($value)) { - $value = $condition; - $condition = '='; - } - - array_push($this->_conditions, []); - - return $this->makeWhere($key, $condition, $value); - } - - /** - * generator for AND and OR where - * - * @param string $key - * @param string $condition - * @param mixed $value - * @return $this - */ - protected function makeWhere($key, $condition = null, $value = null) - { - $current = end($this->_conditions); - $index = key($this->_conditions); - if (is_callable($key)) { - $key($this); - return $this; - } - - array_push($current, [ - 'key' => $key, - 'condition' => $condition, - 'value' => $value, - ]); - - $this->_conditions[$index] = $current; - - return $this; - } - - /** - * make WHERE IN clause - * - * @param string $key - * @param array $value - * @return $this - */ - public function whereIn($key = null, $value = []) - { - $this->where($key, 'in', $value); - - return $this; - } - - /** - * make WHERE NOT IN clause - * - * @param string $key - * @param mixed $value - * @return $this - */ - public function whereNotIn($key = null, $value = []) - { - $this->where($key, 'notin', $value); - return $this; - } - - /** - * make WHERE NULL clause - * - * @param string $key - * @return $this - */ - public function whereNull($key = null) - { - $this->where($key, 'null', 'null'); - return $this; - } - - - /** - * make WHERE Boolean clause - * - * @param string $key - * @return $this - */ - public function whereBool($key = null, $value) - { - if (is_bool($value)) { - $this->where($key, '==', $value); - } - return $this; - } - - /** - * make WHERE NOT NULL clause - * - * @param string $key - * @return $this - */ - public function whereNotNull($key = null) - { - $this->where($key, 'notnull', 'null'); - - return $this; - } - - /** - * make WHERE START WITH clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereStartsWith($key, $value) - { - $this->where($key, 'startswith', $value); - - return $this; - } - - /** - * make WHERE ENDS WITH clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereEndsWith($key, $value) - { - $this->where($key, 'endswith', $value); - - return $this; - } - - /** - * make WHERE MATCH clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereMatch($key, $value) - { - $this->where($key, 'match', $value); - - return $this; - } - - /** - * make WHERE CONTAINS clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereContains($key, $value) - { - $this->where($key, 'contains', $value); - - return $this; - } - - /** - * make WHERE DATE clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereDate($key, $value) - { - $this->where($key, 'dates', $value); - - return $this; - } - - /** - * make WHERE month clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereMonth($key, $value) - { - $this->where($key, 'month', $value); - - return $this; - } - - /** - * make WHERE Year clause - * - * @param string $key - * @param string $value - * @return $this - */ - public function whereYear($key, $value) - { - $this->where($key, 'year', $value); - - return $this; - } - - /** - * make macro for custom where clause - * - * @param string $name - * @param callable $fn - * @return bool - */ - public static function macro($name, callable $fn) - { - if (!in_array($name, self::$_rulesMap)) { - self::$_rulesMap[$name] = $fn; - return true; - } - - return false; - } -} diff --git a/src/Jsonq.php b/src/Jsonq.php index 722c196..da390d4 100644 --- a/src/Jsonq.php +++ b/src/Jsonq.php @@ -2,746 +2,67 @@ namespace Nahid\JsonQ; -use Nahid\JsonQ\Exceptions\ConditionNotAllowedException; -use Nahid\JsonQ\Exceptions\InvalidJsonException; -use Nahid\JsonQ\Exceptions\InvalidNodeException; -use Nahid\JsonQ\Exceptions\NullValueException; +use Nahid\QArray\Exceptions\InvalidJsonException; +use Nahid\QArray\Exceptions\FileNotFoundException; +use Nahid\QArray\QueryEngine; -class Jsonq +class Jsonq extends QueryEngine { - use JsonQueriable; /** - * this constructor set main json file path - * otherwise create it and read file contents - * and decode as an array and store it in $this->_data + * Parse valid JSON data to an Array * - * @param null $jsonFile - * @throws Exceptions\FileNotFoundException + * @param string $data + * @return array|mixed * @throws InvalidJsonException */ - public function __construct($jsonFile = null) - { - if (!is_null($jsonFile)) { - $path = pathinfo($jsonFile); - $extension = isset($path['extension']) ? $path['extension'] : null; - - if ($extension != 'json') { - throw new InvalidJsonException(); - } - - $this->import($jsonFile); - } - } - - /** - * Deep copy current instance - * - * @return Jsonq - */ - public function copy() - { - return clone $this; - } - - /** - * Set node path, where JsonQ start to prepare - * - * @param null $node - * @return $this - * @throws NullValueException - */ - public function from($node = null) - { - $this->_isProcessed = false; - - if (is_null($node) || $node == '') { - throw new NullValueException("Null node exception"); - } - - $this->_node = $node; - - return $this; - } - - /** - * Alias of from() method - * - * @param null $node - * @return $this - * @throws NullValueException - */ - public function at($node = null) - { - return $this->from($node); - } - - /** - * select desired column - * - * @param ... scalar - * @return $this - */ - public function select() - { - $args = func_get_args(); - if (count($args) > 0 ){ - $this->_select = $args; - } - - return $this; - } - - /** - * select desired column for except - * - * @param ... scalar - * @return $this - */ - public function except() - { - $args = func_get_args(); - if (count($args) > 0 ){ - $this->_except = $args; - } - - return $this; - } - - /** - * getting prepared data - * - * @param bool $object - * @return array|object - * @throws ConditionNotAllowedException - */ - public function get($object = false) - { - $this->prepare(); - - return $this->prepareResult($this->_map, $object); - } - - /** - * alias of get method - * - * @param bool $object - * @return array|object - * @throws ConditionNotAllowedException - */ - public function fetch($object = true) - { - return $this->get($object); - } - - /** - * check data exists in system - * - * @return bool - * @throws ConditionNotAllowedException - */ - public function exists() - { - $this->prepare(); - - return (!empty($this->_map) && !is_null($this->_map)); - } - - /** - * reset given data to the $_map - * - * @param mixed $data - * @param bool $instance - * @return jsonq - */ - public function reset($data = null, $instance = false) - { - if (!is_null($data)) { - $this->_baseContents = $data; - } - - if ($instance) { - $self = new self(); - $self->collect($this->_baseContents); - - return $self; - } - - $this->_map = $this->_baseContents; - $this->reProcess(); - - return $this; - } - - /** - * getting group data from specific column - * - * @param string $column - * @return $this - * @throws ConditionNotAllowedException - */ - public function groupBy($column) - { - $this->prepare(); - - $data = []; - foreach ($this->_map as $map) { - $value = $this->getFromNested($map, $column); - if ($value) { - $data[$value][] = $map; - } - } - - $this->_map = $data; - return $this; - } - - public function countGroupBy($column) - { - - $this->prepare(); - - $data = []; - foreach ($this->_map as $map) { - $value = $this->getFromNested($map, $column); - if (!$value) { - continue; - } - - if (isset($data[$value])) { - $data[$value] ++; - } else { - $data[$value] = 1; - } - } - - $this->_map = $data; - return $this; - } - - /** - * count prepared data - * - * @return int - * @throws ConditionNotAllowedException - */ - public function count() - { - $this->prepare(); - - return count($this->_map); - } - - /** - * size is an alias of count - * - * @return int - * @throws ConditionNotAllowedException - */ - public function size() - { - return $this->count(); - } - - /** - * sum prepared data - * @param int $column - * @return int - * @throws ConditionNotAllowedException - */ - public function sum($column = null) - { - $this->prepare(); - - $sum = 0; - if (is_null($column)) { - $sum = array_sum($this->_map); - } else { - foreach ($this->_map as $key => $val) { - $value = $this->getFromNested($val, $column); - if (is_scalar($value)) { - $sum += $value; - } - - } - } - - return $sum; - } - - /** - * getting max value from prepared data - * - * @param int $column - * @return int - * @throws ConditionNotAllowedException - */ - public function max($column = null) - { - $this->prepare(); - - if (is_null($column)) { - $max = max($this->_map); - } else { - $max = max(array_column($this->_map, $column)); - } - - return $max; - } - - /** - * getting min value from prepared data - * - * @param int $column - * @return string - * @throws ConditionNotAllowedException - */ - public function min($column = null) - { - $this->prepare(); - - if (is_null($column)) { - $min = min($this->_map); - } else { - $min = min(array_column($this->_map, $column)); - } - - return $min; - } - - /** - * getting average value from prepared data - * - * @param int $column - * @return string - * @throws ConditionNotAllowedException - */ - public function avg($column = null) - { - $this->prepare(); - - $count = $this->count(); - $total = $this->sum($column); - - return ($total/$count); - } - - /** - * getting first element of prepared data - * - * @param bool $object - * @return object|array|null - * @throws ConditionNotAllowedException - */ - public function first($object = false) - { - $this->prepare(); - - $data = $this->_map; - if (count($data) > 0) { - return $this->prepareResult(reset($data), $object); - } - - return null; - } - - /** - * getting last element of prepared data - * - * @param bool $object - * @return object|array|null - * @throws ConditionNotAllowedException - */ - public function last($object = false) - { - $this->prepare(); - - $data = $this->_map; - if (count($data) > 0) { - return $this->prepareResult(end($data), $object); - } - - return null; - } - - /** - * getting nth number of element of prepared data - * - * @param int $index - * @param bool $object - * @return object|array|null - * @throws ConditionNotAllowedException - */ - public function nth($index, $object = false) + public function parseData($data) { - $this->prepare(); - - $data = $this->_map; - $total_elm = count($data); - $idx = abs($index); - - if (!is_integer($index) || $total_elm < $idx || $index == 0 || !is_array($this->_map)) { - return null; - } - - if ($index > 0) { - $result = $data[$index - 1]; - } else { - $result = $data[$this->count() + $index]; - } - - return $this->prepareResult($result, $object); - } - - /** - * sorting from prepared data - * - * @param string $column - * @param string $order - * @return object|array|null - * @throws ConditionNotAllowedException - */ - public function sortBy($column, $order = 'asc') - { - $this->prepare(); - - if (!is_array($this->_map)) { - return $this; - } - - usort($this->_map, function ($a, $b) use ($column, $order) { - $val1 = $this->getFromNested($a, $column); - $val2 = $this->getFromNested($b, $column); - if (is_string($val1)) { - $val1 = strtolower($val1); - } - - if (is_string($val2)) { - $val2 = strtolower($val2); - } - - if ($val1 == $val2) { - return 0; - } - $order = strtolower(trim($order)); - - if ($order == 'desc') { - return ($val1 > $val2) ? -1 : 1; - } else { - return ($val1 < $val2) ? -1 : 1; - } - }); - - return $this; - } - - /** - * Sort prepared data using a custom sort function. - * - * @param callable $sortFunc - * - * @return object|array|null - * @throws ConditionNotAllowedException - */ - public function sortByCallable(callable $sortFunc) - { - $this->prepare(); - - if (!is_array($this->_map)) { - return $this; - } - - usort($this->_map, $sortFunc); + if (is_null($data)) return []; - return $this; - } - - /** - * Sort an array value - * - * @param string $order - * @return Jsonq - */ - public function sort($order = 'asc') - { - if ($order == 'desc') { - rsort($this->_map); - }else{ - sort($this->_map); - } - - return $this; - } - - /** - * getting data from desire path - * - * @param string $path - * @param bool $object - * @return mixed - * @throws NullValueException - * @throws ConditionNotAllowedException - */ - public function find($path, $object = false) - { - return $this->from($path)->prepare()->get($object); - } - - /** - * take action of each element of prepared data - * - * @param callable $fn - * @throws ConditionNotAllowedException - */ - public function each(callable $fn) - { - $this->prepare(); - - foreach ($this->_map as $key => $val) { - $fn($key, $val); - } - } - - /** - * transform prepared data by using callable function - * - * @param callable $fn - * @return object|array - * @throws ConditionNotAllowedException - */ - public function transform(callable $fn) - { - $this->prepare(); - - $new_data = []; - foreach ($this->_map as $key => $val) { - $new_data[$key] = $fn($val); - } - - return $this->prepareResult($new_data, false); - } - - /** - * pipe send output in next pipe - * - * @param callable $fn - * @param string|null $class - * @return object|array - * @throws ConditionNotAllowedException - */ - public function pipe(callable $fn, $class = null) - { - $this->prepare(); - - if (is_string($fn) && !is_null($class)) { - $instance = new $class; - - $this->_map = call_user_func_array([$instance, $fn], [$this]); - return $this; - } + $data = json_decode($data, true); + if (json_last_error() != JSON_ERROR_NONE) throw new InvalidJsonException(); - $this->_map = $fn($this); - return $this; + return $data; } /** - * filtered each element of prepared data + * Parse data from give file or URL * - * @param callable $fn - * @param bool $key - * @return mixed|array - * @throws ConditionNotAllowedException + * @param string $jsonFile + * @return array|mixed + * @throws FileNotFoundException + * @throws InvalidJsonException */ - public function filter(callable $fn, $key = false) + public function readPath($jsonFile) { - $this->prepare(); - - $data = []; - foreach ($this->_map as $k => $val) { - if ($fn($val)) { - if ($key) { - $data[$k] = $val; - } else { - $data[] = $val; - } - } + if (is_null($jsonFile)) { + throw new FileNotFoundException(); } - return $this->prepareResult($data, false); - } + $rawData = null; - /** - * then method set position of working data - * - * @param string $node - * @return jsonq - * @throws NullValueException - * @throws ConditionNotAllowedException - */ - public function then($node) - { - $this->_map = $this->prepare()->first(false); - - $this->from($node); - - return $this; - } - - /** - * import raw JSON data for process - * - * @param string $data - * @return jsonq - */ - public function json($data) - { - $json = $this->isJson($data, true); - - if ($json) { - return $this->collect($json); + if (filter_var($jsonFile, FILTER_VALIDATE_URL)) { + $rawData = file_get_contents($jsonFile); } - return $this; - } - - /** - * import parsed data from raw json - * - * @param array|object $data - * @return jsonq - */ - public function collect($data) - { - $this->_map = $this->objectToArray($data); - $this->_baseContents = &$this->_map; - - return $this; - } - - /** - * implode resulting data from desire key and delimeter - * - * @param string|array $key - * @param string $delimiter - * @return string|array - * @throws ConditionNotAllowedException - */ - public function implode($key, $delimiter = ',') - { - $this->prepare(); - - $implode = []; - if (is_string($key)) { - return $this->makeImplode($key, $delimiter); - } + if (file_exists($jsonFile)) { + $path = pathinfo($jsonFile); + $extension = isset($path['extension']) ? $path['extension'] : null; - if (is_array($key)) { - foreach ($key as $k) { - $imp = $this->makeImplode($k, $delimiter); - $implode[$k] = $imp; + if ($extension != 'json') { + throw new InvalidJsonException(); } - return $implode; + $rawData = file_get_contents($jsonFile); } - return ''; - } - /** - * process implode from resulting data - * - * @param string $key - * @param string $delimiter - * @return string|null - */ - protected function makeImplode($key, $delimiter) - { - $data = array_column($this->_map, $key); - - if (is_array($data)) { - return implode($delimiter, $data); - } - - return null; - } - - /** - * getting specific key's value from prepared data - * - * @param string $column - * @return object|array - * @throws ConditionNotAllowedException - */ - public function column($column) - { - $this->prepare(); - - return array_column($this->_map, $column); - } - - /** - * getting raw JSON from prepared data - * - * @return string - * @throws ConditionNotAllowedException - */ - public function toJson() - { - $this->prepare(); - - return json_encode($this->_map); - } - - /** - * getting all keys from prepared data - * - * @return object|array - * @throws ConditionNotAllowedException - */ - public function keys() - { - $this->prepare(); - - return array_keys($this->_map); - } - - /** - * getting all values from prepared data - * - * @return object|array - * @throws ConditionNotAllowedException - */ - public function values() - { - $this->prepare(); - - return array_values($this->_map); - } - - /** - * getting chunk values from prepared data - * - * @param int $amount - * @param $fn - * @return object|array|bool - * @throws ConditionNotAllowedException - */ - public function chunk($amount, callable $fn = null) - { - $this->prepare(); + if (is_null($rawData)) throw new FileNotFoundException(); - $chunk_value = array_chunk($this->_map, $amount); - $chunks = []; + $data = json_decode($rawData, true); - if (!is_null($fn) && is_callable($fn)) { - foreach ($chunk_value as $chunk) { - $return = $fn($chunk); - if (!is_null($return)) { - $chunks[] = $return; - } - } - return count($chunks) > 0 ? $chunks : null; - } + if (json_last_error() !== JSON_ERROR_NONE) throw new InvalidJsonException(); - return $chunk_value; + return $data; } } diff --git a/src/JsonqServiceProvider.php b/src/JsonqServiceProvider.php deleted file mode 100644 index 24ecd2b..0000000 --- a/src/JsonqServiceProvider.php +++ /dev/null @@ -1,83 +0,0 @@ -setupConfig(); - } - - /** - * Register the application services. - */ - public function register() - { - $this->registerJsonq(); - $this->registerJsonManager(); - } - - /** - * Setup the config. - */ - protected function setupConfig() - { - $source = realpath(__DIR__.'/../config/jsonq.php'); - // Check if the application is a Laravel OR Lumen instance to properly merge the configuration file. - if ($this->app instanceof LaravelApplication && $this->app->runningInConsole()) { - $this->publishes([$source => config_path('jsonq.php')]); - } elseif ($this->app instanceof LumenApplication) { - $this->app->configure('jsonq'); - } - $this->mergeConfigFrom($source, 'Jsonq'); - } - - /** - * register JsonManager. - */ - protected function registerJsonManager() - { - $config = $this->app['config']; - $this->app->singleton('jsonq.manager', function () use ($config) { - return new JsonQueriable($config->get('jsonq.json.storage_path')); - }); - - $this->app->alias('jsonq.manager', JsonQueriable::class); - } - - /** - * Register Talk class. - */ - protected function registerJsonq() - { - $config = $this->app['config']; - $this->app->bind('Jsonq', function () use ($config) { - $path = $config->get('jsonq.json.storage_path'); - $storagePath = $path == '' ? null : $path; - - return new Jsonq($storagePath); - }); - - $this->app->alias('Jsonq', Jsonq::class); - } - /** - * Get the services provided by the provider. - * - * @return string[] - */ - public function provides() - { - return [ - 'jsonq', - 'jsonq.manager', - ]; - } -} diff --git a/src/Results/ValueNotFound.php b/src/Results/ValueNotFound.php deleted file mode 100644 index b57861b..0000000 --- a/src/Results/ValueNotFound.php +++ /dev/null @@ -1,9 +0,0 @@ -assertIsInjectable(Jsonq::class); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php deleted file mode 100644 index d9aa266..0000000 --- a/tests/TestCase.php +++ /dev/null @@ -1,24 +0,0 @@ - Date: Sun, 23 Aug 2020 00:43:21 +0600 Subject: [PATCH 2/2] update readme --- README.md | 119 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index b6a14dd..47cfe8d 100755 --- a/README.md +++ b/README.md @@ -8,6 +8,20 @@ Hey due, please help me out for daily improve this project [![Beerpay](https://beerpay.io/nahid/jsonq/badge.svg)](https://beerpay.io/nahid/jsonq) + + +## NOTE + +> From the version JsonQ 6.0 all the features rewrite from [QAarray](https://github.com/nahid/qarray). After a long run we noticed that Query Engine of JsonQ should be seperate. Becouse people want to query over various types of data like CSV, YAML, XML. So if we keep the query engine tightly coupled with this project its make no sense. Thats why we move the Query Engine part and develop a new package [QAarray](https://github.com/nahid/qarray). Qarray is designed for queryng over native PHP array and anyone can implement their own Engine, like JsonQ. + + + +> +> +> ### Please do not update to >= 6.0 version directly from bellow + + + ## Installation ``` @@ -42,33 +56,33 @@ Let's see a quick example: ```json //data.json { - "name": "products", - "description": "Features product list", - "vendor":{ - "name": "Computer Source BD", - "email": "info@example.com", - "website":"www.example.com" - }, - "users":[ - {"id":1, "name":"Johura Akter Sumi", "location": "Barisal"}, - {"id":2, "name":"Mehedi Hasan Nahid", "location": "Barisal"}, - {"id":3, "name":"Ariful Islam", "location": "Barisal"}, - {"id":4, "name":"Suhel Ahmed", "location": "Sylhet"}, - {"id":5, "name":"Firoz Serniabat", "location": "Gournodi"}, - {"id":6, "name":"Musa Jewel", "location": "Barisal", "visits": [ - {"name": "Sylhet", "year": 2011}, - {"name": "Cox's Bazar", "year": 2012}, - {"name": "Bandarbar", "year": 2014} - ]} - ], - "products": [ - {"id":1, "user_id": 2, "city": "bsl", "name":"iPhone", "cat":1, "price": 80000}, - {"id":2, "user_id": 2, "city": null, "name":"macbook pro", "cat": 2, "price": 150000}, - {"id":3, "user_id": 2, "city": "dhk", "name":"Redmi 3S Prime", "cat": 1, "price": 12000}, - {"id":4, "user_id": 1, "city": null, "name":"Redmi 4X", "cat":1, "price": 15000}, - {"id":5, "user_id": 1, "city": "bsl", "name":"macbook air", "cat": 2, "price": 110000}, - {"id":6, "user_id": 2, "city": null, "name":"macbook air 1", "cat": 2, "price": 81000} - ] + "name": "products", + "description": "Features product list", + "vendor":{ + "name": "Computer Source BD", + "email": "info@example.com", + "website":"www.example.com" + }, + "users":[ + {"id":1, "name":"Johura Akter Sumi", "location": "Barisal"}, + {"id":2, "name":"Mehedi Hasan Nahid", "location": "Barisal"}, + {"id":3, "name":"Ariful Islam", "location": "Barisal"}, + {"id":4, "name":"Suhel Ahmed", "location": "Sylhet"}, + {"id":5, "name":"Firoz Serniabat", "location": "Gournodi"}, + {"id":6, "name":"Musa Jewel", "location": "Barisal", "visits": [ + {"name": "Sylhet", "year": 2011}, + {"name": "Cox's Bazar", "year": 2012}, + {"name": "Bandarbar", "year": 2014} + ]} + ], + "products": [ + {"id":1, "user_id": 2, "city": "bsl", "name":"iPhone", "cat":1, "price": 80000}, + {"id":2, "user_id": 2, "city": null, "name":"macbook pro", "cat": 2, "price": 150000}, + {"id":3, "user_id": 2, "city": "dhk", "name":"Redmi 3S Prime", "cat": 1, "price": 12000}, + {"id":4, "user_id": 1, "city": null, "name":"Redmi 4X", "cat":1, "price": 15000}, + {"id":5, "user_id": 1, "city": "bsl", "name":"macbook air", "cat": 2, "price": 110000}, + {"id":6, "user_id": 2, "city": null, "name":"macbook air 1", "cat": 2, "price": 81000} + ] } ``` @@ -250,31 +264,31 @@ This is an alias method of `from()` and will behave exactly like that. See examp * `val` -- value to be matched with. It can be a _int_, _string_, _bool_ or even _Function_ - depending on the `op`. * `op` -- operand to be used for matching. The following operands are available to use: - * `=` : For weak equality matching - * `eq` : Same as `=` - * `!=` : For weak not equality matching - * `neq` : Same as `!=` - * `==` : For strict equality matching - * `seq` : Same as `==` - * `!==` : For strict not equality matching - * `sneq` : Same as `!==` - * `>` : Check if value of given **key** in data is Greater than **val** - * `gt` : Same as `>` - * `<` : Check if value of given **key** in data is Less than **val** - * `lt` : Same as `<` - * `>=` : Check if value of given **key** in data is Greater than or Equal of **val** - * `gte` : Same as `>=` - * `<=` : Check if value of given **key** in data is Less than or Equal of **val** - * `lte` : Same as `<=` - * `null` : Check if the value of given **key** in data is **null** (`val` parameter in `where()` can be omitted for this `op`) - * `notnull` : Check if the value of given **key** in data is **not null** (`val` parameter in `where()` can be omitted for this `op`) - * `in` : Check if the value of given **key** in data is exists in given **val**. **val** should be a plain _Array_. - * `notin` : Check if the value of given **key** in data is not exists in given **val**. **val** should be a plain _Array_. - * `startswith` : Check if the value of given **key** in data starts with (has a prefix of) the given **val**. This would only works for _String_ type data. - * `endswith` : Check if the value of given **key** in data ends with (has a suffix of) the given **val**. This would only works for _String_ type data. - * `contains` : Check if the value of given **key** in data has a substring of given **val**. This would only works for _String_ type data. - * `match` : Check if the value of given **key** in data has a Regular Expression match with the given **val**. The `val` parameter should be a **RegExp** for this `op`. - * `macro` : It would try to match the value of given **key** in data executing the given `val`. The `val` parameter should be a **Function** for this `op`. This function should have a matching logic inside it and return **true** or **false** based on that. + * `=` : For weak equality matching + * `eq` : Same as `=` + * `!=` : For weak not equality matching + * `neq` : Same as `!=` + * `==` : For strict equality matching + * `seq` : Same as `==` + * `!==` : For strict not equality matching + * `sneq` : Same as `!==` + * `>` : Check if value of given **key** in data is Greater than **val** + * `gt` : Same as `>` + * `<` : Check if value of given **key** in data is Less than **val** + * `lt` : Same as `<` + * `>=` : Check if value of given **key** in data is Greater than or Equal of **val** + * `gte` : Same as `>=` + * `<=` : Check if value of given **key** in data is Less than or Equal of **val** + * `lte` : Same as `<=` + * `null` : Check if the value of given **key** in data is **null** (`val` parameter in `where()` can be omitted for this `op`) + * `notnull` : Check if the value of given **key** in data is **not null** (`val` parameter in `where()` can be omitted for this `op`) + * `in` : Check if the value of given **key** in data is exists in given **val**. **val** should be a plain _Array_. + * `notin` : Check if the value of given **key** in data is not exists in given **val**. **val** should be a plain _Array_. + * `startswith` : Check if the value of given **key** in data starts with (has a prefix of) the given **val**. This would only works for _String_ type data. + * `endswith` : Check if the value of given **key** in data ends with (has a suffix of) the given **val**. This would only works for _String_ type data. + * `contains` : Check if the value of given **key** in data has a substring of given **val**. This would only works for _String_ type data. + * `match` : Check if the value of given **key** in data has a Regular Expression match with the given **val**. The `val` parameter should be a **RegExp** for this `op`. + * `macro` : It would try to match the value of given **key** in data executing the given `val`. The `val` parameter should be a **Function** for this `op`. This function should have a matching logic inside it and return **true** or **false** based on that. **example:** @@ -603,6 +617,7 @@ This package has also different language support. - [Go JsonQ](https://github.com/thedevsaddam/gojsonq) developed by [Saddam H](https://github.com/thedevsaddam) - Upcoming ## Support on Beerpay + Hey dude! Help me out for a couple of :beers:! [![Beerpay](https://beerpay.io/nahid/jsonq/badge.svg?style=beer-square)](https://beerpay.io/nahid/jsonq) [![Beerpay](https://beerpay.io/nahid/jsonq/make-wish.svg?style=flat-square)](https://beerpay.io/nahid/jsonq?focus=wish)