Skip to content

Commit

Permalink
fix: adds missing type inferences for entries of IN-/UPSERT
Browse files Browse the repository at this point in the history
  • Loading branch information
stockbal committed Nov 29, 2024
1 parent e5b8490 commit b462352
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).

## Version 0.9.0 - tbd

### Fixed
- Added missing type inference for `.entries` of `UPSERT` and `INSERT`

## Version 0.8.0 - 24-11-26

### Fixed
Expand Down
3 changes: 2 additions & 1 deletion apis/internal/query.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ export interface And {
export interface InUpsert<T> {
data (block: (e: T) => void): this

entries (...entries: object[]): this
entries (...entries: T[]): this
entries (entries: T[]): this

values (...val: (null | Primitive)[]): this
values (val: (null | Primitive)[]): this
Expand Down
18 changes: 10 additions & 8 deletions apis/ql.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,13 @@ export interface INSERT<T> extends Columns<T>, InUpsert<T> {}
export class INSERT<T> extends ConstructedQuery<T> {
private constructor();

static into: (<T extends ArrayConstructable> (entity: T, entries?: Entries) => INSERT<SingularInstanceType<T>>)
static into: (<T extends ArrayConstructable> (entity: T, ...entries: SingularInstanceType<T>[]) => INSERT<SingularInstanceType<T>>)
& (<T extends ArrayConstructable> (entity: T, entries?: SingularInstanceType<T>[]) => INSERT<SingularInstanceType<T>>)
& (TaggedTemplateQueryPart<INSERT<unknown>>)
& ((entity: EntityDescription, ...entries: Entries[]) => INSERT<StaticAny>)
& ((entity: EntityDescription, entries?: Entries) => INSERT<StaticAny>)
& (<T> (entity: Constructable<T>, entries?: Entries) => INSERT<T>)
& (<T> (entity: T, entries?: T | Entries) => INSERT<T>)
& (<T> (entity: Constructable<T>, ...entries: T[]) => INSERT<T>)
& (<T> (entity: Constructable<T>, entries?: T[]) => INSERT<T>)

/**
* @deprected
Expand All @@ -207,13 +209,13 @@ export interface UPSERT<T> extends Columns<T>, InUpsert<T> {}
export class UPSERT<T> extends ConstructedQuery<T> {
private constructor();

static into: (<T extends ArrayConstructable> (entity: T, entries?: Entries) => UPSERT<SingularInstanceType<T>>)
static into: (<T extends ArrayConstructable> (entity: T, ...entries: SingularInstanceType<T>[]) => UPSERT<SingularInstanceType<T>>)
& (<T extends ArrayConstructable> (entity: T, entries?: SingularInstanceType<T>[]) => UPSERT<SingularInstanceType<T>>)
& (TaggedTemplateQueryPart<UPSERT<StaticAny>>)
& ((entity: EntityDescription, ...entries: Entries[]) => UPSERT<StaticAny>)
& ((entity: EntityDescription, entries?: Entries) => UPSERT<StaticAny>)
& (<T> (entity: Constructable<T>, entries?: Entries) => UPSERT<T>)
// currently no easy way to restrict T to non-primitives
& (<T> (entity: T, entries?: T | Entries) => UPSERT<T>)

& (<T> (entity: Constructable<T>, ...entries: T[]) => UPSERT<T>)
& (<T> (entity: Constructable<T>, entries?: T[]) => UPSERT<T>)

UPSERT: CQN.UPSERT['UPSERT']

Expand Down
43 changes: 42 additions & 1 deletion test/typescript/apis/project/cds-ql.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Definition } from '../../../../apis/csn';
import { QLExtensions } from '../../../../apis/ql'
import { linked } from '../../../../apis/models';
import { Foo, Foos, attach } from './dummy'

// @ts-expect-error - only supposed to be used statically, constructors private
Expand Down Expand Up @@ -87,7 +89,7 @@ SELECT(Foos) === SELECT.from(Foos)

INSERT.into(Foos).columns("x") // x was suggested by code completion
let ins: INSERT<Foo>
ins = INSERT.into(Foos, {})
ins = INSERT.into(Foos, { x: 4 })
ins.into(Foos)
ins.into(Foos)
ins.columns("x") // x was suggested by code completion
Expand Down Expand Up @@ -278,3 +280,42 @@ INSERT.into('Foos').rows([[1,2,3]])
INSERT.into('Foos').rows([[1,2,3],[1,2]])
// @ts-expect-error
INSERT.into('Foos').values([[1,2,3]])

// Type checks with typed INSERT
// @ts-expect-error - invalid property of Foo
INSERT.into(Foos).entries({ a: "" })
// @ts-expect-error - invalid property of Foo
INSERT.into(Foos).entries([{ a: "" }])
INSERT.into(Foos).entries({ x: 4, ref: { x: 4 }, refs: [] })
INSERT.into(Foo).entries({ x: 4 }, { x: 1 }, { x: 4, ref: { x: 1 } })
// @ts-expect-error - invalid type for property x of Foo
INSERT.into(Foo).entries({ x: "4" })
INSERT.into(Foo, { x: 4, ref: { x: 2 }})
INSERT.into(Foo, [{ x: 4 }])

INSERT.into("Foo", [{ x: "4" }])
INSERT.into("Foo", { x: "4" }, { "ref": "4" })

INSERT.into({} as Definition, { x : 4, "other": 5 }, { a : 4})
INSERT.into({} as Definition, [{ x : 4, "other": 5 }, { a : 4}])
INSERT.into({} as linked.classes.entity, { "a": 4 })

// Type checks with typed UPSERTs
// @ts-expect-error - invalid property of Foo
UPSERT.into(Foos).entries({ a: "" })
// @ts-expect-error - invalid property of Foo
UPSERT.into(Foos).entries([{ a: "" }])
UPSERT.into(Foos).entries({ x: 4, ref: { x: 4 }, refs: [] })
UPSERT.into(Foo).entries({ x: 4 }, { x: 1 }, { x: 4, ref: { x: 1 } })
// @ts-expect-error - invalid type for property x of Foo
UPSERT.into(Foo).entries({ x: "4" })
UPSERT.into(Foo, { x: 4, ref: { x: 2 }})
UPSERT.into(Foo, [{ x: 4 }])

UPSERT.into("Foo", [{ x: "4" }])
UPSERT.into("Foo", { x: "4" }, { "ref": "4" })

UPSERT.into({} as Definition, { x : 4, "other": 5 }, { a : 4})
UPSERT.into({} as Definition, [{ x : 4, "other": 5 }])

UPSERT.into({} as linked.classes.entity, { "a": 4 })
2 changes: 1 addition & 1 deletion test/typescript/apis/project/cds-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const up: UPSERT<Foos> = await srv.upsert(Foos)
const d: DELETE<Foos> = await srv.delete(Foos)

// queries
const query = INSERT.into({}, { ID: 111, name: 'Mark Twain' })
const query = INSERT.into("Authors", { ID: 111, name: 'Mark Twain' })
await srv.run(query)
await srv.run([query, query])
await srv.run('SELECT * from Authors where name like ?', ['%Poe%'])
Expand Down

0 comments on commit b462352

Please sign in to comment.