Skip to content

Commit d45340d

Browse files
committed
FQL parser knows use parser attributes from FileQuery and parsing order by clause has default asc sorting type
1 parent fab636f commit d45340d

File tree

3 files changed

+135
-43
lines changed

3 files changed

+135
-43
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [2.0.9]
4+
5+
- Previous fix for loading csv data with more attributes is fixing parsing only but this fix is knows works with files properly at FQL parser too
6+
- Parsing `ORDER BY` clause supports default sorting by `ASC` when not specified
7+
38
## [2.0.8]
49

510
- Fixed support for loading csv data with more attributes

src/Query/FileQuery.php

Lines changed: 108 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use FQL\Enum;
66
use FQL\Exception;
7+
use FQL\Exception\InvalidFormatException;
78
use FQL\Interface;
89

910
final class FileQuery implements \Stringable
@@ -50,6 +51,81 @@ public function __construct(private readonly string $queryPath)
5051
$this->query = $query;
5152
}
5253

54+
/**
55+
* @throws Exception\FileQueryException
56+
* @throws Exception\InvalidFormatException
57+
*/
58+
public function withFile(?string $file): self
59+
{
60+
return new self(self::toString(
61+
$this->extension,
62+
$file,
63+
$this->encoding,
64+
$this->delimiter,
65+
$this->query
66+
));
67+
}
68+
69+
/**
70+
* @throws Exception\FileQueryException
71+
* @throws Exception\InvalidFormatException
72+
*/
73+
public function withEncoding(string $encoding): self
74+
{
75+
return new self(self::toString(
76+
$this->extension,
77+
$this->file,
78+
$encoding,
79+
$this->delimiter,
80+
$this->query
81+
));
82+
}
83+
84+
/**
85+
* @throws Exception\FileQueryException
86+
* @throws Exception\InvalidFormatException
87+
*/
88+
public function withDelimiter(string $delimiter): self
89+
{
90+
return new self(self::toString(
91+
$this->extension,
92+
$this->file,
93+
$this->encoding,
94+
$delimiter,
95+
$this->query
96+
));
97+
}
98+
99+
/**
100+
* @throws Exception\FileQueryException
101+
* @throws Exception\InvalidFormatException
102+
*/
103+
public function withQuery(?string $query): self
104+
{
105+
return new self(self::toString(
106+
$this->extension,
107+
$this->file,
108+
$this->encoding,
109+
$this->delimiter,
110+
$query
111+
));
112+
}
113+
114+
/**
115+
* @throws Exception\FileQueryException
116+
* @throws Exception\InvalidFormatException
117+
*/
118+
public function withExtension(?Enum\Format $extension): self
119+
{
120+
return new self(self::toString(
121+
$extension,
122+
$this->file,
123+
$this->encoding,
124+
$this->delimiter,
125+
$this->query
126+
));
127+
}
128+
53129
/**
54130
* @throws Exception\InvalidFormatException
55131
*/
@@ -65,20 +141,45 @@ public static function getRegexp(int $defaultPosition = 12): string
65141

66142
public function __toString(): string
67143
{
144+
return self::toString(
145+
$this->extension,
146+
$this->file,
147+
$this->encoding,
148+
$this->delimiter,
149+
$this->query
150+
);
151+
}
152+
153+
private static function toString(
154+
?Enum\Format $extension,
155+
?string $file,
156+
?string $encoding,
157+
?string $delimiter,
158+
?string $query
159+
): string {
68160
$fileQueryString = '';
69-
if ($this->extension !== null) {
70-
$fileQueryString .= "[{$this->extension->value}]";
161+
if ($extension !== null) {
162+
$fileQueryString .= "[{$extension->value}]";
71163
}
72164

73-
if ($this->file !== null) {
74-
$fileQueryString .= "({$this->file})";
165+
if ($file !== null) {
166+
$fileQueryStringParts = [$file];
167+
if ($encoding !== null && $encoding !== '' && $encoding !== 'utf-8') {
168+
$fileQueryStringParts[] = $encoding;
169+
}
170+
171+
if ($delimiter !== null && $delimiter !== '' && $delimiter !== ',') {
172+
$fileQueryStringParts[] = sprintf('"%s"', $delimiter);
173+
}
174+
175+
$fileQueryString .= sprintf('(%s)', implode(', ', $fileQueryStringParts));
75176
}
76177

77-
if ($this->query !== null) {
78-
if ($this->file !== null) {
178+
if ($query !== null) {
179+
if ($file !== null) {
79180
$fileQueryString .= '.';
80181
}
81-
$fileQueryString .= $this->query;
182+
$fileQueryString .= $query;
82183
}
83184

84185
return $fileQueryString;

src/Sql/Sql.php

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,17 @@ public function parse(): Interface\Results
3636
public function toQuery(): Interface\Query
3737
{
3838
$this->rewind();
39-
$stream = null;
4039
while (!$this->isEOF()) {
4140
$token = $this->nextToken();
4241
if (strtoupper($token) !== 'FROM') {
4342
continue;
4443
}
4544

46-
$fileQueryString = $this->nextToken();
47-
$this->validateFileQueryPath($fileQueryString);
48-
49-
$fileQuery = new Query\FileQuery($fileQueryString);
50-
$fileName = null;
51-
if ($fileQuery->file !== null) {
52-
$fileName = $this->basePath !== null
53-
? $this->basePath . DIRECTORY_SEPARATOR . $fileQuery->file
54-
: $fileQuery->file;
55-
}
56-
57-
$stream = Stream\Provider::fromFile($fileName ?? '', $fileQuery->extension);
58-
break;
45+
$fileQuery = $this->validateFileQueryPath($this->nextToken());
46+
return $this->parseWithQuery(Query\Provider::fromFileQuery((string) $fileQuery));
5947
}
6048

61-
if ($stream === null) {
62-
throw new Exception\UnexpectedValueException('No query found');
63-
}
64-
65-
return $this->parseWithQuery($stream->query());
49+
throw new Exception\UnexpectedValueException('Undefined file in query');
6650
}
6751

6852
/**
@@ -81,26 +65,23 @@ public function parseWithQuery(Interface\Query $query): Interface\Query
8165
break;
8266

8367
case Interface\Query::FROM:
84-
$fileQuery = new Query\FileQuery($this->nextToken());
85-
$this->validateFileQueryPath($fileQuery);
86-
68+
$fileQuery = $this->validateFileQueryPath($this->nextToken());
8769
$query->from($fileQuery->query ?? '');
8870
break;
8971

9072
case 'INNER':
9173
case 'LEFT':
9274
$this->nextToken(); // Consume "JOIN"
9375

94-
$joinQuery = $this->nextToken();
95-
$this->validateFileQueryPath($joinQuery);
76+
$joinQuery = $this->validateFileQueryPath($this->nextToken());
9677

9778
$this->expect('AS');
9879
$alias = $this->nextToken();
9980

10081
if (strtolower($token) === 'left') {
101-
$query->leftJoin(Query\Provider::fromFileQuery($joinQuery), $alias);
82+
$query->leftJoin(Query\Provider::fromFileQuery((string) $joinQuery), $alias);
10283
} elseif (strtolower($token) === 'inner') {
103-
$query->innerJoin(Query\Provider::fromFileQuery($joinQuery), $alias);
84+
$query->innerJoin(Query\Provider::fromFileQuery((string) $joinQuery), $alias);
10485
}
10586
$this->expect('ON');
10687

@@ -111,13 +92,11 @@ public function parseWithQuery(Interface\Query $query): Interface\Query
11192
$query->on($field, $operator, $value);
11293
break;
11394
case 'JOIN':
114-
$joinQuery = $this->nextToken();
115-
$this->validateFileQueryPath($joinQuery);
116-
95+
$joinQuery = $this->validateFileQueryPath($this->nextToken());
11796
$this->expect(Interface\Query::AS);
11897
$alias = $this->nextToken();
11998

120-
$query->innerJoin(Query\Provider::fromFileQuery($joinQuery), $alias);
99+
$query->innerJoin(Query\Provider::fromFileQuery((string) $joinQuery), $alias);
121100
$this->expect('ON');
122101

123102
$field = $this->nextToken();
@@ -238,6 +217,7 @@ private function applyFunctionToQuery(string $field, Interface\Query $query): vo
238217
{
239218
$functionName = $this->getFunction($field);
240219
$arguments = $this->getFunctionArguments($field);
220+
dump($arguments);
241221

242222
match (strtoupper($functionName)) {
243223
// aggregate
@@ -393,8 +373,12 @@ private function parseSort(Interface\Query $query): void
393373
$direction = match ($directionString) {
394374
'ASC' => Enum\Sort::ASC,
395375
'DESC' => Enum\Sort::DESC,
396-
default => throw new Exception\SortException(sprintf('Invalid direction %s', $directionString)),
376+
default => false,
397377
};
378+
if ($direction === false) {
379+
$direction = Enum\Sort::ASC;
380+
$this->rewindToken();
381+
}
398382
$query->orderBy($field, $direction);
399383
}
400384
}
@@ -454,15 +438,15 @@ public function setBasePath(?string $basePath): void
454438
/**
455439
* @throws Exception\InvalidFormatException
456440
*/
457-
private function validateFileQueryPath(string $fileQueryString): void
441+
private function validateFileQueryPath(string $fileQueryString): Query\FileQuery
458442
{
443+
$fileQuery = new Query\FileQuery($fileQueryString);
459444
if ($this->basePath === null) {
460-
return;
445+
return $fileQuery;
461446
}
462447

463-
$fileQuery = new Query\FileQuery($fileQueryString);
464448
if ($fileQuery->file === null) {
465-
return;
449+
return $fileQuery;
466450
}
467451

468452
$fileName = $this->basePath . DIRECTORY_SEPARATOR . $fileQuery->file;
@@ -473,7 +457,9 @@ private function validateFileQueryPath(string $fileQueryString): void
473457
$basePathRealPath === false ||
474458
!str_starts_with($fileNameRealPath, $basePathRealPath)
475459
) {
476-
throw new Exception\InvalidFormatException('Invalid query base path');
460+
throw new Exception\InvalidFormatException('Invalid path of file');
477461
}
462+
463+
return $fileQuery->withFile($fileNameRealPath);
478464
}
479465
}

0 commit comments

Comments
 (0)