Skip to content

Commit

Permalink
integer type support (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
rohit-kadhe authored Mar 23, 2024
1 parent eaccab5 commit 1c85dd9
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 131 deletions.
107 changes: 95 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,102 @@
# ClickHouse-Schema
# ClickHouse-Schema Guide

Clickhouse-Schema is a TypeScript library that simplifies working with ClickHouse databases by allowing developers to effortlessly define table schemas in TypeScript. This approach not only ensures robust type safety but also significantly reduces development time by automating the generation of TypeScript types that mirror your ClickHouse schemas.
In ClickHouse, defining and managing table schemas and their associated types can be done either manually or through the ClickHouse-Schema library. This guide compares these two approaches to illustrate the simplicity and efficiency ClickHouse-Schema brings to your projects.

## Key Benefits
## Traditional Manual Query Approach

- **Effortless TypeScript Integration**: Instantly define your ClickHouse table schemas within TypeScript, leveraging the full power of type safety without the hassle.
- **Time-Saving Type Generation**: Say goodbye to manually creating TypeScript types for your database tables. Clickhouse-Schema does it for you, automatically generating accurate types from your schema definitions.
- **Simplified Database Management**: Easily translate your TypeScript schema definition into a create table ClickHouse SQL query.
- **Comprehensive Data Type Support**: Utilize ClickHouse's extensive data type system, including complex types like JSON, arrays, enums, and more, right from your TypeScript code.
Traditionally, creating a table in clickhouse requires manually writing the SQL query and the interface in your code. This method is straightforward but prone to errors and inconsistencies, especially when schema changes occur.

### Create Table Query

```sql
CREATE TABLE IF NOT EXISTS students
(
id UInt32,
name String,
height float32,
age UInt8,
weight Float64,,
isStudent Boolean
)
# Manually defined
interface StudentsTableTypeManuallyDefined {
id: number,
name: string,
age: number,
height: number,
weight: number,
isStudent: boolean
}
```

**Did you notice any errors with the code below?** These would not get caught till runtime

## Using ClickHouse-Schema

ClickHouse-Schema automates schema creation and ensures type safety with minimal code, providing a more robust and maintainable solution.

### Defining Schema

``` typescript
const studentsTableSchema = new ClickhouseSchema({
id: { type: CHUInt32 },
name: { type: CHString },
age: { type: CHUInt8 },
height: { type: CHFloat32 },
weight: { type: CHFloat64 },
isStudent: { type: CHBoolean }
}, {
table_name: 'students',
primary_key: 'id'
})

//Automatic type inference. If schema changes type automatically changes too
type StudentsTableType = InferClickhouseSchemaType<typeof studentsTableSchema>
```
## Getting Started
### Installation
To start using ClickHouse-Schema in your projects, follow these steps:
1. **Installation**
To install ClickHouse-Schema, run the following command in your terminal:
```bash
npm install clickhouse-schema
```
2. **Create a Schema**
Define your table schema and provide options such as the table name and primary key. This will enable automatic type inference, making your code more robust and maintainable.
``` typescript
import { CHString, CHUUID, type InferClickhouseSchemaType } from '@clickhouse-schema'
const myTable = new ClickhouseSchema({
id: { type: CHUUID },
name: { type: CHString }
// Add more columns as needed
}, { table_name: 'my_table', primary_key: 'id' })

type MyTableType = InferClickhouseSchemaType<typeof myTable>
```
3. **Utilize Schema Methods**
ClickHouse-Schema provides several methods to streamline working with your database schema:
- Use `<your_schema>.GetCreateTableQuery()` to generate the SQL `CREATE TABLE` query.
- Use `<your_schema>.GetOptions()` to access the options passed when creating the table schema.
- Use `<your_schema>.GetCreateTableQueryAsList()` to get the `CREATE TABLE` query as a list of strings, which can be helpful for debugging or logging.
## Supported Types
- Integer (signed and unsigned integers): `UInt8, UInt16, UInt32, UInt64, UInt128, UInt256, Int8, Int16, Int32, Int64, Int128, Int256` types
- Floating-point numbers: `Float32` and `Float64` types
- Boolean: `Boolean` type
- Strings: `String` and `FixedString` types
- Dates: `Date`, `Date32`, `DateTime` and `DateTime64` types
- JSON: `JSON` type
- UUID: `UUID` type
- Arrays: `Array` type
- Nullable: `Nullable` type
```bash
npm install clickhouse-schema
# or
yarn add clickhouse-schema
And support for more types is coming!
6 changes: 5 additions & 1 deletion core/clickhouse_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class ClickhouseSchema<SchemaDefinition extends ChSchemaDefinition> imple
throw new Error('One of order_by or primary_key must be specified')
}

const columns = Object.entries(this.schema as Record<string, SchemaValue>)
const columns = Object.entries(this.schema as ChSchemaDefinition)
.map(([name, field]) => {
// Check if default is defined and a string, add single quotes; otherwise, just use the value
const defaultValue = field.default !== undefined
Expand Down Expand Up @@ -79,4 +79,8 @@ export class ClickhouseSchema<SchemaDefinition extends ChSchemaDefinition> imple
GetCreateTableQueryAsList (): string[] {
return this.GetCreateTableQuery().split('\n')
}

toString (): string {
return this.GetCreateTableQuery()
}
}
54 changes: 54 additions & 0 deletions data_types/ch_integer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ export class ChUInt64 implements ChDataType {
}
}

export class ChUInt128 implements ChDataType {
readonly typeStr: 'UInt128' = 'UInt128' as const
readonly dataTypeMarker = 'UInt128' as const

toString (): string {
return this.typeStr
}
}

export class ChUInt256 implements ChDataType {
readonly typeStr: 'UInt256' = 'UInt256' as const
readonly dataTypeMarker = 'UInt256' as const

toString (): string {
return this.typeStr
}
}

export class ChInt8 implements ChDataType {
readonly typeStr: 'Int8' = 'Int8' as const
readonly dataTypeMarker = 'Int8' as const
Expand All @@ -59,3 +77,39 @@ export class ChInt16 implements ChDataType {
return this.typeStr
}
}

export class ChInt32 implements ChDataType {
readonly typeStr: 'Int32' = 'Int32' as const
readonly dataTypeMarker = 'Int32' as const

toString (): string {
return this.typeStr
}
}

export class ChInt64 implements ChDataType {
readonly typeStr: 'Int64' = 'Int64' as const
readonly dataTypeMarker = 'Int64' as const

toString (): string {
return this.typeStr
}
}

export class ChInt128 implements ChDataType {
readonly typeStr: 'Int128' = 'Int128' as const
readonly dataTypeMarker = 'Int128' as const

toString (): string {
return this.typeStr
}
}

export class ChInt256 implements ChDataType {
readonly typeStr: 'Int256' = 'Int256' as const
readonly dataTypeMarker = 'Int256' as const

toString (): string {
return this.typeStr
}
}
4 changes: 2 additions & 2 deletions data_types/ch_json.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type SchemaValue } from '@clickhouse-schema-core/clickhouse_schema'
import { type ChSchemaDefinition } from '@clickhouse-schema-core/clickhouse_schema'
import { type ChDataType } from '@clickhouse-schema-data-types/index'

export class ChJSON<T extends Record<string, SchemaValue>> implements ChDataType {
export class ChJSON<T extends ChSchemaDefinition> implements ChDataType {
readonly typeStr: 'JSON'
readonly innerType: T
readonly dataTypeMarker = 'JSON' as const
Expand Down
102 changes: 75 additions & 27 deletions data_types/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type SchemaValue } from '@clickhouse-schema-core/clickhouse_schema'
import { type ChSchemaDefinition } from '@clickhouse-schema-core/clickhouse_schema'
import { ChArray } from '@clickhouse-schema-data-types/ch_array'
import { ChBoolean } from '@clickhouse-schema-data-types/ch_boolean'
import { ChDate, ChDate32, ChDateTime, ChDateTime64 } from '@clickhouse-schema-data-types/ch_date'
import { ChEnum } from '@clickhouse-schema-data-types/ch_enum'
import { ChFloat32, ChFloat64 } from '@clickhouse-schema-data-types/ch_float'
import { ChUInt8, ChUInt16, ChUInt32, ChUInt64, ChInt8, ChInt16 } from '@clickhouse-schema-data-types/ch_integer'
import { ChUInt8, ChUInt16, ChUInt32, ChUInt64, ChInt8, ChInt16, ChInt128, ChInt256, ChUInt128, ChUInt256, ChInt32, ChInt64 } from '@clickhouse-schema-data-types/ch_integer'
import { ChJSON } from '@clickhouse-schema-data-types/ch_json'
import { ChString, ChFixedString } from '@clickhouse-schema-data-types/ch_string'
import { ChUUID } from '@clickhouse-schema-data-types/ch_uuid'
Expand All @@ -16,38 +16,84 @@ export interface ChDataType {
toString: () => string
}

// Individual type definitions
// Integer types unsigned
export const CHUInt8 = new ChUInt8()
export const CHUInt16 = new ChUInt16()
export const CHUInt32 = new ChUInt32()
export const CHUInt64 = new ChUInt64()
export const CHUInt128 = new ChUInt128()
export const CHUInt256 = new ChUInt256()
// Integer types signed
export const CHInt8 = new ChInt8()
export const CHInt16 = new ChInt16()
export const CHInt32 = new ChInt32()
export const CHInt64 = new ChInt64()
export const CHInt128 = new ChInt128()
export const CHInt256 = new ChInt256()
// Float types
export const CHFloat32 = new ChFloat32()
export const CHFloat64 = new ChFloat64()
// Boolean type
export const CHBoolean = new ChBoolean()
// String types
export const CHString = new ChString()
export const CHFixedString = <T extends number>(length: T): ChFixedString<T> => new ChFixedString(length)
export const CHUUID = new ChUUID()
// Date types
export const CHDate = new ChDate()
export const CHDate32 = new ChDate32()
export const CHDateTime = <TZ extends string>(timezone: TZ): ChDateTime<TZ> => new ChDateTime(timezone)
export const CHDateTime64 = <P extends number, TZ extends string>(precision: P, timezone: TZ): ChDateTime64<P, TZ> => new ChDateTime64(precision, timezone)
// JSON type
export const CHJSON = <T extends ChSchemaDefinition>(schema: T): ChJSON<T> => new ChJSON(schema)
// Array, Enum, Nullable types
export const CHArray = <T extends ChDataType>(t: T): ChArray<T> => new ChArray(t)
export const CHEnum = <T extends Record<string, number>>(enumObj: T): ChEnum<T> => new ChEnum(enumObj)
export const CHNullable = <T extends ChPrimitiveType>(type: T): ChNullable<T> => new ChNullable(type)

// You can still export the entire ClickhouseTypes object if you wish
export const ClickhouseTypes = {
UInt8: new ChUInt8(),
UInt16: new ChUInt16(),
UInt32: new ChUInt32(),
UInt64: new ChUInt64(),
Int8: new ChInt8(),
Int16: new ChInt16(),
Float32: new ChFloat32(),
Float64: new ChFloat64(),
Boolean: new ChBoolean(),
String: new ChString(),
UUID: new ChUUID(),
Date: new ChDate(),
Date32: new ChDate32(),
DateTime: <TZ extends string>(timezone: TZ) => new ChDateTime(timezone),
DateTime64: <P extends number, TZ extends string>(precision: P, timezone: TZ) => new ChDateTime64(precision, timezone),
FixedString: <T extends number>(length: T) => new ChFixedString(length),
JSON: <T extends Record<string, SchemaValue>>(schema: T) => new ChJSON(schema),
Array: <T extends ChDataType>(t: T) => new ChArray(t),
Enum: <T extends Record<string, number>>(enumObj: T) => new ChEnum(enumObj),
Nullable: <T extends ChPrimitiveType>(type: T) => new ChNullable(type)
CHUInt8,
CHUInt16,
CHUInt32,
CHUInt64,
CHUInt128,
CHUInt256,
CHInt8,
CHInt16,
CHInt32,
CHInt64,
CHInt128,
CHInt256,
CHFloat32,
CHFloat64,
CHBoolean,
CHString,
CHUUID,
CHDate,
CHDate32,
CHDateTime,
CHDateTime64,
CHFixedString,
CHJSON,
CHArray,
CHEnum,
CHNullable
}

export interface MapChSchemaTypes {
UInt8: number
UInt16: number
UInt32: number
UInt64: number
UInt128: number
UInt256: number
Int8: number
Int16: number
Int32: number
Int64: number
Int128: number
Int256: number
Float32: number
Float64: number
Boolean: boolean
Expand All @@ -61,8 +107,10 @@ export interface MapChSchemaTypes {
}

export type ChPrimitiveType =
ChBoolean | ChUInt8 | ChUInt16 | ChUInt32 | ChUInt64 | ChInt8 | ChInt16 |
ChFloat32 | ChFloat64 | ChString | ChUUID | ChDate | ChDate32 | ChDateTime<string> |
ChDateTime64<number, string> | ChFixedString<number>
ChUInt8 | ChUInt16 | ChUInt32 | ChUInt64 | ChUInt128 | ChUInt256 |
ChInt8 | ChInt16 | ChInt32 | ChInt64 | ChInt128 | ChInt256 |
ChFloat32 | ChFloat64 | ChBoolean |
ChDate | ChDate32 | ChDateTime<string> | ChDateTime64<number, string> |
ChUUID | ChFixedString<number> | ChString

export type ChCompositeType = ChArray<ChArray<ChDataType> | ChDataType> | ChEnum<Record<string, number>> | ChNullable<ChPrimitiveType>
export type ChCompositeType = ChArray<ChArray<ChDataType> | ChDataType> | ChEnum<Record<string, number>> | ChNullable<ChPrimitiveType> | ChJSON<ChSchemaDefinition>
46 changes: 0 additions & 46 deletions examples/server.ts

This file was deleted.

Loading

1 comment on commit 1c85dd9

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 100% 187/187
🟢 Branches 100% 25/25
🟢 Functions 100% 67/67
🟢 Lines 100% 170/170

Test suite run success

21 tests passing in 2 suites.

Report generated by 🧪jest coverage report action from 1c85dd9

Please sign in to comment.