Skip to content

Commit

Permalink
Expose parseColumnType function (#316)
Browse files Browse the repository at this point in the history
  • Loading branch information
slvrtrn authored Sep 23, 2024
1 parent d930aa5 commit 9ab44fb
Show file tree
Hide file tree
Showing 21 changed files with 2,110 additions and 11 deletions.
22 changes: 17 additions & 5 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ on:
schedule:
- cron: '43 12 * * 6'
push:
branches: [ "main" ]
branches:
- main
paths-ignore:
- '**/*.md'
- 'LICENSE'
- 'benchmarks/**'
- 'examples/**'
pull_request:
paths-ignore:
- '**/*.md'
- 'LICENSE'
- 'benchmarks/**'
- 'examples/**'
workflow_dispatch:

# Declare default permissions as read only.
Expand All @@ -32,12 +44,12 @@ jobs:
# actions: read

steps:
- name: "Checkout code"
- name: 'Checkout code'
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false

- name: "Run analysis"
- name: 'Run analysis'
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
Expand All @@ -59,7 +71,7 @@ jobs:

# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
- name: 'Upload artifact'
uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20
with:
name: SARIF file
Expand All @@ -68,7 +80,7 @@ jobs:

# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
# 1.7.0 (Common, Node.js, Web)

- (Experimental) Exposed the `parseColumnType` function that takes a string representation of a ClickHouse type (e.g., `FixedString(16)`, `Nullable(Int32)`, etc.) and returns an AST-like object that represents the type. For example:

```ts
for (const type of [
'Int32',
'Array(Nullable(String))',
`Map(Int32, DateTime64(9, 'UTC'))`,
]) {
console.log(`##### Source ClickHouse type: ${type}`)
console.log(parseColumnType(type))
}
```

The above code will output:

```
##### Source ClickHouse type: Int32
{ type: 'Simple', columnType: 'Int32', sourceType: 'Int32' }
##### Source ClickHouse type: Array(Nullable(String))
{
type: 'Array',
value: {
type: 'Nullable',
sourceType: 'Nullable(String)',
value: { type: 'Simple', columnType: 'String', sourceType: 'String' }
},
dimensions: 1,
sourceType: 'Array(Nullable(String))'
}
##### Source ClickHouse type: Map(Int32, DateTime64(9, 'UTC'))
{
type: 'Map',
key: { type: 'Simple', columnType: 'Int32', sourceType: 'Int32' },
value: {
type: 'DateTime64',
timezone: 'UTC',
precision: 9,
sourceType: "DateTime64(9, 'UTC')"
},
sourceType: "Map(Int32, DateTime64(9, 'UTC'))"
}
```

While the original intention was to use this function internally for `Native`/`RowBinaryWithNamesAndTypes` data formats headers parsing, it can be useful for other purposes as well (e.g., interfaces generation, or custom JSON serializers).

NB: currently unsupported source types to parse:

- Geo
- (Simple)AggregateFunction
- Nested
- Old/new experimental JSON
- Dynamic
- Variant

# 1.6.0 (Common, Node.js, Web)

## New features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ describe('abort request', () => {
beforeEach(() => {
client = createTestClient()
})

afterEach(async () => {
await client.close()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ describe('ClickHouse server errors parsing', () => {
// Possible error messages here:
// (since 24.3+, Cloud SMT): Unknown expression identifier 'number' in scope SELECT number AS FR
// (since 23.8+, Cloud RMT): Missing columns: 'number' while processing query: 'SELECT number AS FR', required columns: 'number'
// (since 24.9+): Unknown expression identifier `number` in scope SELECT number AS FR
const errorMessagePattern =
`((?:Missing columns: 'number' while processing query: 'SELECT number AS FR', required columns: 'number')|` +
`(?:Unknown expression identifier 'number' in scope SELECT number AS FR))`
`(?:Unknown expression identifier ('|\`)number('|\`) in scope SELECT number AS FR))`
await expectAsync(
client.query({
query: 'SELECT number FR',
Expand All @@ -37,7 +38,7 @@ describe('ClickHouse server errors parsing', () => {
const dbName = getTestDatabaseName()
const errorMessagePattern =
`((?:^Table ${dbName}.unknown_table does not exist.*)|` +
`(?:Unknown table expression identifier 'unknown_table' in scope))`
`(?:Unknown table expression identifier ('|\`)unknown_table('|\`) in scope))`
await expectAsync(
client.query({
query: 'SELECT * FROM unknown_table',
Expand Down
56 changes: 56 additions & 0 deletions packages/client-common/__tests__/unit/parse_column_types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { parseFixedStringType } from '../../src/parse'

describe('Columns types parser', () => {
describe('FixedString', () => {
it('should parse FixedString', async () => {
const args: [string, number][] = [
['FixedString(1)', 1],
['FixedString(42)', 42],
['FixedString(100)', 100],
['FixedString(32768)', 32768],
]
args.forEach(([columnType, sizeBytes]) => {
const result = parseFixedStringType({
columnType,
sourceType: columnType,
})
expect(result)
.withContext(
`Expected ${columnType} to be parsed as a FixedString with size ${sizeBytes}`,
)
.toEqual({ type: 'FixedString', sizeBytes, sourceType: columnType })
})
})

it('should throw on invalid FixedString type', async () => {
const args: [string][] = [
['FixedString'],
['FixedString('],
['FixedString()'],
['String'],
]
args.forEach(([columnType]) => {
expect(() =>
parseFixedStringType({ columnType, sourceType: columnType }),
)
.withContext(`Expected ${columnType} to throw`)
.toThrowError('Invalid FixedString type')
})
})

it('should throw on invalid FixedString size', async () => {
const args: [string][] = [
['FixedString(0)'],
['FixedString(x)'],
[`FixedString(')`],
]
args.forEach(([columnType]) => {
expect(() =>
parseFixedStringType({ columnType, sourceType: columnType }),
)
.withContext(`Expected ${columnType} to throw`)
.toThrowError('Invalid FixedString size in bytes')
})
})
})
})
Loading

0 comments on commit 9ab44fb

Please sign in to comment.