Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8a2e7dd
merging in some regex tooling and bug fixes
nathannorthcutt Aug 9, 2024
4d005b6
starting to work on adding where clause support
nathannorthcutt Aug 14, 2024
8f217f2
working on where clause addition
nathannorthcutt Aug 15, 2024
9344782
working on refactoring, a lot of things have to change for full where…
nathannorthcutt Aug 18, 2024
5fee2c7
fix with test
nathannorthcutt Aug 18, 2024
504ed6d
refactor out arithmetic operations and ensure all are used for normal…
nathannorthcutt Aug 19, 2024
d433472
working on arithmetic parser as example for expressions
nathannorthcutt Aug 20, 2024
7585dd6
making some changes as I test alternate operations and options
nathannorthcutt Aug 20, 2024
4353936
refactoring arithmetic expressions for more completeness, still need …
nathannorthcutt Aug 21, 2024
f482da2
parse the next arithmetic chunk and return the remainder as the main …
nathannorthcutt Aug 22, 2024
317c6f8
refactor to cleanup
nathannorthcutt Aug 22, 2024
b75cf9a
adding options to all builders, refactoring parse value to read poten…
nathannorthcutt Aug 23, 2024
d66a18c
switching to use the value from the stack
nathannorthcutt Aug 23, 2024
c41125f
horrible mess but getting more clear
nathannorthcutt Aug 23, 2024
2d5ef6f
fixing a few things to get ready to start parsing where clauses
nathannorthcutt Aug 28, 2024
99e4b9c
working on the parsing and expressions handling arithmetic and logical
nathannorthcutt Sep 2, 2024
9b4a076
parser should handle where, not select
nathannorthcutt Sep 2, 2024
3f21cb7
better
nathannorthcutt Sep 2, 2024
48fa0d8
sync everything to fix local wsl
nathannorthcutt Sep 12, 2024
4bc5a30
sometimes easier to just delete and begin again with an easier solution
nathannorthcutt Sep 16, 2024
98e8d70
starting to work on refactoring and greatly simplifying parsing of where
nathannorthcutt Sep 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions packages/sql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Telefrek SQL

This package is designed to showcase typescript parsing, validation and
customization capabilities when dealing with SQL queries that can be executed
against a variety of backends. It is initially being written as a tutorial
series for how to build something ambitious and new but is something I also
intend to use in future projects and will be releasing packages and updates for
in the future.

## Structure

There are several sub packages within this main SQL project related to the
specific areas they are handling in the parsing and query building process. The
query package contains the parsing, building and validation components that are
used to manage the queries themselves in the project. The ast is the backbone
for communication between components and represents the SQL independent of it's
parsed or re-hydrated forms. The engines represent code designed to manage and
execute queries at runtime without having to know about the individual sources.
Finally the schema packages are intended to help with managing database schemas
that are used to validate queries and represent the entities that are expected
to exist as well as their shape in the target database.

## Testing

For now the primary testing is done with some mostly silly tests that fail as
soon as the TypeScript compilation becomes invalid to help track down
regressions or issues with the realtime parsing system. There are other tests
that verify that the builders generate the same structures that the parsers
expect and define. Finally most of the tests are grouped into a single file to
help find performance issues when dealing with dozens or hundreds of queries
within a single file. I might eventually split more of them out but for now I
want a place to be able to stress the type system and force a lot of
recompilation.
2 changes: 1 addition & 1 deletion packages/sql/ast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type ColumnFilter<
> = {
type: "ColumnFilter"
left: Left
op: Operation
operation: Operation
right: Right
}
```
Expand Down
20 changes: 11 additions & 9 deletions packages/sql/ast/combined.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ export type CombinedSelectOperation = "UNION" | "INTERSECT" | "MINUS" | "EXCEPT"
*/
export type CombinedSelect<
Operation extends string = CombinedSelectOperation,
Next extends SelectClause = SelectClause,
Next extends SelectClause = SelectClause
> = {
type: "CombinedSelect"
op: Operation
operation: Operation
next: Next
}

/**
* Utliity type to extract the keys from the initial select clause to restrict
* others to having the same set of keys
*/
type GetSelectKeys<Select extends SelectClause> =
Select extends SelectClause<infer Columns, infer _>
? Columns extends "*"
? string
: Extract<keyof Columns, string>
: string
type GetSelectKeys<Select extends SelectClause> = Select extends SelectClause<
infer Columns,
infer _
>
? Columns extends "*"
? string
: Extract<keyof Columns, string>
: string

/**
* A chain of select clauses
Expand All @@ -36,7 +38,7 @@ export type CombinedSelectClause<
Original extends SelectClause = SelectClause,
Additions extends OneOrMore<
CombinedSelect<GetSelectKeys<Original>>
> = OneOrMore<CombinedSelect<GetSelectKeys<Original>>>,
> = OneOrMore<CombinedSelect<GetSelectKeys<Original>>>
> = {
type: "CombinedSelectClause"
original: Original
Expand Down
195 changes: 195 additions & 0 deletions packages/sql/ast/expressions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import type { ColumnReference } from "./columns.js"
import type { SubQuery } from "./queries.js"
import type { ValueTypes } from "./values.js"

/**
* Types for Arithmetic operations
*/
export type ArithmeticOperation = "+" | "-" | "*" | "/" | "%" | "|" | "&" | "^"

/**
* The default arithmetic operations
*/
export const DEFAULT_ARITHMETIC_OPS: ArithmeticOperation[] = [
"%",
"&",
"*",
"+",
"-",
"/",
"^",
"|",
]

/**
* Types for Arithmetic assignment
*/
export type ArithmeticAssignmentOperation = `${ArithmeticOperation}=` | "="

/**
* The default arithmetic assignment operations
*/
export const DEFAULT_ARITHMETIC_ASSIGNMENT_OPS: ArithmeticAssignmentOperation[] =
["%=", "&=", "*=", "+=", "-=", "/=", "^=", "|=", "="]

/**
* Any logical operation
*/
export type LogicalOperation = {
type: string
operation: string
}

export function isLogicalOperation(value: unknown): value is LogicalOperation {
return (
typeof value === "object" &&
value !== null &&
"type" in value &&
"operation" in value &&
typeof value.type === "string" &&
typeof value.operation === "string"
)
}

/**
* Types for for value comparisons
*/
export type ComparisonOperation = "=" | "<" | ">" | "<=" | ">=" | "!=" | "<>"

/**
* The default comparison operations
*/
export const DEFAULT_COMPARISON_OPS: ComparisonOperation[] = [
"=",
"<",
">",
"<=",
">=",
"!=",
"<>",
]

/**
* A filter between two objects
*/
export type ColumnFilter<
Column extends ColumnReference = ColumnReference,
Operation extends string = ComparisonOperation,
Filter extends LogicalExpression = LogicalExpression
> = {
type: "ColumnFilter"
column: Column
operation: Operation
filter: Filter
}

/**
* An expression which could be an operation, value or column
*/
export type LogicalExpression = LogicalOperation | ValueTypes | ColumnReference

/**
* Type for handling logical negations
*/
export type LogicalNegation<
Expression extends LogicalExpression = LogicalExpression
> = LogicalOperation & {
type: "LogicalNegation"
operation: "NOT"
expression: Expression
}

/**
* An arithmetic assignment expression, ex: column += b
*/
export type ColumnArithmeticAssignment<
Column extends ColumnReference = ColumnReference,
Op extends string = ArithmeticAssignmentOperation,
Value extends LogicalExpression = LogicalExpression
> = LogicalOperation & {
type: "ColumnArithmeticAssignment"
column: Column
operation: Op
value: Value
}

/**
* An arithmetic expression between two values, ex: a + b
*/
export type ArithmeticExpression<
Left extends LogicalExpression = LogicalExpression,
Op extends string = ArithmeticOperation,
Right extends LogicalExpression = LogicalExpression
> = LogicalOperation & {
type: "ArithmeticExpression"
left: Left
operation: Op
right: Right
}

/**
* A grouped expression (surrounded by parenthesis)
*/
export type LogicalGroup<
Expression extends LogicalOperation = LogicalOperation
> = {
type: "LogicalGroup"
operation: "LogicalGroup"
expression: Expression
}

/**
* A filter for a clause that matches something IN a set
*/
export type InFilter<
Column extends ColumnReference = ColumnReference,
Values extends SubQuery | ValueTypes[] = SubQuery | ValueTypes[]
> = LogicalOperation & {
type: "InFilter"
operation: "IN"
column: Column
values: Values
}

/**
* A filter between two values
*/
export type BetweenFilter<
Column extends ColumnReference = ColumnReference,
Left extends LogicalExpression = LogicalExpression,
Right extends LogicalExpression = LogicalExpression
> = LogicalOperation & {
type: "BetweenFilter"
operation: "BETWEEN"
column: Column
left: Left
right: Right
}

/**
* A logical tree operation
*/
export type LogicalTree<
Left extends LogicalExpression = LogicalExpression,
Operation extends string = "AND" | "OR",
Right extends LogicalExpression = LogicalExpression
> = LogicalOperation & {
type: "LogicalTree"
operation: Operation
left: Left
right: Right
}

/**
* A subquery filter that is NOT an "IN" because of syntax restrictions
*/
export type SubqueryFilter<
Column extends ColumnReference = ColumnReference,
Operation extends string = "ANY" | "ALL" | "EXISTS" | "SOME",
Subquery extends SubQuery = SubQuery
> = LogicalOperation & {
type: "SubqueryFilter"
operation: Operation
column: Column
query: Subquery
}
104 changes: 0 additions & 104 deletions packages/sql/ast/filtering.ts

This file was deleted.

Loading