标识符语法
在API的许多地方,可以将诸如表名或列名之类的标识符传递给方法。
通常一个最需要的只是普通的tableName.columnName
,tableName
或者columnName
,但在许多情况下,人们还需要通过一个别名怎么说标识符后来在查询简称。
有两种方法来声明标识符的别名。可以直接给as aliasName
标识符加上后缀(例如identifierName as aliasName
),也可以通过一个对象{ aliasName: 'identifierName' }
。
如果对象具有多个别名{ alias1: 'identifier1', alias2: 'identifier2' }
,则所有别名标识符都将扩展为逗号分隔的列表。
注意:标识符语法没有选择模式的位置,因此,如果这样做schemaName.tableName
,查询可能会显示为错误。使用.withSchema('schemaName')
代替。
knex({ a: 'table', b: 'table' })
.select({
aTitle: 'a.title',
bTitle: 'b.title'
})
.whereRaw('?? = ??', ['a.column_1', 'b.column_2'])
输出:
select [a].[title] as [aTitle], [b].[title] as [bTitle] from [table] as [a], [table] as [b] where [a].[column_1] = [b].[column_2]
关节 -knex(tableName, options={only: boolean}) / knex.[methodName]
通过指定要查询的tableName或直接在knex对象上调用任何方法,查询构建器开始。这将启动类似于jQuery的链,您可以根据需要调用其他查询构建器方法来构建查询,最终调用任何接口方法来转换为toString或使用promise,回调或流执行查询。传递选项的可选第二个参数: 仅:如果:true
,则在之前使用ONLY关键字tableName
来丢弃继承表的数据。*注意:目前仅在PostgreSQL中受支持。
TypeScript的用法
如果使用TypeScript,则可以将数据库行的类型作为类型参数传递,以在链中获得更好的自动完成支持。
interface User {
id: number;
name: string;
age: number;
}
knex('users')
.where('id')
.first(); // Resolves to any
knex<User>('users') // User is the type of row in database
.where('id', 1) // Your IDE will be able to help with the completion of id
.first(); // Resolves to User | undefined
通过JSDoc注释以纯JavaScript编写代码时,还可以利用自动完成支持(在支持TypeScript的IDE中)和泛型类型参数。
/**
* @typedef {Object} User
* @property {number} id
* @property {number} age
* @property {string} name
*
* @returns {Knex.QueryBuilder<User, {}>}
*/
const Users = () => knex('Users')
Users().where('id', 1) // 'id' property can be autocompleted by editor
使用类型推断和可变的流畅API的警告
大多数knex API都会变异当前对象并返回它。此模式不适用于类型推断。
knex<User>('users')
.select('id')
.then((users) => { // Type of users is inferred as Pick<User, "id">[]
// Do something with users
});
knex<User>('users')
.select('id')
.select('age')
.then((users) => { // Type of users is inferred as Pick<User, "id" | "age">[]
// Do something with users
});
// The type of usersQueryBuilder is determined here
const usersQueryBuilder = knex<User>('users').select('id');
if (someCondition) {
// This select will not change the type of usersQueryBuilder
// We can not change the type of a pre-declared variabe in TypeScript
usersQueryBuilder.select('age');
}
usersQueryBuilder.then((users) => {
// Type of users here will be Pick<User, "id">[]
// which may not be what you expect.
});
// You can specify the type of result explicitly through a second type parameter:
const queryBuilder = knex<User, Pick<User, "id" | "age">>('users');
// But there is no type constraint to ensure that these properties have actually been
// selected.
// So, this will compile:
queryBuilder.select('name').then((users) => {
// Type of users is Pick<User, "id"> but it will only have name
})
如果您不想手动指定结果类型,建议始终使用链的最后一个值的类型,并将将来任何链延续的结果分配给单独的变量(类型将不同)。
超时 -.timeout(ms, options={cancel: boolean})
设置查询超时,如果超过超时,将抛出TimeoutError。该错误包含有关查询,绑定和设置的超时的信息。对于要确保不会花费太长时间执行的复杂查询很有用。传递选项的可选第二个参数: cancel:if true
,如果达到超时则取消查询。*注意:目前仅在MySQL和PostgreSQL中受支持。
knex.select().from('books').timeout(1000)
输出:
select * from [books]
knex.select().from('books').timeout(1000, {cancel: true}) // MySQL and PostgreSQL only
错误:
Query cancelling not supported for this dialect
选择 —.select([*columns])
创建一个选择查询,为查询获取一个可选的列数组,如果在构建查询时未指定任何列,则最终默认为*。select调用的响应将使用从数据库中选择的对象数组解决。
knex.select('title', 'author', 'year').from('books')
输出:
select [title], [author], [year] from [books]
knex.select().table('books')
输出:
select * from [books]
TypeScript的用法
只要选择参数与记录类型中的键名完全匹配,我们通常就可以根据所选列来推断结果类型。但是,别名和作用域可能会妨碍推理。
knex.select('id').from<User>('users'); // Resolves to Pick<User, "id">[]
knex.select('users.id').from<User>('users'); // Resolves to any[]
// ^ TypeScript doesn't provide us a way to look into a string and infer the type
// from a substring, so we fall back to any
// We can side-step this using knex.ref:
knex.select(knex.ref('id').withSchema('users')).from<User>('users'); // Resolves to Pick<User, "id">[]
knex.select('id as identifier').from<User>('users'); // Resolves to any[], for same reason as above
// Refs are handy here too:
knex.select(knex.ref('id').as('identifier')).from<User>('users'); // Resolves to { identifier: number; }[]
作为 -.as(name)
允许对子查询使用别名,并使用您希望为当前查询命名的字符串。如果查询不是子查询,它将被忽略。
knex.avg('sum_column1').from(function() {
this.sum('column1 as sum_column1').from('t1').groupBy('column1').as('t1')
}).as('ignored_alias')
输出:
select avg([sum_column1]) from (select sum([column1]) as [sum_column1] from [t1] group by [column1]) as [t1]
列 -.column(columns)
专门设置要在选择查询中选择的列,采用数组,对象或列名列表。传递对象会自动使用给定的键对列进行别名。
knex.column('title', 'author', 'year').select().from('books')
输出:
select [title], [author], [year] from [books]
knex.column(['title', 'author', 'year']).select().from('books')
输出:
select [title], [author], [year] from [books]
knex.column('title', {by: 'author'}, 'year').select().from('books')
输出:
select [title], [author] as [by], [year] from [books]
来自 —.from([tableName], options={only: boolean})
指定当前查询中使用的表,如果已经指定了当前表名,则替换当前表名。这通常用在高级where或union方法中执行的子查询中。传递选项的可选第二个参数: 仅:如果:true
,则在之前使用ONLY关键字tableName
来丢弃继承表的数据。*注意:目前仅在PostgreSQL中受支持。
knex.select('*').from('users')
输出:
select * from [users]
TypeScript的用法
我们可以通过TRecord type参数指定数据库行的类型
knex.select('id').from('users'); // Resolves to any[]
knex.select('id').from<User>('users'); // Results to Pick<User, "id">[]
与 -.with(alias, function|raw)
在查询中添加一个“ with”子句。PostgreSQL,Oracle,SQLite3和MSSQL支持“带有”子句。
knex.with('with_alias', knex.raw('select * from "books" where "author" = ?', 'Test')).select('*').from('with_alias')
输出:
with [with_alias] as (select * from "books" where "author" = 'Test') select * from [with_alias]
knex.with('with_alias', (qb) => {
qb.select('*').from('books').where('author', 'Test')
}).select('*').from('with_alias')
输出:
with [with_alias] as (select * from [books] where [author] = 'Test') select * from [with_alias]
withRecursive —.withRecursive(alias, function|raw)
与该with
方法相同,但在“ with”后附加“递归”,以使自引用CTE成为可能。
knex.withRecursive('ancestors', (qb) => {
qb.select('*').from('people').where('people.id', 1).union((qb) => {
qb.select('*').from('people').join('ancestors', 'ancestors.parentId', 'people.id')
})
}).select('*').from('ancestors')
输出:
with recursive [ancestors] as (select * from [people] where [people].[id] = 1 union select * from [people] inner join [ancestors] on [ancestors].[parentId] = [people].[id]) select * from [ancestors]
withSchema —.withSchema([schemaName])
指定用作表名前缀的模式。
knex.withSchema('public').select('*').from('users')
输出:
select * from [public].[users]