@pdg/drizzle-mssql 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +408 -2
- package/dist/@types/MsSqlConditions.d.cts +20 -0
- package/dist/@types/MsSqlConditions.d.ts +20 -0
- package/dist/@types/MsSqlInsertValues.d.cts +21 -0
- package/dist/@types/MsSqlInsertValues.d.ts +21 -0
- package/dist/@types/MsSqlUpdateValues.d.cts +28 -0
- package/dist/@types/MsSqlUpdateValues.d.ts +28 -0
- package/dist/@types/common.d.cts +16 -0
- package/dist/@types/common.d.ts +16 -0
- package/dist/@types/index.d.cts +4 -0
- package/dist/@types/index.d.ts +4 -0
- package/dist/MsSqlQuery.d.cts +259 -0
- package/dist/MsSqlQuery.d.ts +259 -0
- package/dist/alias.d.cts +6 -0
- package/dist/alias.d.ts +6 -0
- package/dist/columns.d.cts +90 -0
- package/dist/columns.d.ts +90 -0
- package/dist/conditions.d.cts +106 -0
- package/dist/conditions.d.ts +106 -0
- package/dist/drizzleMsSql.d.cts +166 -0
- package/dist/drizzleMsSql.d.ts +166 -0
- package/dist/index.cjs +700 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.esm.js +700 -0
- package/dist/mssqlTable.d.cts +71 -0
- package/dist/mssqlTable.d.ts +71 -0
- package/package.json +88 -4
package/README.md
CHANGED
|
@@ -1,3 +1,409 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @pdg/drizzle-mssql
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Drizzle ORM과 `mssql`을 사용하는 Node.js용 SQL Server 보조 라이브러리입니다. `drizzle-orm@1.0.0-rc.5`를 기준으로 합니다.
|
|
4
|
+
|
|
5
|
+
## 설치
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @pdg/drizzle-mssql drizzle-orm@1.0.0-rc.5 mssql@^11
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 사용
|
|
12
|
+
|
|
13
|
+
### 연결과 스키마
|
|
14
|
+
|
|
15
|
+
테이블 정의에는 Drizzle의 SQL Server 스키마 API를 패키지 루트에서 가져올 수 있습니다. 연결은 `drizzleMsSql`에 `mssql` 드라이버의 SQL Server 연결 문자열과 스키마를 전달해 만듭니다.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
drizzleMsSql,
|
|
20
|
+
datetime2,
|
|
21
|
+
int,
|
|
22
|
+
mssqlTable,
|
|
23
|
+
nvarchar,
|
|
24
|
+
} from '@pdg/drizzle-mssql';
|
|
25
|
+
|
|
26
|
+
const users = mssqlTable('users', {
|
|
27
|
+
id: int('id').identity().primaryKey(),
|
|
28
|
+
name: nvarchar('name', { length: 100 }).notNull(),
|
|
29
|
+
email: nvarchar('email', { length: 255 }),
|
|
30
|
+
created_at: datetime2('created_at'),
|
|
31
|
+
updated_at: datetime2('updated_at'),
|
|
32
|
+
});
|
|
33
|
+
const posts = mssqlTable('posts', {
|
|
34
|
+
id: int('id').identity().primaryKey(),
|
|
35
|
+
user_id: int('user_id').notNull(),
|
|
36
|
+
title: nvarchar('title', { length: 200 }).notNull(),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const db = drizzleMsSql({
|
|
40
|
+
url: process.env.DATABASE_URL!,
|
|
41
|
+
schema: { users, posts },
|
|
42
|
+
getTimestamp: () => new Date(),
|
|
43
|
+
});
|
|
44
|
+
const user = db.query(users);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`drizzleMsSql` 옵션은 필수인 `url`, `schema`, `getTimestamp`입니다. `new MsSqlQuery(table, db.current, getTimestamp?)`에서 생성 함수를 지정하면 해당 쿼리에서 우선 사용합니다. `db.query(table)`은 해당 테이블에 맞춰 타입이 지정된 쿼리 객체를 반환합니다. 연결을 다 사용한 뒤 `await db.close()`로 커넥션 풀을 닫습니다.
|
|
48
|
+
|
|
49
|
+
### 데이터 추가·수정·삭제
|
|
50
|
+
|
|
51
|
+
`user.insertValues(...)`와 `user.updateValues(...)`는 테이블의 입력 타입을 검사하고 전달한 값을 그대로 반환합니다. 실제 정책 검사와 시각 생성은 `add`와 `edit`에서 수행합니다.
|
|
52
|
+
|
|
53
|
+
IDENTITY 컬럼이 있는 테이블에서 `add`는 `OUTPUT`으로 생성된 값을 반환합니다. 여러 행을 넣으면 값의 배열을 반환하고, IDENTITY 컬럼이 없으면 단일 행에는 `undefined`, 여러 행에는 `undefined` 배열을 반환합니다. 해당 INSERT 동작에 활성 트리거가 있는 테이블에서는 SQL Server가 결과를 직접 반환하는 `OUTPUT`을 허용하지 않습니다. 생성 키의 타입은 IDENTITY 컬럼의 타입을 따릅니다.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const id = (await user.add({ name: '홍길동', email: 'hong@example.com' })) as number;
|
|
57
|
+
const ids = await user.add([
|
|
58
|
+
{ name: '김민수', email: 'minsu@example.com' },
|
|
59
|
+
{ name: '이서연', email: 'seoyeon@example.com' },
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
await user.editByPrimaryKey({ name: '김민수' }, id);
|
|
63
|
+
await user.removeByPrimaryKey(id);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
조건으로 수정·삭제할 때는 반드시 SQL 조건을 전달해야 합니다. 실수로 테이블 전체를 갱신하거나 삭제하지 않도록 조건이 없으면 오류가 발생합니다.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
await user.edit({ name: '수정된 이름' }, user.eq({ id }));
|
|
70
|
+
await user.remove(user.eq({ id }));
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
복합 기본 키 테이블은 기본 키 컬럼명을 모두 포함한 객체를 사용합니다. 단일 기본 키는 값 하나 또는 기본 키 객체를 전달할 수 있습니다. 테이블 수준으로 정의한 복합 기본 키는 Drizzle 타입에 컬럼 목록이 노출되지 않으므로 런타임에 필수 키를 검사합니다.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const found = await user.findByPrimaryKey(id);
|
|
77
|
+
const exists = await user.existsByPrimaryKey(id);
|
|
78
|
+
const missing = await user.notExistsByPrimaryKey(id);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 조회와 컬럼 선택
|
|
82
|
+
|
|
83
|
+
`select`는 Drizzle 조회 빌더를 반환하므로 `where`, `orderBy`, `offset`, `fetch` 등 Drizzle의 빌더 메서드를 이어서 사용할 수 있습니다. `find`는 한 행을 조회하며, 결과가 없으면 `undefined`를 반환합니다.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const rows = await user
|
|
87
|
+
.select(['id', 'name'])
|
|
88
|
+
.where(user.gt({ id: 0 }))
|
|
89
|
+
.orderBy(user.t.id)
|
|
90
|
+
.offset(0)
|
|
91
|
+
.fetch(20);
|
|
92
|
+
|
|
93
|
+
const found = await user.find(['id', 'name'], user.eq({ id }));
|
|
94
|
+
const count = await user.count(user.isNotNull('email'));
|
|
95
|
+
const exists = await user.exists(user.eq({ email: 'hong@example.com' }));
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
컬럼 선택에는 컬럼명 배열, Drizzle 선택 객체, 또는 `columns()`를 사용하는 콜백을 사용할 수 있습니다. `columns()`는 전체 컬럼 또는 지정한 컬럼만 가져오며, `as`로 결과 키를 지정할 수 있습니다.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const allColumns = user.columns();
|
|
102
|
+
const selectedColumns = user.columns('id', 'name as displayName');
|
|
103
|
+
|
|
104
|
+
const projected = await user.find(
|
|
105
|
+
(query) => [query.columns('id', 'name as displayName')],
|
|
106
|
+
user.eq({ id })
|
|
107
|
+
);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
테이블의 TypeScript 속성명과 SQL 컬럼명을 다르게 지정하면 기본 전체 조회 결과 키와 추론된 타입이 달라질 수 있습니다. 기본 컬럼 선택을 사용할 경우 스키마 속성명과 SQL 컬럼명을 같게 작성하는 것을 권장합니다. 이름이 다르면 필요한 컬럼을 명시적으로 선택하고 별칭을 지정하세요.
|
|
111
|
+
|
|
112
|
+
문자열 컬럼 별칭의 `as`는 `AS`, `As`, `aS`도 지원하며 결과 키의 대소문자는 유지합니다.
|
|
113
|
+
|
|
114
|
+
### 조건식
|
|
115
|
+
|
|
116
|
+
조건 함수는 `db` 연결 객체나 `db.query(table)`이 반환한 쿼리 객체에서 사용할 수 있습니다. 쿼리 객체 메서드는 해당 테이블의 컬럼을 기준으로 타입을 검사하고, `db` 메서드는 테이블 객체 또는 연결 스키마에 등록된 스키마 키를 함께 받습니다.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const byName = user.eq({ name: '홍길동' });
|
|
120
|
+
const bySchemaKey = db.eq('users', { name: '홍길동' });
|
|
121
|
+
const byTable = db.eq(users, { name: '홍길동' });
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`createConditions(schema)`를 직접 호출해도 같은 조건 함수를 만들 수 있습니다. 독립된 조건 빌더가 필요할 때 사용하며, 반환된 함수는 생성할 때 전달한 스키마의 키와 테이블을 기준으로 동작합니다.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { createConditions } from '@pdg/drizzle-mssql';
|
|
128
|
+
|
|
129
|
+
const condition = createConditions({ users });
|
|
130
|
+
const where = condition.and('users', {
|
|
131
|
+
gte: { id: 1 },
|
|
132
|
+
isNotNull: 'email',
|
|
133
|
+
});
|
|
134
|
+
const rows = await user.select().where(where);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### 비교 연산자
|
|
138
|
+
|
|
139
|
+
`eq`, `ne`, `gt`, `gte`, `lt`, `lte`는 컬럼과 값을 비교합니다. 하나의 값 객체에 여러 컬럼을 넣으면 각 비교가 `AND`로 묶입니다. `undefined` 값은 생략되므로 선택적 검색 조건을 만들 때 유용합니다.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
const filters = {
|
|
143
|
+
name: searchName,
|
|
144
|
+
email: searchEmail,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const rows = await user.find((query) =>
|
|
148
|
+
query.eq({
|
|
149
|
+
name: filters.name,
|
|
150
|
+
email: filters.email,
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const changedIds = await user
|
|
155
|
+
.select(['id'])
|
|
156
|
+
.where(user.and({
|
|
157
|
+
gte: { id: 10 },
|
|
158
|
+
lte: { id: 50 },
|
|
159
|
+
}));
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`eq({ email: null })`은 `IS NULL`, `ne({ email: null })`은 `IS NOT NULL`로 변환됩니다. `gt` 등의 비교 연산자에는 `null`을 전달할 수 없습니다.
|
|
163
|
+
|
|
164
|
+
#### 배열과 범위
|
|
165
|
+
|
|
166
|
+
`inArray`와 `notInArray`는 컬럼별 허용·제외 값 배열을 받고, `between`과 `notBetween`은 `[시작, 끝]` 튜플을 받습니다. 한 객체에 여러 컬럼을 지정하면 각각의 조건은 `AND`로 결합됩니다.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const selected = await user.find((query) =>
|
|
170
|
+
query.and({
|
|
171
|
+
inArray: { id: [1, 3, 5, 7] },
|
|
172
|
+
notInArray: { name: ['차단 사용자', '삭제 사용자'] },
|
|
173
|
+
between: { id: [1, 100] },
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const recentIds = await user
|
|
178
|
+
.select(['id'])
|
|
179
|
+
.where(user.notBetween({ id: [1, 10] }));
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
범위 양 끝은 `null`이나 `undefined`가 아닌 값이어야 합니다. `inArray`와 `notInArray`의 값은 배열이어야 합니다.
|
|
183
|
+
|
|
184
|
+
#### 문자열 패턴
|
|
185
|
+
|
|
186
|
+
`like`, `notLike`, `ilike`, `notIlike`는 문자열 컬럼에 SQL 패턴을 적용합니다. `%`는 임의 길이 문자열, `_`는 한 문자에 대응합니다. `ilike` 계열은 대소문자를 구분하지 않는 `ILIKE` 연산자를 생성하지만, SQL Server는 `ILIKE` 문법을 지원하지 않으므로 SQL Server 쿼리에서는 사용하지 마세요. SQL Server의 `LIKE` 대소문자 구분 여부는 컬럼 collation 설정에 따릅니다.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
const matchingUsers = await user.find((query) =>
|
|
190
|
+
query.or({
|
|
191
|
+
like: { email: '%@example.com' },
|
|
192
|
+
eq: { name: 'Kim' },
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const excludedNames = await user
|
|
197
|
+
.select()
|
|
198
|
+
.where(user.notLike({ name: '테스트_%' }));
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
패턴 연산은 문자열 컬럼에만 사용할 수 있으며, 값은 `%홍길동%`처럼 SQL 패턴 문자열로 전달합니다. `ilike` / `notIlike`는 패키지의 조건 함수 목록에는 있지만 SQL Server에서는 실행할 수 없습니다.
|
|
202
|
+
|
|
203
|
+
#### NULL 검사
|
|
204
|
+
|
|
205
|
+
`isNull`과 `isNotNull`은 컬럼명 하나 또는 컬럼명 배열을 받습니다. 배열 안의 컬럼 검사는 `AND`로 결합됩니다. 검색 조건에 따라 컬럼 검사를 생략하려면 `undefined`를 전달할 수 있습니다.
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
const noEmail = await user.find((query) => query.isNull('email'));
|
|
209
|
+
const hasNameAndEmail = await user.find((query) =>
|
|
210
|
+
query.isNotNull(['name', 'email'])
|
|
211
|
+
);
|
|
212
|
+
const optionalNullCheck = user.isNull(shouldCheckEmail ? 'email' : undefined);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### AND·OR 조합
|
|
216
|
+
|
|
217
|
+
`query.and({ ... })`와 `query.or({ ... })`는 여러 연산자 그룹을 객체로 구성합니다. 한 연산자 아래의 컬럼 비교는 먼저 `AND`로 묶이고, 바깥 함수가 각 연산자 그룹을 `AND` 또는 `OR`로 결합합니다. `and` / `or` 객체는 조건 그룹이며, 그 안에 다시 `and` / `or`를 중첩하는 형식은 지원하지 않습니다.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
const usersMatchingEither = await user.find((query) =>
|
|
221
|
+
query.or({
|
|
222
|
+
eq: { name: '홍길동' },
|
|
223
|
+
like: { email: '%@example.com' },
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const activeCandidates = await user.find((query) =>
|
|
228
|
+
query.and({
|
|
229
|
+
isNotNull: 'email',
|
|
230
|
+
ne: { name: '탈퇴 사용자' },
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
여러 조건을 임의로 중첩하거나 이미 만든 SQL 조건을 결합할 때는 `db.and(...)` / `db.or(...)`의 Drizzle 호환 오버로드를 사용합니다. 이 형식에서는 함수 호출 인자로 SQL 조건을 직접 조합할 수 있습니다.
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
const nameOrEmail = db.or(
|
|
239
|
+
user.eq({ name: '홍길동' }),
|
|
240
|
+
user.like({ email: '%@example.com' }),
|
|
241
|
+
);
|
|
242
|
+
const condition = db.and(
|
|
243
|
+
nameOrEmail,
|
|
244
|
+
db.isNotNull(users.email),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const matchingUsers = await user.select().where(condition);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
같은 함수는 테이블 객체와 조건 객체를 받아 그룹 조건을 만들 수도 있습니다.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
const groupedCondition = db.and(users, {
|
|
254
|
+
gte: { id: 1 },
|
|
255
|
+
isNotNull: ['name', 'email'],
|
|
256
|
+
});
|
|
257
|
+
const groupedUsers = await user.select().where(groupedCondition);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Drizzle 컬럼 연산자와 함께 사용
|
|
261
|
+
|
|
262
|
+
`db`의 조건 함수는 테이블/객체 형식 외에도 Drizzle의 컬럼 기반 연산자 오버로드를 그대로 사용할 수 있습니다. `SQL` 조건은 래퍼 조회 메서드에 전달하거나 Drizzle 조회 빌더에서 조합할 수 있습니다.
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
const columnCondition = db.and(
|
|
266
|
+
db.eq(users.name, '홍길동'),
|
|
267
|
+
db.isNotNull(users.email),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const rows = await user.select().where(columnCondition);
|
|
271
|
+
const count = await user.count(columnCondition);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
지원하는 객체 조건 함수는 `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `inArray`, `notInArray`, `between`, `notBetween`, `like`, `notLike`, `ilike`, `notIlike`, `isNull`, `isNotNull`, `and`, `or`입니다. 존재하지 않는 스키마 키나 컬럼, 잘못된 값 형식은 조건을 조용히 생략하지 않고 오류로 처리합니다.
|
|
275
|
+
|
|
276
|
+
### 별칭과 조인
|
|
277
|
+
|
|
278
|
+
`db.a`는 연결에 전달한 스키마의 테이블별 별칭 생성 함수입니다. 별칭 테이블은 선택 및 조건식에 사용할 수 있습니다. `select`가 반환하는 Drizzle 빌더에서 조인을 이어서 작성할 수 있습니다.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const u = db.a.users('u');
|
|
282
|
+
const rows = await user
|
|
283
|
+
.select(u, ['id', 'name'])
|
|
284
|
+
.where(db.eq(u, { name: '홍길동' }));
|
|
285
|
+
|
|
286
|
+
const userPosts = await user
|
|
287
|
+
.select()
|
|
288
|
+
.leftJoin(posts, db.eq(users.id, posts.user_id));
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
기본 별칭은 스키마 키의 첫 글자와 대문자 위치를 기준으로 만듭니다. 예를 들어 `userProfile`의 기본 별칭은 `up`이며, `db.a.userProfile('profile')`처럼 직접 지정할 수도 있습니다.
|
|
292
|
+
|
|
293
|
+
### 페이지네이션
|
|
294
|
+
|
|
295
|
+
`db.paginate(builder, page, limit)`은 조회 데이터와 페이지 정보를 함께 반환합니다. 페이지와 페이지 크기는 양의 정수여야 합니다. SQL Server 2012 이상의 `OFFSET … FETCH`를 사용합니다. `orderBy`가 없으면 `(select 0)`을 사용하므로 행 순서가 보장되지 않습니다. 페이지 간 중복이나 누락을 줄이려면 고유한 컬럼을 포함해 `orderBy`를 지정하세요. 페이지네이션에 전달하는 빌더는 사용할 트랜잭션 안에서 생성해야 합니다.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const page = await db.paginate(
|
|
299
|
+
user.select().where(user.isNotNull('email')).orderBy(user.t.id),
|
|
300
|
+
1,
|
|
301
|
+
20,
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
console.log(page.data);
|
|
305
|
+
console.log(page.paging); // current_page, per_page, last_page, total, from, to
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 트랜잭션과 원본 Drizzle API
|
|
309
|
+
|
|
310
|
+
`db.trans` 콜백 안의 쿼리 객체는 현재 트랜잭션을 자동으로 사용합니다. 중첩된 `db.trans`는 savepoint로 동작합니다. 트랜잭션 안에서 시작한 비동기 작업은 트랜잭션이 끝나기 전에 모두 `await`해야 합니다.
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
await db.trans(async () => {
|
|
314
|
+
const id = (await user.add({ name: '트랜잭션 사용자' })) as number;
|
|
315
|
+
await user.editByPrimaryKey({ name: '이름 변경' }, id);
|
|
316
|
+
|
|
317
|
+
// 같은 트랜잭션을 사용하는 원본 Drizzle API
|
|
318
|
+
await db.current().select().from(users);
|
|
319
|
+
|
|
320
|
+
await db.trans(async () => {
|
|
321
|
+
await user.removeByPrimaryKey(id);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
`db.current()`는 현재 문맥의 Drizzle 데이터베이스 인스턴스를 반환합니다. 래퍼가 제공하지 않는 Drizzle 기능은 이 API로 직접 사용할 수 있습니다.
|
|
327
|
+
|
|
328
|
+
### 테이블 수정·삭제 금지
|
|
329
|
+
|
|
330
|
+
이 패키지의 `mssqlTable`에 `{ updateBlocked: true, deleteBlocked: true }`를 전달하면 등록과 조회는 유지하면서 테이블 전체의 수정·삭제를 금지합니다. 정책은 세 번째 인자에 전달하거나, 인덱스·제약조건 설정 콜백을 사용하는 경우 네 번째 인자에 전달합니다. 각 옵션을 생략하거나 `false`로 지정하면 해당 작업은 기존처럼 허용됩니다. 별도로 선언하는 정책 객체에는 `as const` 또는 `satisfies TablePolicy`를 사용해 `true` 리터럴 타입을 유지하면 타입 검사에서도 차단됩니다.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
import { mssqlTable, int, varchar, index } from '@pdg/drizzle-mssql';
|
|
334
|
+
|
|
335
|
+
const logs = mssqlTable(
|
|
336
|
+
'logs',
|
|
337
|
+
{
|
|
338
|
+
id: int().identity().primaryKey(),
|
|
339
|
+
message: varchar({ length: 100 }).notNull(),
|
|
340
|
+
},
|
|
341
|
+
{ updateBlocked: true, deleteBlocked: true },
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const indexedLogs = mssqlTable(
|
|
345
|
+
'indexed_logs',
|
|
346
|
+
{
|
|
347
|
+
id: int().identity().primaryKey(),
|
|
348
|
+
message: varchar({ length: 100 }).notNull(),
|
|
349
|
+
},
|
|
350
|
+
(t) => [index('indexed_logs_message_idx').on(t.message)],
|
|
351
|
+
{ updateBlocked: true, deleteBlocked: true },
|
|
352
|
+
);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`updateBlocked`는 `MsSqlQuery.edit`와 `editByPrimaryKey`, `deleteBlocked`는 `remove`와 `removeByPrimaryKey` 호출을 TypeScript에서 차단합니다. 타입 정보가 사라지거나 JavaScript에서 호출하더라도 조건 콜백과 DB 접근 전에 명시적인 오류가 발생합니다. 테이블 수정 금지는 컬럼의 `updateAllowed()`보다 우선합니다. 정책은 `db.query(table)`과 직접 생성한 `MsSqlQuery` 모두에 적용되지만, 원본 Drizzle 쿼리나 직접 실행한 SQL에는 적용되지 않습니다. DB 수준의 제한이 필요하면 별도로 `UPDATE`·`DELETE` 권한을 제한해야 합니다.
|
|
356
|
+
|
|
357
|
+
### 생성·수정 시각
|
|
358
|
+
|
|
359
|
+
패키지의 `mssqlTable`로 정의한 컬럼에 `createdAt()`과 `updatedAt()`을 지정하면 `add`에서 누락된 시각을 `getTimestamp`로 채웁니다. 한 행에서 생성한 값은 누락된 시각 컬럼이 공유하며 직접 지정한 값은 유지합니다. `edit`에서는 생성 시각의 변경을 금지하고 수정 시각이 없으면 자동으로 갱신합니다.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
const users = mssqlTable('users', {
|
|
363
|
+
id: int('id').identity().primaryKey(),
|
|
364
|
+
name: nvarchar('name', { length: 100 }).notNull(),
|
|
365
|
+
created_at: datetime2('created_at').notNull().createdAt(),
|
|
366
|
+
updated_at: datetime2('updated_at').notNull().updatedAt(),
|
|
367
|
+
});
|
|
368
|
+
const db = drizzleMsSql({ url: process.env.DATABASE_URL!, schema: { users }, getTimestamp: () => new Date() });
|
|
369
|
+
const user = db.query(users);
|
|
370
|
+
const id = await user.add(user.insertValues({ name: '사용자' }));
|
|
371
|
+
await user.editByPrimaryKey(user.updateValues({ name: '수정' }), id);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
`insertBlocked()`, `insertAllowed()`, `updateBlocked()`, `updateAllowed()`, `updateRequired()`로 컬럼 정책을 지정할 수 있습니다. IDENTITY 컬럼은 기본적으로 등록과 수정이 금지되고 기본 키는 수정이 금지됩니다. 이러한 정책은 타입 검사와 런타임 검사에 반영됩니다. 기본 키 수정에는 `updateAllowed()`가 필요합니다. Drizzle의 SQL Server 입력 타입은 IDENTITY 컬럼을 제외하므로 `insertAllowed()`로도 IDENTITY 직접 등록을 지원하지 않습니다. 금지된 키는 값이 `undefined`여도 런타임에서 거부하며, 필수 수정 값이 누락되어도 오류가 발생합니다. `updatedAt().updateRequired()`는 생략 시 자동 시각으로 채웁니다.
|
|
375
|
+
|
|
376
|
+
정책은 이 패키지의 `mssqlTable`과 `MsSqlQuery`에 적용됩니다. `mssqlTableCreator`, `mssqlSchema`, Drizzle의 원본 테이블 생성 함수와 `db.current()`의 원본 쿼리에는 적용되지 않습니다. 생성 함수를 직접 전달하지 않은 `MsSqlQuery`가 자동 시각을 필요로 하면 오류가 발생합니다. 생성 함수의 반환값은 컬럼 타입과 일치해야 합니다.
|
|
377
|
+
|
|
378
|
+
### 집계·SQL 표현식
|
|
379
|
+
|
|
380
|
+
`db` 인스턴스는 `asc`, `desc`, `count`, `countDistinct`, `avg`, `avgDistinct`, `sum`, `sumDistinct`, `max`, `min`, `not`, `exists`, `notExists`, `arrayContains`, `arrayContained`, `arrayOverlaps` 등 Drizzle 함수를 제공합니다. `arrayContains`, `arrayContained`, `arrayOverlaps`는 Drizzle 함수로 노출되지만 SQL Server에서 사용할 수 있는 배열 연산을 보장하지 않습니다. `db.sqlNumber`, `db.sqlString`, `db.sqlBoolean`은 SQL 표현식 또는 기본 값을 해당 타입으로 매핑하는 표현식을 만듭니다.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
const [summary] = await db.current()
|
|
384
|
+
.select({ total: db.count() })
|
|
385
|
+
.from(users);
|
|
386
|
+
|
|
387
|
+
const numericExpression = db.sqlNumber(db.sql`1`);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### 공개 타입과 스키마 API
|
|
391
|
+
|
|
392
|
+
스키마 정의에 필요한 다음 API를 `@pdg/drizzle-mssql`에서 직접 가져올 수 있습니다.
|
|
393
|
+
|
|
394
|
+
| 구분 | 내보내기 |
|
|
395
|
+
| --- | --- |
|
|
396
|
+
| 테이블·스키마·뷰 | `mssqlTable`, `mssqlTableCreator`, `mssqlSchema`, `mssqlView` |
|
|
397
|
+
| 정수·실수 | `tinyint`, `smallint`, `int`, `bigint`, `float`, `real`, `decimal`, `numeric` |
|
|
398
|
+
| 문자열 | `char`, `nchar`, `varchar`, `nvarchar`, `text`, `ntext` |
|
|
399
|
+
| 날짜·시간 | `date`, `datetime`, `datetime2`, `datetimeoffset`, `time` |
|
|
400
|
+
| 바이너리 | `binary`, `varbinary` |
|
|
401
|
+
| 기타 컬럼 | `bit`, `customType` |
|
|
402
|
+
| 인덱스·제약조건 | `index`, `uniqueIndex`, `primaryKey`, `foreignKey`, `unique`, `check` |
|
|
403
|
+
| 타입 (`import type`) | `InferColumnsDataTypes`, `MsSqlConditions`, `MsSqlInsertValues`, `MsSqlUpdateValues`, `MsSqlAliasTable`, `MsSqlSelectedColumns`, `MsSqlSelectedTableColumns`, `MsSqlColumnSelectionName`, `MsSqlSelectedNamedColumnUnion`, `MsSqlSelectedNamedColumns`, `MsSqlCompareValues`, `MsSqlColumnName`, `MsSqlArrayCompareValues`, `MsSqlRangeCompareValues`, `MsSqlPatternCompareValues`, `MsSqlNullConditionInput` |
|
|
404
|
+
|
|
405
|
+
`check`나 SQL 표현식 기반 기본값에 사용하는 `sql`은 `drizzle-orm`에서 가져옵니다. Drizzle의 `MsSqlTable` 등 직접 필요한 타입도 `drizzle-orm/mssql-core`에서 가져올 수 있습니다.
|
|
406
|
+
|
|
407
|
+
## 라이선스
|
|
408
|
+
|
|
409
|
+
이 프로젝트는 [MIT 라이선스](https://opensource.org/licenses/MIT)에 따라 배포됩니다.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core';
|
|
2
|
+
import type { MsSqlArrayCompareValues, MsSqlCompareValues, MsSqlNullConditionInput, MsSqlPatternCompareValues, MsSqlRangeCompareValues } from './common.cjs';
|
|
3
|
+
export type MsSqlConditions<T extends MsSqlTable> = {
|
|
4
|
+
eq?: MsSqlCompareValues<T>;
|
|
5
|
+
ne?: MsSqlCompareValues<T>;
|
|
6
|
+
gt?: MsSqlCompareValues<T>;
|
|
7
|
+
gte?: MsSqlCompareValues<T>;
|
|
8
|
+
lt?: MsSqlCompareValues<T>;
|
|
9
|
+
lte?: MsSqlCompareValues<T>;
|
|
10
|
+
inArray?: MsSqlArrayCompareValues<T>;
|
|
11
|
+
notInArray?: MsSqlArrayCompareValues<T>;
|
|
12
|
+
between?: MsSqlRangeCompareValues<T>;
|
|
13
|
+
notBetween?: MsSqlRangeCompareValues<T>;
|
|
14
|
+
like?: MsSqlPatternCompareValues<T>;
|
|
15
|
+
notLike?: MsSqlPatternCompareValues<T>;
|
|
16
|
+
ilike?: MsSqlPatternCompareValues<T>;
|
|
17
|
+
notIlike?: MsSqlPatternCompareValues<T>;
|
|
18
|
+
isNull?: MsSqlNullConditionInput<T>;
|
|
19
|
+
isNotNull?: MsSqlNullConditionInput<T>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core';
|
|
2
|
+
import type { MsSqlArrayCompareValues, MsSqlCompareValues, MsSqlNullConditionInput, MsSqlPatternCompareValues, MsSqlRangeCompareValues } from './common.js';
|
|
3
|
+
export type MsSqlConditions<T extends MsSqlTable> = {
|
|
4
|
+
eq?: MsSqlCompareValues<T>;
|
|
5
|
+
ne?: MsSqlCompareValues<T>;
|
|
6
|
+
gt?: MsSqlCompareValues<T>;
|
|
7
|
+
gte?: MsSqlCompareValues<T>;
|
|
8
|
+
lt?: MsSqlCompareValues<T>;
|
|
9
|
+
lte?: MsSqlCompareValues<T>;
|
|
10
|
+
inArray?: MsSqlArrayCompareValues<T>;
|
|
11
|
+
notInArray?: MsSqlArrayCompareValues<T>;
|
|
12
|
+
between?: MsSqlRangeCompareValues<T>;
|
|
13
|
+
notBetween?: MsSqlRangeCompareValues<T>;
|
|
14
|
+
like?: MsSqlPatternCompareValues<T>;
|
|
15
|
+
notLike?: MsSqlPatternCompareValues<T>;
|
|
16
|
+
ilike?: MsSqlPatternCompareValues<T>;
|
|
17
|
+
notIlike?: MsSqlPatternCompareValues<T>;
|
|
18
|
+
isNull?: MsSqlNullConditionInput<T>;
|
|
19
|
+
isNotNull?: MsSqlNullConditionInput<T>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core/table';
|
|
2
|
+
import type { MsSqlInsertValue as InsertValue } from 'drizzle-orm/mssql-core/query-builders/insert';
|
|
3
|
+
import type { TablePolicies } from '../mssqlTable.cjs';
|
|
4
|
+
type Blocked<T extends MsSqlTable> = {
|
|
5
|
+
[K in keyof InsertValue<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
6
|
+
insert: 'blocked';
|
|
7
|
+
} ? K : TablePolicies<T>[K] extends {
|
|
8
|
+
insert: 'allowed';
|
|
9
|
+
} ? never : K extends keyof T['_']['columns'] ? (T['_']['columns'][K]['_'] extends {
|
|
10
|
+
generated: infer G;
|
|
11
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never : K extends keyof T['_']['columns'] ? (T['_']['columns'][K]['_'] extends {
|
|
12
|
+
generated: infer G;
|
|
13
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never;
|
|
14
|
+
}[keyof InsertValue<T>];
|
|
15
|
+
type TimestampKeys<T extends MsSqlTable> = {
|
|
16
|
+
[K in keyof InsertValue<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
17
|
+
timestamp: string;
|
|
18
|
+
} ? K : never : never;
|
|
19
|
+
}[keyof InsertValue<T>] & keyof InsertValue<T>;
|
|
20
|
+
export type MsSqlInsertValues<T extends MsSqlTable, B extends keyof InsertValue<T> = never> = Omit<InsertValue<T>, B | Blocked<T> | TimestampKeys<T>> & Partial<Pick<InsertValue<T>, Exclude<TimestampKeys<T>, B | Blocked<T>>>>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core/table';
|
|
2
|
+
import type { MsSqlInsertValue as InsertValue } from 'drizzle-orm/mssql-core/query-builders/insert';
|
|
3
|
+
import type { TablePolicies } from '../mssqlTable.js';
|
|
4
|
+
type Blocked<T extends MsSqlTable> = {
|
|
5
|
+
[K in keyof InsertValue<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
6
|
+
insert: 'blocked';
|
|
7
|
+
} ? K : TablePolicies<T>[K] extends {
|
|
8
|
+
insert: 'allowed';
|
|
9
|
+
} ? never : K extends keyof T['_']['columns'] ? (T['_']['columns'][K]['_'] extends {
|
|
10
|
+
generated: infer G;
|
|
11
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never : K extends keyof T['_']['columns'] ? (T['_']['columns'][K]['_'] extends {
|
|
12
|
+
generated: infer G;
|
|
13
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never;
|
|
14
|
+
}[keyof InsertValue<T>];
|
|
15
|
+
type TimestampKeys<T extends MsSqlTable> = {
|
|
16
|
+
[K in keyof InsertValue<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
17
|
+
timestamp: string;
|
|
18
|
+
} ? K : never : never;
|
|
19
|
+
}[keyof InsertValue<T>] & keyof InsertValue<T>;
|
|
20
|
+
export type MsSqlInsertValues<T extends MsSqlTable, B extends keyof InsertValue<T> = never> = Omit<InsertValue<T>, B | Blocked<T> | TimestampKeys<T>> & Partial<Pick<InsertValue<T>, Exclude<TimestampKeys<T>, B | Blocked<T>>>>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core/table';
|
|
2
|
+
import type { MsSqlUpdateSetSource } from 'drizzle-orm/mssql-core/query-builders/update';
|
|
3
|
+
import type { TablePolicies } from '../mssqlTable.cjs';
|
|
4
|
+
type DefaultBlocked<T extends MsSqlTable, K> = K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isPrimaryKey'] extends true ? K : (T['_']['columns'][K]['_'] extends {
|
|
5
|
+
generated: infer G;
|
|
6
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never;
|
|
7
|
+
type Blocked<T extends MsSqlTable> = {
|
|
8
|
+
[K in keyof MsSqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
9
|
+
timestamp: 'created';
|
|
10
|
+
} | {
|
|
11
|
+
update: 'blocked';
|
|
12
|
+
} ? K : TablePolicies<T>[K] extends {
|
|
13
|
+
update: 'allowed';
|
|
14
|
+
} ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isPrimaryKey'] extends true ? K : TablePolicies<T>[K] extends {
|
|
15
|
+
update: 'required';
|
|
16
|
+
} ? never : DefaultBlocked<T, K> : never : DefaultBlocked<T, K>;
|
|
17
|
+
}[keyof MsSqlUpdateSetSource<T>] & keyof MsSqlUpdateSetSource<T>;
|
|
18
|
+
type RequiredKeys<T extends MsSqlTable> = {
|
|
19
|
+
[K in keyof MsSqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
20
|
+
update: 'required';
|
|
21
|
+
} ? TablePolicies<T>[K] extends {
|
|
22
|
+
timestamp: 'updated';
|
|
23
|
+
} ? never : K : never : never;
|
|
24
|
+
}[keyof MsSqlUpdateSetSource<T>] & keyof MsSqlUpdateSetSource<T>;
|
|
25
|
+
export type MsSqlUpdateValues<T extends MsSqlTable, B extends keyof MsSqlUpdateSetSource<T> = never, R extends Exclude<keyof MsSqlUpdateSetSource<T>, B | Blocked<T>> = never> = Omit<MsSqlUpdateSetSource<T>, B | Blocked<T> | R | RequiredKeys<T>> & {
|
|
26
|
+
[K in Exclude<R | RequiredKeys<T>, B | Blocked<T>>]-?: Exclude<MsSqlUpdateSetSource<T>[K], undefined>;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core/table';
|
|
2
|
+
import type { MsSqlUpdateSetSource } from 'drizzle-orm/mssql-core/query-builders/update';
|
|
3
|
+
import type { TablePolicies } from '../mssqlTable.js';
|
|
4
|
+
type DefaultBlocked<T extends MsSqlTable, K> = K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isPrimaryKey'] extends true ? K : (T['_']['columns'][K]['_'] extends {
|
|
5
|
+
generated: infer G;
|
|
6
|
+
} ? undefined extends G ? false : keyof G extends never ? true : false : false) extends true ? K : never : never;
|
|
7
|
+
type Blocked<T extends MsSqlTable> = {
|
|
8
|
+
[K in keyof MsSqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
9
|
+
timestamp: 'created';
|
|
10
|
+
} | {
|
|
11
|
+
update: 'blocked';
|
|
12
|
+
} ? K : TablePolicies<T>[K] extends {
|
|
13
|
+
update: 'allowed';
|
|
14
|
+
} ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isPrimaryKey'] extends true ? K : TablePolicies<T>[K] extends {
|
|
15
|
+
update: 'required';
|
|
16
|
+
} ? never : DefaultBlocked<T, K> : never : DefaultBlocked<T, K>;
|
|
17
|
+
}[keyof MsSqlUpdateSetSource<T>] & keyof MsSqlUpdateSetSource<T>;
|
|
18
|
+
type RequiredKeys<T extends MsSqlTable> = {
|
|
19
|
+
[K in keyof MsSqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
|
|
20
|
+
update: 'required';
|
|
21
|
+
} ? TablePolicies<T>[K] extends {
|
|
22
|
+
timestamp: 'updated';
|
|
23
|
+
} ? never : K : never : never;
|
|
24
|
+
}[keyof MsSqlUpdateSetSource<T>] & keyof MsSqlUpdateSetSource<T>;
|
|
25
|
+
export type MsSqlUpdateValues<T extends MsSqlTable, B extends keyof MsSqlUpdateSetSource<T> = never, R extends Exclude<keyof MsSqlUpdateSetSource<T>, B | Blocked<T>> = never> = Omit<MsSqlUpdateSetSource<T>, B | Blocked<T> | R | RequiredKeys<T>> & {
|
|
26
|
+
[K in Exclude<R | RequiredKeys<T>, B | Blocked<T>>]-?: Exclude<MsSqlUpdateSetSource<T>[K], undefined>;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core';
|
|
2
|
+
import type { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
3
|
+
export type MsSqlCompareValues<T extends MsSqlTable> = {
|
|
4
|
+
[P in keyof InferSelectModel<T>]?: InferSelectModel<T>[P] | SQLWrapper;
|
|
5
|
+
};
|
|
6
|
+
export type MsSqlColumnName<T extends MsSqlTable> = keyof T['_']['columns'] & string;
|
|
7
|
+
export type MsSqlArrayCompareValues<T extends MsSqlTable> = {
|
|
8
|
+
[P in keyof InferSelectModel<T>]?: NonNullable<InferSelectModel<T>[P]>[];
|
|
9
|
+
};
|
|
10
|
+
export type MsSqlRangeCompareValues<T extends MsSqlTable> = {
|
|
11
|
+
[P in keyof InferSelectModel<T>]?: [NonNullable<InferSelectModel<T>[P]>, NonNullable<InferSelectModel<T>[P]>];
|
|
12
|
+
};
|
|
13
|
+
export type MsSqlPatternCompareValues<T extends MsSqlTable> = {
|
|
14
|
+
[P in keyof InferSelectModel<T> as NonNullable<InferSelectModel<T>[P]> extends string ? P : never]?: string;
|
|
15
|
+
};
|
|
16
|
+
export type MsSqlNullConditionInput<T extends MsSqlTable> = MsSqlColumnName<T> | undefined | readonly (MsSqlColumnName<T> | undefined)[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MsSqlTable } from 'drizzle-orm/mssql-core';
|
|
2
|
+
import type { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
3
|
+
export type MsSqlCompareValues<T extends MsSqlTable> = {
|
|
4
|
+
[P in keyof InferSelectModel<T>]?: InferSelectModel<T>[P] | SQLWrapper;
|
|
5
|
+
};
|
|
6
|
+
export type MsSqlColumnName<T extends MsSqlTable> = keyof T['_']['columns'] & string;
|
|
7
|
+
export type MsSqlArrayCompareValues<T extends MsSqlTable> = {
|
|
8
|
+
[P in keyof InferSelectModel<T>]?: NonNullable<InferSelectModel<T>[P]>[];
|
|
9
|
+
};
|
|
10
|
+
export type MsSqlRangeCompareValues<T extends MsSqlTable> = {
|
|
11
|
+
[P in keyof InferSelectModel<T>]?: [NonNullable<InferSelectModel<T>[P]>, NonNullable<InferSelectModel<T>[P]>];
|
|
12
|
+
};
|
|
13
|
+
export type MsSqlPatternCompareValues<T extends MsSqlTable> = {
|
|
14
|
+
[P in keyof InferSelectModel<T> as NonNullable<InferSelectModel<T>[P]> extends string ? P : never]?: string;
|
|
15
|
+
};
|
|
16
|
+
export type MsSqlNullConditionInput<T extends MsSqlTable> = MsSqlColumnName<T> | undefined | readonly (MsSqlColumnName<T> | undefined)[];
|