@pdg/drizzle-mysql 1.0.0 → 1.0.1

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 CHANGED
@@ -42,7 +42,7 @@ const db = drizzleMySql({
42
42
  const user = db.query(users);
43
43
  ```
44
44
 
45
- `drizzleMySql` 옵션은 `url`, `schema`, 선택 사항인 `timestamp`, `timestampColumns`입니다. `db.query(table)`은 해당 테이블에 맞춰 타입이 지정된 쿼리 객체를 반환합니다. 연결을 다 사용한 뒤 `await db.close()`로 커넥션 풀을 닫습니다.
45
+ `drizzleMySql` 옵션은 `url`, `schema`, 선택 사항인 `timestamp`입니다. `db.query(table)`은 해당 테이블에 맞춰 타입이 지정된 쿼리 객체를 반환합니다. 연결을 다 사용한 뒤 `await db.close()`로 커넥션 풀을 닫습니다.
46
46
 
47
47
  ### 데이터 추가·수정·삭제
48
48
 
@@ -320,23 +320,25 @@ await db.trans(async () => {
320
320
 
321
321
  ### 생성·수정 시각
322
322
 
323
- 시각 자동 입력 메서드를 사용하려면 `timestamp` 생성 함수를 설정합니다. 기본 컬럼 이름은 `created_at`과 `updated_at`이며, `timestampColumns`의 `createdAt`과 `updatedAt`으로 변경할 수 있습니다.
323
+ 컬럼 정책은 이 패키지에서 가져온 `mysqlTable`에 선언합니다. 자동 증가 컬럼은 기본적으로 등록과 수정이 금지되며, 각각 `insertAllowed()`와 `updateAllowed()`로 허용할 수 있습니다. 다른 컬럼은 `insertBlocked()`와 `updateBlocked()`로 금지하거나 `updateRequired()`로 수정 시 필수로 지정합니다. 금지된 값을 전달하거나 필수 수정 값을 누락하면 런타임에도 오류가 발생합니다.
324
324
 
325
325
  ```ts
326
- const dbWithTimestamp = drizzleMySql({
327
- url: process.env.DATABASE_URL!,
328
- schema: { users },
329
- timestamp: () => new Date(),
330
- timestampColumns: { createdAt: 'created_at', updatedAt: 'updated_at' },
331
- });
332
- const timestampedUser = dbWithTimestamp.query(users);
326
+ import { drizzleMySql, mysqlTable, int, varchar, datetime } from '@pdg/drizzle-mysql';
333
327
 
334
- await timestampedUser.addWithCreatedAt({ name: '생성 시각 입력' });
335
- await timestampedUser.addWithCreatedUpdatedAt({ name: '생성·수정 시각 입력' });
336
- await timestampedUser.editWithUpdatedAtByPrimaryKey({ name: '수정 시각 갱신' }, id);
328
+ const users = mysqlTable('users', {
329
+ id: int().autoincrement().primaryKey(),
330
+ name: varchar({ length: 50 }).notNull(),
331
+ locked: int().default(0).notNull().updateBlocked(),
332
+ created_at: datetime({ mode: 'string' }).notNull().createdAt(),
333
+ updated_at: datetime({ mode: 'string' }).notNull().updatedAt(),
334
+ });
335
+ const db = drizzleMySql({ url: process.env.DATABASE_URL!, schema: { users }, timestamp: () => new Date().toISOString() });
336
+ const usersQuery = db.query(users);
337
+ const id = await usersQuery.add({ name: '사용자' });
338
+ await usersQuery.editByPrimaryKey({ name: '수정' }, id);
337
339
  ```
338
340
 
339
- 시각 관련 메서드는 `addWithCreatedAt`, `addWithCreatedUpdatedAt`, `editWithUpdatedAt`, `editWithUpdatedAtByPrimaryKey`입니다. 직접 시각 값을 지정하는 대신 설정한 생성 함수의 값을 사용합니다.
341
+ `createdAt()`은 등록 시, `updatedAt()`은 등록과 수정 시 `timestamp` 생성 함수의 값을 자동으로 넣습니다. 지정된 시각 컬럼은 직접 입력할 수 없으며 생성 함수를 설정하지 않으면 해당 작업에서 오류가 발생합니다. 컬럼의 데이터 형식에 맞는 값을 반환해야 합니다. 정책은 `MySqlQuery`에만 적용되며 `db.current()`의 원본 Drizzle 쿼리에는 적용되지 않습니다. `mysqlTableCreator`, `mysqlSchema` 또는 Drizzle에서 직접 가져온 `mysqlTable`은 컬럼 정책을 수집하지 않으므로 정책이 필요한 테이블에는 이 패키지의 `mysqlTable`을 사용합니다.
340
342
 
341
343
  ### 집계·SQL 표현식
342
344
 
@@ -1,7 +1,16 @@
1
1
  import type { MySqlTable } from 'drizzle-orm/mysql-core/table';
2
2
  import type { MySqlInsertValue as InsertValue } from 'drizzle-orm/mysql-core/query-builders/insert';
3
- export type MySqlInsertValues<TTable extends MySqlTable, TBlocked extends keyof InsertValue<TTable> = never> = [
4
- TBlocked
5
- ] extends [never] ? InsertValue<TTable> : Omit<InsertValue<TTable>, TBlocked> & {
6
- [P in TBlocked]?: never;
3
+ import type { TablePolicies } from '../mysqlTable.cjs';
4
+ type Blocked<T extends MySqlTable> = {
5
+ [K in keyof InsertValue<T>]: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
6
+ timestamp: string;
7
+ } | {
8
+ insert: 'blocked';
9
+ } ? K : TablePolicies<T>[K] extends {
10
+ insert: 'allowed';
11
+ } ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never;
12
+ }[keyof InsertValue<T>];
13
+ export type MySqlInsertValues<T extends MySqlTable, B extends keyof InsertValue<T> = never> = Omit<InsertValue<T>, B | Blocked<T>> & {
14
+ [K in B | Blocked<T>]?: never;
7
15
  };
16
+ export {};
@@ -1,7 +1,16 @@
1
1
  import type { MySqlTable } from 'drizzle-orm/mysql-core/table';
2
2
  import type { MySqlInsertValue as InsertValue } from 'drizzle-orm/mysql-core/query-builders/insert';
3
- export type MySqlInsertValues<TTable extends MySqlTable, TBlocked extends keyof InsertValue<TTable> = never> = [
4
- TBlocked
5
- ] extends [never] ? InsertValue<TTable> : Omit<InsertValue<TTable>, TBlocked> & {
6
- [P in TBlocked]?: never;
3
+ import type { TablePolicies } from '../mysqlTable.js';
4
+ type Blocked<T extends MySqlTable> = {
5
+ [K in keyof InsertValue<T>]: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
6
+ timestamp: string;
7
+ } | {
8
+ insert: 'blocked';
9
+ } ? K : TablePolicies<T>[K] extends {
10
+ insert: 'allowed';
11
+ } ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never;
12
+ }[keyof InsertValue<T>];
13
+ export type MySqlInsertValues<T extends MySqlTable, B extends keyof InsertValue<T> = never> = Omit<InsertValue<T>, B | Blocked<T>> & {
14
+ [K in B | Blocked<T>]?: never;
7
15
  };
16
+ export {};
@@ -1,7 +1,23 @@
1
1
  import type { MySqlTable } from 'drizzle-orm/mysql-core/table';
2
2
  import type { MySqlUpdateSetSource } from 'drizzle-orm/mysql-core/query-builders/update';
3
- export type MySqlUpdateValues<TTable extends MySqlTable, TBlocked extends keyof MySqlUpdateSetSource<TTable> = never, TRequired extends Exclude<keyof MySqlUpdateSetSource<TTable>, TBlocked> = never> = Omit<MySqlUpdateSetSource<TTable>, TBlocked | TRequired> & {
4
- [P in TBlocked]?: never;
3
+ import type { TablePolicies } from '../mysqlTable.cjs';
4
+ type Blocked<T extends MySqlTable> = {
5
+ [K in keyof MySqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
6
+ timestamp: string;
7
+ } | {
8
+ update: 'blocked';
9
+ } ? K : TablePolicies<T>[K] extends {
10
+ update: 'allowed' | 'required';
11
+ } ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never;
12
+ }[keyof MySqlUpdateSetSource<T>] & keyof MySqlUpdateSetSource<T>;
13
+ type RequiredKeys<T extends MySqlTable> = {
14
+ [K in keyof MySqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
15
+ update: 'required';
16
+ } ? K : never : never;
17
+ }[keyof MySqlUpdateSetSource<T>] & keyof MySqlUpdateSetSource<T>;
18
+ export type MySqlUpdateValues<T extends MySqlTable, B extends keyof MySqlUpdateSetSource<T> = never, R extends Exclude<keyof MySqlUpdateSetSource<T>, B | Blocked<T>> = never> = Omit<MySqlUpdateSetSource<T>, B | Blocked<T> | R | RequiredKeys<T>> & {
19
+ [K in B | Blocked<T>]?: never;
5
20
  } & {
6
- [P in TRequired]-?: Exclude<MySqlUpdateSetSource<TTable>[P], undefined>;
21
+ [K in Exclude<R | RequiredKeys<T>, B | Blocked<T>>]-?: Exclude<MySqlUpdateSetSource<T>[K], undefined>;
7
22
  };
23
+ export {};
@@ -1,7 +1,23 @@
1
1
  import type { MySqlTable } from 'drizzle-orm/mysql-core/table';
2
2
  import type { MySqlUpdateSetSource } from 'drizzle-orm/mysql-core/query-builders/update';
3
- export type MySqlUpdateValues<TTable extends MySqlTable, TBlocked extends keyof MySqlUpdateSetSource<TTable> = never, TRequired extends Exclude<keyof MySqlUpdateSetSource<TTable>, TBlocked> = never> = Omit<MySqlUpdateSetSource<TTable>, TBlocked | TRequired> & {
4
- [P in TBlocked]?: never;
3
+ import type { TablePolicies } from '../mysqlTable.js';
4
+ type Blocked<T extends MySqlTable> = {
5
+ [K in keyof MySqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
6
+ timestamp: string;
7
+ } | {
8
+ update: 'blocked';
9
+ } ? K : TablePolicies<T>[K] extends {
10
+ update: 'allowed' | 'required';
11
+ } ? never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never : K extends keyof T['_']['columns'] ? T['_']['columns'][K]['_']['isAutoincrement'] extends true ? K : never : never;
12
+ }[keyof MySqlUpdateSetSource<T>] & keyof MySqlUpdateSetSource<T>;
13
+ type RequiredKeys<T extends MySqlTable> = {
14
+ [K in keyof MySqlUpdateSetSource<T>]-?: K extends keyof TablePolicies<T> ? TablePolicies<T>[K] extends {
15
+ update: 'required';
16
+ } ? K : never : never;
17
+ }[keyof MySqlUpdateSetSource<T>] & keyof MySqlUpdateSetSource<T>;
18
+ export type MySqlUpdateValues<T extends MySqlTable, B extends keyof MySqlUpdateSetSource<T> = never, R extends Exclude<keyof MySqlUpdateSetSource<T>, B | Blocked<T>> = never> = Omit<MySqlUpdateSetSource<T>, B | Blocked<T> | R | RequiredKeys<T>> & {
19
+ [K in B | Blocked<T>]?: never;
5
20
  } & {
6
- [P in TRequired]-?: Exclude<MySqlUpdateSetSource<TTable>[P], undefined>;
21
+ [K in Exclude<R | RequiredKeys<T>, B | Blocked<T>>]-?: Exclude<MySqlUpdateSetSource<T>[K], undefined>;
7
22
  };
23
+ export {};
@@ -8,18 +8,14 @@ import type { MySql2Database } from 'drizzle-orm/mysql2';
8
8
  /********************************************************************************************************************
9
9
  * MySqlQuery
10
10
  * ******************************************************************************************************************/
11
- export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInsertValues<TTable> = MySqlInsertValues<TTable>, UV extends MySqlUpdateValues<TTable> = MySqlUpdateValues<TTable>, TCreatedAt extends string = 'created_at', TUpdatedAt extends string = 'updated_at', AR = AddResult<TTable>> {
11
+ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInsertValues<TTable> = MySqlInsertValues<TTable>, UV extends MySqlUpdateValues<TTable> = MySqlUpdateValues<TTable>, AR = AddResult<TTable>> {
12
12
  private readonly current;
13
13
  private readonly getTimestamp;
14
- private readonly timestampColumns;
15
14
  readonly t: TTable;
16
15
  /********************************************************************************************************************
17
16
  * constructor
18
17
  * ******************************************************************************************************************/
19
- constructor(table: TTable, current: () => MySql2Database, getTimestamp: () => any, timestampColumns?: {
20
- createdAt?: TCreatedAt;
21
- updatedAt?: TUpdatedAt;
22
- });
18
+ constructor(table: TTable, current: () => MySql2Database, getTimestamp: () => any);
23
19
  private readonly drizzle;
24
20
  /********************************************************************************************************************
25
21
  * (PROTECTED) getTx
@@ -94,6 +90,7 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
94
90
  * count
95
91
  * ******************************************************************************************************************/
96
92
  count(where?: BaseWhere<this>): Promise<number>;
93
+ private prepareValues;
97
94
  /********************************************************************************************************************
98
95
  * (PRIVATE) insertValues
99
96
  * ******************************************************************************************************************/
@@ -103,16 +100,6 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
103
100
  * ******************************************************************************************************************/
104
101
  add(value: IV[]): Promise<AR[]>;
105
102
  add(value: IV): Promise<AR>;
106
- /********************************************************************************************************************
107
- * addWithCreatedAt
108
- * ******************************************************************************************************************/
109
- addWithCreatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>[]): Promise<AR[]>;
110
- addWithCreatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>): Promise<AR>;
111
- /********************************************************************************************************************
112
- * addWithCreatedUpdatedAt
113
- * ******************************************************************************************************************/
114
- addWithCreatedUpdatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>[]): Promise<AR[]>;
115
- addWithCreatedUpdatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>): Promise<AR>;
116
103
  /********************************************************************************************************************
117
104
  * edit
118
105
  * ******************************************************************************************************************/
@@ -121,18 +108,6 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
121
108
  * editByPrimaryKey
122
109
  * ******************************************************************************************************************/
123
110
  editByPrimaryKey(set: UV, key: PrimaryKeyInput<TTable>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
124
- /********************************************************************************************************************
125
- * editWithUpdatedAt
126
- * ******************************************************************************************************************/
127
- editWithUpdatedAt(set: Omit<UV, TUpdatedAt> & {
128
- [P in TUpdatedAt]?: never;
129
- }, where: BaseWhere<this>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
130
- /********************************************************************************************************************
131
- * editWithUpdatedAtByPrimaryKey
132
- * ******************************************************************************************************************/
133
- editWithUpdatedAtByPrimaryKey(set: Omit<UV, TUpdatedAt> & {
134
- [P in TUpdatedAt]?: never;
135
- }, key: PrimaryKeyInput<TTable>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
136
111
  /********************************************************************************************************************
137
112
  * remove
138
113
  * ******************************************************************************************************************/
@@ -257,8 +232,5 @@ type AutoIncrementKeys<TTable extends MySqlTable> = {
257
232
  } ? P : never;
258
233
  }[keyof TTable['_']['columns']];
259
234
  type HasAutoIncrement<TTable extends MySqlTable> = [AutoIncrementKeys<TTable>] extends [never] ? false : true;
260
- type TimestampInput<T, C extends string, U extends string> = Omit<T, C | U> & {
261
- [P in C | U]?: never;
262
- };
263
235
  type AddResult<TTable extends MySqlTable> = HasAutoIncrement<TTable> extends true ? number : undefined;
264
236
  export {};
@@ -8,18 +8,14 @@ import type { MySql2Database } from 'drizzle-orm/mysql2';
8
8
  /********************************************************************************************************************
9
9
  * MySqlQuery
10
10
  * ******************************************************************************************************************/
11
- export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInsertValues<TTable> = MySqlInsertValues<TTable>, UV extends MySqlUpdateValues<TTable> = MySqlUpdateValues<TTable>, TCreatedAt extends string = 'created_at', TUpdatedAt extends string = 'updated_at', AR = AddResult<TTable>> {
11
+ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInsertValues<TTable> = MySqlInsertValues<TTable>, UV extends MySqlUpdateValues<TTable> = MySqlUpdateValues<TTable>, AR = AddResult<TTable>> {
12
12
  private readonly current;
13
13
  private readonly getTimestamp;
14
- private readonly timestampColumns;
15
14
  readonly t: TTable;
16
15
  /********************************************************************************************************************
17
16
  * constructor
18
17
  * ******************************************************************************************************************/
19
- constructor(table: TTable, current: () => MySql2Database, getTimestamp: () => any, timestampColumns?: {
20
- createdAt?: TCreatedAt;
21
- updatedAt?: TUpdatedAt;
22
- });
18
+ constructor(table: TTable, current: () => MySql2Database, getTimestamp: () => any);
23
19
  private readonly drizzle;
24
20
  /********************************************************************************************************************
25
21
  * (PROTECTED) getTx
@@ -94,6 +90,7 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
94
90
  * count
95
91
  * ******************************************************************************************************************/
96
92
  count(where?: BaseWhere<this>): Promise<number>;
93
+ private prepareValues;
97
94
  /********************************************************************************************************************
98
95
  * (PRIVATE) insertValues
99
96
  * ******************************************************************************************************************/
@@ -103,16 +100,6 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
103
100
  * ******************************************************************************************************************/
104
101
  add(value: IV[]): Promise<AR[]>;
105
102
  add(value: IV): Promise<AR>;
106
- /********************************************************************************************************************
107
- * addWithCreatedAt
108
- * ******************************************************************************************************************/
109
- addWithCreatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>[]): Promise<AR[]>;
110
- addWithCreatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>): Promise<AR>;
111
- /********************************************************************************************************************
112
- * addWithCreatedUpdatedAt
113
- * ******************************************************************************************************************/
114
- addWithCreatedUpdatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>[]): Promise<AR[]>;
115
- addWithCreatedUpdatedAt(value: TimestampInput<IV, TCreatedAt, TUpdatedAt>): Promise<AR>;
116
103
  /********************************************************************************************************************
117
104
  * edit
118
105
  * ******************************************************************************************************************/
@@ -121,18 +108,6 @@ export declare class MySqlQuery<TTable extends MySqlTable, IV extends MySqlInser
121
108
  * editByPrimaryKey
122
109
  * ******************************************************************************************************************/
123
110
  editByPrimaryKey(set: UV, key: PrimaryKeyInput<TTable>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
124
- /********************************************************************************************************************
125
- * editWithUpdatedAt
126
- * ******************************************************************************************************************/
127
- editWithUpdatedAt(set: Omit<UV, TUpdatedAt> & {
128
- [P in TUpdatedAt]?: never;
129
- }, where: BaseWhere<this>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
130
- /********************************************************************************************************************
131
- * editWithUpdatedAtByPrimaryKey
132
- * ******************************************************************************************************************/
133
- editWithUpdatedAtByPrimaryKey(set: Omit<UV, TUpdatedAt> & {
134
- [P in TUpdatedAt]?: never;
135
- }, key: PrimaryKeyInput<TTable>): Omit<import("drizzle-orm/mysql-core").MySqlAsyncUpdateBase<import("drizzle-orm").Assume<import("drizzle-orm").Assume<TTable, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, MySqlTable<import("drizzle-orm/mysql-core").TableConfig>>, import("drizzle-orm/mysql2").MySql2QueryResultHKT, false, "where">, "where">;
136
111
  /********************************************************************************************************************
137
112
  * remove
138
113
  * ******************************************************************************************************************/
@@ -257,8 +232,5 @@ type AutoIncrementKeys<TTable extends MySqlTable> = {
257
232
  } ? P : never;
258
233
  }[keyof TTable['_']['columns']];
259
234
  type HasAutoIncrement<TTable extends MySqlTable> = [AutoIncrementKeys<TTable>] extends [never] ? false : true;
260
- type TimestampInput<T, C extends string, U extends string> = Omit<T, C | U> & {
261
- [P in C | U]?: never;
262
- };
263
235
  type AddResult<TTable extends MySqlTable> = HasAutoIncrement<TTable> extends true ? number : undefined;
264
236
  export {};
@@ -4,14 +4,10 @@ import type { MySqlTable } from 'drizzle-orm/mysql-core';
4
4
  import * as native from 'drizzle-orm';
5
5
  import { TableColumns } from './columns.cjs';
6
6
  import { MySqlQuery } from './MySqlQuery.cjs';
7
- export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>, TCreatedAt extends string = 'created_at', TUpdatedAt extends string = 'updated_at'>(options: {
7
+ export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>>(options: {
8
8
  url: string;
9
9
  schema: TSchema;
10
10
  timestamp?: () => unknown;
11
- timestampColumns?: {
12
- createdAt?: TCreatedAt;
13
- updatedAt?: TUpdatedAt;
14
- };
15
11
  }): {
16
12
  columns: typeof TableColumns;
17
13
  sql: typeof sql;
@@ -21,7 +17,7 @@ export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>,
21
17
  current: () => (import("drizzle-orm/mysql2").MySql2Database<native.ExtractTablesWithRelations<{}, native.ExtractTablesFromSchema<TSchema>>> & {
22
18
  $client: mysql.Pool;
23
19
  }) | import("drizzle-orm/mysql-core").MySqlAsyncTransaction<import("drizzle-orm/mysql2").MySql2QueryResultHKT, native.ExtractTablesWithRelations<{}, native.ExtractTablesFromSchema<TSchema>>>;
24
- query: <TTable extends TSchema[keyof TSchema]>(table: TTable) => MySqlQuery<TTable, ({ [Key in keyof TTable["_"]["columns"] & string as native.RequiredKeyOnly<Key, TTable["_"]["columns"][Key]>]: TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null; } & { [Key_1 in keyof TTable["_"]["columns"] & string as native.OptionalKeyOnly<Key_1, TTable["_"]["columns"][Key_1], false>]?: (TTable["_"]["columns"][Key_1]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key_1]["_"]["data"] : TTable["_"]["columns"][Key_1]["_"]["data"] | null) | undefined; } extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T extends Record<string, any> ? { [K in keyof T as K]: SQL<unknown> | native.Placeholder<string, any> | T[K]; } : never, import("./@types.cjs").MySqlUpdateValues<TTable>, TCreatedAt, TUpdatedAt, ([{ [P in keyof TTable["_"]["columns"]]: TTable["_"]["columns"][P]["_"] extends {
20
+ query: <TTable extends TSchema[keyof TSchema]>(table: TTable) => MySqlQuery<TTable, import("./@types.cjs").MySqlInsertValues<TTable>, import("./@types.cjs").MySqlUpdateValues<TTable>, ([{ [P in keyof TTable["_"]["columns"]]: TTable["_"]["columns"][P]["_"] extends {
25
21
  isAutoincrement: true;
26
22
  } ? P : never; }[keyof TTable["_"]["columns"]]] extends [never] ? false : true) extends true ? number : undefined>;
27
23
  trans: <T>(callback: () => Promise<T>) => Promise<T>;
@@ -4,14 +4,10 @@ import type { MySqlTable } from 'drizzle-orm/mysql-core';
4
4
  import * as native from 'drizzle-orm';
5
5
  import { TableColumns } from './columns.js';
6
6
  import { MySqlQuery } from './MySqlQuery.js';
7
- export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>, TCreatedAt extends string = 'created_at', TUpdatedAt extends string = 'updated_at'>(options: {
7
+ export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>>(options: {
8
8
  url: string;
9
9
  schema: TSchema;
10
10
  timestamp?: () => unknown;
11
- timestampColumns?: {
12
- createdAt?: TCreatedAt;
13
- updatedAt?: TUpdatedAt;
14
- };
15
11
  }): {
16
12
  columns: typeof TableColumns;
17
13
  sql: typeof sql;
@@ -21,7 +17,7 @@ export declare function drizzleMySql<TSchema extends Record<string, MySqlTable>,
21
17
  current: () => (import("drizzle-orm/mysql2").MySql2Database<native.ExtractTablesWithRelations<{}, native.ExtractTablesFromSchema<TSchema>>> & {
22
18
  $client: mysql.Pool;
23
19
  }) | import("drizzle-orm/mysql-core").MySqlAsyncTransaction<import("drizzle-orm/mysql2").MySql2QueryResultHKT, native.ExtractTablesWithRelations<{}, native.ExtractTablesFromSchema<TSchema>>>;
24
- query: <TTable extends TSchema[keyof TSchema]>(table: TTable) => MySqlQuery<TTable, ({ [Key in keyof TTable["_"]["columns"] & string as native.RequiredKeyOnly<Key, TTable["_"]["columns"][Key]>]: TTable["_"]["columns"][Key]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key]["_"]["data"] : TTable["_"]["columns"][Key]["_"]["data"] | null; } & { [Key_1 in keyof TTable["_"]["columns"] & string as native.OptionalKeyOnly<Key_1, TTable["_"]["columns"][Key_1], false>]?: (TTable["_"]["columns"][Key_1]["_"]["notNull"] extends true ? TTable["_"]["columns"][Key_1]["_"]["data"] : TTable["_"]["columns"][Key_1]["_"]["data"] | null) | undefined; } extends infer T_1 ? { [K_1 in keyof T_1]: T_1[K_1]; } : never) extends infer T extends Record<string, any> ? { [K in keyof T as K]: SQL<unknown> | native.Placeholder<string, any> | T[K]; } : never, import("./@types.js").MySqlUpdateValues<TTable>, TCreatedAt, TUpdatedAt, ([{ [P in keyof TTable["_"]["columns"]]: TTable["_"]["columns"][P]["_"] extends {
20
+ query: <TTable extends TSchema[keyof TSchema]>(table: TTable) => MySqlQuery<TTable, import("./@types.js").MySqlInsertValues<TTable>, import("./@types.js").MySqlUpdateValues<TTable>, ([{ [P in keyof TTable["_"]["columns"]]: TTable["_"]["columns"][P]["_"] extends {
25
21
  isAutoincrement: true;
26
22
  } ? P : never; }[keyof TTable["_"]["columns"]]] extends [never] ? false : true) extends true ? number : undefined>;
27
23
  trans: <T>(callback: () => Promise<T>) => Promise<T>;
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var mysql=require('mysql2/promise'),mysql2=require('drizzle-orm/mysql2'),native=require('drizzle-orm'),node_async_hooks=require('node:async_hooks'),alias=require('drizzle-orm/mysql-core/alias'),mysqlCore=require('drizzle-orm/mysql-core');function _interopNamespaceDefault(e){var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var native__namespace=/*#__PURE__*/_interopNamespaceDefault(native);function createAlias(schema) {
1
+ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var mysql=require('mysql2/promise'),mysql2=require('drizzle-orm/mysql2'),native=require('drizzle-orm'),node_async_hooks=require('node:async_hooks'),alias=require('drizzle-orm/mysql-core/alias'),mysqlCore=require('drizzle-orm/mysql-core'),columnBuilder=require('drizzle-orm/column-builder');function _interopNamespaceDefault(e){var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var native__namespace=/*#__PURE__*/_interopNamespaceDefault(native);function createAlias(schema) {
2
2
  /********************************************************************************************************************
3
3
  * getDefaultAlias
4
4
  * ******************************************************************************************************************/
@@ -192,22 +192,49 @@
192
192
  throw new Error('columns: expected a column object.');
193
193
  return [column.name, column];
194
194
  }));
195
+ }const policies = new WeakMap();
196
+ for (const [method, policy] of Object.entries({
197
+ insertBlocked: { insert: 'blocked' },
198
+ insertAllowed: { insert: 'allowed' },
199
+ updateBlocked: { update: 'blocked' },
200
+ updateAllowed: { update: 'allowed' },
201
+ updateRequired: { update: 'required' },
202
+ createdAt: { timestamp: 'created' },
203
+ updatedAt: { timestamp: 'updated' },
204
+ })) {
205
+ Object.defineProperty(columnBuilder.ColumnBuilder.prototype, method, {
206
+ configurable: true,
207
+ value: function () {
208
+ policies.set(this, { ...policies.get(this), ...policy });
209
+ return this;
210
+ },
211
+ });
212
+ }
213
+ const tablePolicies = new WeakMap();
214
+ function getColumnPolicies(table) {
215
+ return tablePolicies.get(table) ?? {};
216
+ }
217
+ function mysqlTable(name, columns, extraConfig) {
218
+ let builders = {};
219
+ const table = typeof columns === 'function'
220
+ ? mysqlCore.mysqlTable(name, (types) => (builders = columns(types)), extraConfig)
221
+ : mysqlCore.mysqlTable(name, (builders = columns), extraConfig);
222
+ tablePolicies.set(table, Object.fromEntries(Object.entries(builders).map(([key, builder]) => [key, policies.get(builder) ?? {}])));
223
+ return table;
195
224
  }/********************************************************************************************************************
196
225
  * MySqlQuery
197
226
  * ******************************************************************************************************************/
198
227
  class MySqlQuery {
199
228
  current;
200
229
  getTimestamp;
201
- timestampColumns;
202
230
  // Table
203
231
  t;
204
232
  /********************************************************************************************************************
205
233
  * constructor
206
234
  * ******************************************************************************************************************/
207
- constructor(table, current, getTimestamp, timestampColumns = {}) {
235
+ constructor(table, current, getTimestamp) {
208
236
  this.current = current;
209
237
  this.getTimestamp = getTimestamp;
210
- this.timestampColumns = timestampColumns;
211
238
  this.t = table;
212
239
  }
213
240
  drizzle = { ...createConditions({}), sqlNumber: (value) => native.sql `${value}`.mapWith(Number) };
@@ -368,6 +395,32 @@ class MySqlQuery {
368
395
  const [{ cnt }] = await this.select({ cnt: native.count() }).where(condition);
369
396
  return cnt;
370
397
  }
398
+ prepareValues(input, operation) {
399
+ const values = { ...input };
400
+ const columns = native.getTableColumns(this.t);
401
+ const policies = getColumnPolicies(this.t);
402
+ let timestamp;
403
+ let generated = false;
404
+ for (const [key, column] of Object.entries(columns)) {
405
+ const policy = policies[key] ?? {};
406
+ const auto = 'autoIncrement' in column && column.autoIncrement === true;
407
+ const rule = operation === 'insert' ? policy.insert : policy.update;
408
+ const blocked = !!policy.timestamp || rule === 'blocked' || (auto && rule !== 'allowed' && rule !== 'required');
409
+ if (blocked && Object.hasOwn(values, key))
410
+ throw new Error(`${operation}: column "${key}" is blocked.`);
411
+ if (operation === 'update' && rule === 'required' && values[key] === undefined) {
412
+ throw new Error(`update: column "${key}" is required.`);
413
+ }
414
+ if (policy.timestamp && (operation === 'insert' || policy.timestamp === 'updated')) {
415
+ if (!generated) {
416
+ timestamp = this.getTimestamp();
417
+ generated = true;
418
+ }
419
+ values[key] = timestamp;
420
+ }
421
+ }
422
+ return values;
423
+ }
371
424
  /********************************************************************************************************************
372
425
  * (PRIVATE) insertValues
373
426
  * ******************************************************************************************************************/
@@ -399,26 +452,9 @@ class MySqlQuery {
399
452
  }
400
453
  }
401
454
  add(value) {
402
- return this.insertValues(value);
403
- }
404
- addWithCreatedAt(value) {
405
- const created_at = this.getTimestamp();
406
455
  const items = Array.isArray(value) ? value : [value];
407
- const values = items.map((item) => ({
408
- ...item,
409
- [this.timestampColumns.createdAt ?? 'created_at']: created_at,
410
- }));
411
- return this.insertValues(Array.isArray(value) ? values : values[0]);
412
- }
413
- addWithCreatedUpdatedAt(value) {
414
- const dateTime = this.getTimestamp();
415
- const items = Array.isArray(value) ? value : [value];
416
- const values = items.map((item) => ({
417
- ...item,
418
- [this.timestampColumns.createdAt ?? 'created_at']: dateTime,
419
- [this.timestampColumns.updatedAt ?? 'updated_at']: dateTime,
420
- }));
421
- return this.insertValues(Array.isArray(value) ? values : values[0]);
456
+ const values = items.map((item) => this.prepareValues(item, 'insert'));
457
+ return this.insertValues((Array.isArray(value) ? values : values[0]));
422
458
  }
423
459
  /********************************************************************************************************************
424
460
  * edit
@@ -429,7 +465,10 @@ class MySqlQuery {
429
465
  throw new Error('edit: a SQL where condition is required.');
430
466
  }
431
467
  const tx = this.getTx();
432
- return tx.update(this.t).set(set).where(condition);
468
+ return tx
469
+ .update(this.t)
470
+ .set(this.prepareValues(set, 'update'))
471
+ .where(condition);
433
472
  }
434
473
  /********************************************************************************************************************
435
474
  * editByPrimaryKey
@@ -437,27 +476,6 @@ class MySqlQuery {
437
476
  editByPrimaryKey(set, key) {
438
477
  return this.edit(set, this.primaryKeyCondition(key, 'editByPrimaryKey'));
439
478
  }
440
- /********************************************************************************************************************
441
- * editWithUpdatedAt
442
- * ******************************************************************************************************************/
443
- editWithUpdatedAt(set, where) {
444
- const condition = typeof where === 'function' ? where(this) : where;
445
- if (!native.is(condition, native.SQL)) {
446
- throw new Error('editWithUpdatedAt: a SQL where condition is required.');
447
- }
448
- const tx = this.getTx();
449
- const values = {
450
- ...set,
451
- [this.timestampColumns.updatedAt ?? 'updated_at']: this.getTimestamp(),
452
- };
453
- return tx.update(this.t).set(values).where(condition);
454
- }
455
- /********************************************************************************************************************
456
- * editWithUpdatedAtByPrimaryKey
457
- * ******************************************************************************************************************/
458
- editWithUpdatedAtByPrimaryKey(set, key) {
459
- return this.editWithUpdatedAt(set, this.primaryKeyCondition(key, 'editWithUpdatedAtByPrimaryKey'));
460
- }
461
479
  /********************************************************************************************************************
462
480
  * remove
463
481
  * ******************************************************************************************************************/
@@ -658,9 +676,9 @@ const normalizeFields = (fields) => {
658
676
  if (!options.timestamp)
659
677
  throw new Error('timestamp generator is not configured');
660
678
  return options.timestamp();
661
- }, options.timestampColumns),
679
+ }),
662
680
  trans,
663
681
  paginate,
664
682
  close: () => pool.end(),
665
683
  };
666
- }Object.defineProperty(exports,"asc",{enumerable:true,get:function(){return native.asc}});Object.defineProperty(exports,"avg",{enumerable:true,get:function(){return native.avg}});Object.defineProperty(exports,"avgDistinct",{enumerable:true,get:function(){return native.avgDistinct}});Object.defineProperty(exports,"count",{enumerable:true,get:function(){return native.count}});Object.defineProperty(exports,"countDistinct",{enumerable:true,get:function(){return native.countDistinct}});Object.defineProperty(exports,"desc",{enumerable:true,get:function(){return native.desc}});Object.defineProperty(exports,"exists",{enumerable:true,get:function(){return native.exists}});Object.defineProperty(exports,"max",{enumerable:true,get:function(){return native.max}});Object.defineProperty(exports,"min",{enumerable:true,get:function(){return native.min}});Object.defineProperty(exports,"not",{enumerable:true,get:function(){return native.not}});Object.defineProperty(exports,"notExists",{enumerable:true,get:function(){return native.notExists}});Object.defineProperty(exports,"sum",{enumerable:true,get:function(){return native.sum}});Object.defineProperty(exports,"sumDistinct",{enumerable:true,get:function(){return native.sumDistinct}});Object.defineProperty(exports,"bigint",{enumerable:true,get:function(){return mysqlCore.bigint}});Object.defineProperty(exports,"binary",{enumerable:true,get:function(){return mysqlCore.binary}});Object.defineProperty(exports,"blob",{enumerable:true,get:function(){return mysqlCore.blob}});Object.defineProperty(exports,"boolean",{enumerable:true,get:function(){return mysqlCore.boolean}});Object.defineProperty(exports,"char",{enumerable:true,get:function(){return mysqlCore.char}});Object.defineProperty(exports,"check",{enumerable:true,get:function(){return mysqlCore.check}});Object.defineProperty(exports,"customType",{enumerable:true,get:function(){return mysqlCore.customType}});Object.defineProperty(exports,"date",{enumerable:true,get:function(){return mysqlCore.date}});Object.defineProperty(exports,"datetime",{enumerable:true,get:function(){return mysqlCore.datetime}});Object.defineProperty(exports,"decimal",{enumerable:true,get:function(){return mysqlCore.decimal}});Object.defineProperty(exports,"double",{enumerable:true,get:function(){return mysqlCore.double}});Object.defineProperty(exports,"float",{enumerable:true,get:function(){return mysqlCore.float}});Object.defineProperty(exports,"foreignKey",{enumerable:true,get:function(){return mysqlCore.foreignKey}});Object.defineProperty(exports,"index",{enumerable:true,get:function(){return mysqlCore.index}});Object.defineProperty(exports,"int",{enumerable:true,get:function(){return mysqlCore.int}});Object.defineProperty(exports,"json",{enumerable:true,get:function(){return mysqlCore.json}});Object.defineProperty(exports,"longblob",{enumerable:true,get:function(){return mysqlCore.longblob}});Object.defineProperty(exports,"longtext",{enumerable:true,get:function(){return mysqlCore.longtext}});Object.defineProperty(exports,"mediumblob",{enumerable:true,get:function(){return mysqlCore.mediumblob}});Object.defineProperty(exports,"mediumint",{enumerable:true,get:function(){return mysqlCore.mediumint}});Object.defineProperty(exports,"mediumtext",{enumerable:true,get:function(){return mysqlCore.mediumtext}});Object.defineProperty(exports,"mysqlDatabase",{enumerable:true,get:function(){return mysqlCore.mysqlDatabase}});Object.defineProperty(exports,"mysqlEnum",{enumerable:true,get:function(){return mysqlCore.mysqlEnum}});Object.defineProperty(exports,"mysqlSchema",{enumerable:true,get:function(){return mysqlCore.mysqlSchema}});Object.defineProperty(exports,"mysqlTable",{enumerable:true,get:function(){return mysqlCore.mysqlTable}});Object.defineProperty(exports,"mysqlTableCreator",{enumerable:true,get:function(){return mysqlCore.mysqlTableCreator}});Object.defineProperty(exports,"mysqlView",{enumerable:true,get:function(){return mysqlCore.mysqlView}});Object.defineProperty(exports,"primaryKey",{enumerable:true,get:function(){return mysqlCore.primaryKey}});Object.defineProperty(exports,"real",{enumerable:true,get:function(){return mysqlCore.real}});Object.defineProperty(exports,"serial",{enumerable:true,get:function(){return mysqlCore.serial}});Object.defineProperty(exports,"smallint",{enumerable:true,get:function(){return mysqlCore.smallint}});Object.defineProperty(exports,"text",{enumerable:true,get:function(){return mysqlCore.text}});Object.defineProperty(exports,"time",{enumerable:true,get:function(){return mysqlCore.time}});Object.defineProperty(exports,"timestamp",{enumerable:true,get:function(){return mysqlCore.timestamp}});Object.defineProperty(exports,"tinyblob",{enumerable:true,get:function(){return mysqlCore.tinyblob}});Object.defineProperty(exports,"tinyint",{enumerable:true,get:function(){return mysqlCore.tinyint}});Object.defineProperty(exports,"tinytext",{enumerable:true,get:function(){return mysqlCore.tinytext}});Object.defineProperty(exports,"unique",{enumerable:true,get:function(){return mysqlCore.unique}});Object.defineProperty(exports,"uniqueIndex",{enumerable:true,get:function(){return mysqlCore.uniqueIndex}});Object.defineProperty(exports,"varbinary",{enumerable:true,get:function(){return mysqlCore.varbinary}});Object.defineProperty(exports,"varchar",{enumerable:true,get:function(){return mysqlCore.varchar}});Object.defineProperty(exports,"year",{enumerable:true,get:function(){return mysqlCore.year}});exports.MySqlQuery=MySqlQuery;exports.TableColumns=TableColumns;exports.createConditions=createConditions;exports.default=drizzleMySql;exports.drizzleMySql=drizzleMySql;
684
+ }Object.defineProperty(exports,"asc",{enumerable:true,get:function(){return native.asc}});Object.defineProperty(exports,"avg",{enumerable:true,get:function(){return native.avg}});Object.defineProperty(exports,"avgDistinct",{enumerable:true,get:function(){return native.avgDistinct}});Object.defineProperty(exports,"count",{enumerable:true,get:function(){return native.count}});Object.defineProperty(exports,"countDistinct",{enumerable:true,get:function(){return native.countDistinct}});Object.defineProperty(exports,"desc",{enumerable:true,get:function(){return native.desc}});Object.defineProperty(exports,"exists",{enumerable:true,get:function(){return native.exists}});Object.defineProperty(exports,"max",{enumerable:true,get:function(){return native.max}});Object.defineProperty(exports,"min",{enumerable:true,get:function(){return native.min}});Object.defineProperty(exports,"not",{enumerable:true,get:function(){return native.not}});Object.defineProperty(exports,"notExists",{enumerable:true,get:function(){return native.notExists}});Object.defineProperty(exports,"sum",{enumerable:true,get:function(){return native.sum}});Object.defineProperty(exports,"sumDistinct",{enumerable:true,get:function(){return native.sumDistinct}});Object.defineProperty(exports,"bigint",{enumerable:true,get:function(){return mysqlCore.bigint}});Object.defineProperty(exports,"binary",{enumerable:true,get:function(){return mysqlCore.binary}});Object.defineProperty(exports,"blob",{enumerable:true,get:function(){return mysqlCore.blob}});Object.defineProperty(exports,"boolean",{enumerable:true,get:function(){return mysqlCore.boolean}});Object.defineProperty(exports,"char",{enumerable:true,get:function(){return mysqlCore.char}});Object.defineProperty(exports,"check",{enumerable:true,get:function(){return mysqlCore.check}});Object.defineProperty(exports,"customType",{enumerable:true,get:function(){return mysqlCore.customType}});Object.defineProperty(exports,"date",{enumerable:true,get:function(){return mysqlCore.date}});Object.defineProperty(exports,"datetime",{enumerable:true,get:function(){return mysqlCore.datetime}});Object.defineProperty(exports,"decimal",{enumerable:true,get:function(){return mysqlCore.decimal}});Object.defineProperty(exports,"double",{enumerable:true,get:function(){return mysqlCore.double}});Object.defineProperty(exports,"float",{enumerable:true,get:function(){return mysqlCore.float}});Object.defineProperty(exports,"foreignKey",{enumerable:true,get:function(){return mysqlCore.foreignKey}});Object.defineProperty(exports,"index",{enumerable:true,get:function(){return mysqlCore.index}});Object.defineProperty(exports,"int",{enumerable:true,get:function(){return mysqlCore.int}});Object.defineProperty(exports,"json",{enumerable:true,get:function(){return mysqlCore.json}});Object.defineProperty(exports,"longblob",{enumerable:true,get:function(){return mysqlCore.longblob}});Object.defineProperty(exports,"longtext",{enumerable:true,get:function(){return mysqlCore.longtext}});Object.defineProperty(exports,"mediumblob",{enumerable:true,get:function(){return mysqlCore.mediumblob}});Object.defineProperty(exports,"mediumint",{enumerable:true,get:function(){return mysqlCore.mediumint}});Object.defineProperty(exports,"mediumtext",{enumerable:true,get:function(){return mysqlCore.mediumtext}});Object.defineProperty(exports,"mysqlDatabase",{enumerable:true,get:function(){return mysqlCore.mysqlDatabase}});Object.defineProperty(exports,"mysqlEnum",{enumerable:true,get:function(){return mysqlCore.mysqlEnum}});Object.defineProperty(exports,"mysqlSchema",{enumerable:true,get:function(){return mysqlCore.mysqlSchema}});Object.defineProperty(exports,"mysqlTableCreator",{enumerable:true,get:function(){return mysqlCore.mysqlTableCreator}});Object.defineProperty(exports,"mysqlView",{enumerable:true,get:function(){return mysqlCore.mysqlView}});Object.defineProperty(exports,"primaryKey",{enumerable:true,get:function(){return mysqlCore.primaryKey}});Object.defineProperty(exports,"real",{enumerable:true,get:function(){return mysqlCore.real}});Object.defineProperty(exports,"serial",{enumerable:true,get:function(){return mysqlCore.serial}});Object.defineProperty(exports,"smallint",{enumerable:true,get:function(){return mysqlCore.smallint}});Object.defineProperty(exports,"text",{enumerable:true,get:function(){return mysqlCore.text}});Object.defineProperty(exports,"time",{enumerable:true,get:function(){return mysqlCore.time}});Object.defineProperty(exports,"timestamp",{enumerable:true,get:function(){return mysqlCore.timestamp}});Object.defineProperty(exports,"tinyblob",{enumerable:true,get:function(){return mysqlCore.tinyblob}});Object.defineProperty(exports,"tinyint",{enumerable:true,get:function(){return mysqlCore.tinyint}});Object.defineProperty(exports,"tinytext",{enumerable:true,get:function(){return mysqlCore.tinytext}});Object.defineProperty(exports,"unique",{enumerable:true,get:function(){return mysqlCore.unique}});Object.defineProperty(exports,"uniqueIndex",{enumerable:true,get:function(){return mysqlCore.uniqueIndex}});Object.defineProperty(exports,"varbinary",{enumerable:true,get:function(){return mysqlCore.varbinary}});Object.defineProperty(exports,"varchar",{enumerable:true,get:function(){return mysqlCore.varchar}});Object.defineProperty(exports,"year",{enumerable:true,get:function(){return mysqlCore.year}});exports.MySqlQuery=MySqlQuery;exports.TableColumns=TableColumns;exports.createConditions=createConditions;exports.default=drizzleMySql;exports.drizzleMySql=drizzleMySql;exports.mysqlTable=mysqlTable;
package/dist/index.d.cts CHANGED
@@ -2,8 +2,9 @@ import { drizzleMySql } from './drizzleMySql.cjs';
2
2
  export default drizzleMySql;
3
3
  export * from './@types/index.cjs';
4
4
  export * from './columns.cjs';
5
+ export { mysqlTable } from './mysqlTable.cjs';
5
6
  export * from './conditions.cjs';
6
7
  export * from './drizzleMySql.cjs';
7
8
  export * from './MySqlQuery.cjs';
8
9
  export { asc, desc, count, countDistinct, avg, avgDistinct, sum, sumDistinct, max, min, not, exists, notExists, type InferColumnsDataTypes, } from 'drizzle-orm';
9
- export { mysqlTable, mysqlTableCreator, mysqlSchema, mysqlDatabase, mysqlView, bigint, binary, blob, boolean, char, customType, date, datetime, decimal, double, float, int, json, longblob, longtext, mediumblob, mediumint, mediumtext, mysqlEnum, real, serial, smallint, text, time, timestamp, tinyblob, tinyint, tinytext, varbinary, varchar, year, check, foreignKey, index, primaryKey, unique, uniqueIndex, } from 'drizzle-orm/mysql-core';
10
+ export { mysqlTableCreator, mysqlSchema, mysqlDatabase, mysqlView, bigint, binary, blob, boolean, char, customType, date, datetime, decimal, double, float, int, json, longblob, longtext, mediumblob, mediumint, mediumtext, mysqlEnum, real, serial, smallint, text, time, timestamp, tinyblob, tinyint, tinytext, varbinary, varchar, year, check, foreignKey, index, primaryKey, unique, uniqueIndex, } from 'drizzle-orm/mysql-core';
package/dist/index.d.ts CHANGED
@@ -2,8 +2,9 @@ import { drizzleMySql } from './drizzleMySql.js';
2
2
  export default drizzleMySql;
3
3
  export * from './@types/index.js';
4
4
  export * from './columns.js';
5
+ export { mysqlTable } from './mysqlTable.js';
5
6
  export * from './conditions.js';
6
7
  export * from './drizzleMySql.js';
7
8
  export * from './MySqlQuery.js';
8
9
  export { asc, desc, count, countDistinct, avg, avgDistinct, sum, sumDistinct, max, min, not, exists, notExists, type InferColumnsDataTypes, } from 'drizzle-orm';
9
- export { mysqlTable, mysqlTableCreator, mysqlSchema, mysqlDatabase, mysqlView, bigint, binary, blob, boolean, char, customType, date, datetime, decimal, double, float, int, json, longblob, longtext, mediumblob, mediumint, mediumtext, mysqlEnum, real, serial, smallint, text, time, timestamp, tinyblob, tinyint, tinytext, varbinary, varchar, year, check, foreignKey, index, primaryKey, unique, uniqueIndex, } from 'drizzle-orm/mysql-core';
10
+ export { mysqlTableCreator, mysqlSchema, mysqlDatabase, mysqlView, bigint, binary, blob, boolean, char, customType, date, datetime, decimal, double, float, int, json, longblob, longtext, mediumblob, mediumint, mediumtext, mysqlEnum, real, serial, smallint, text, time, timestamp, tinyblob, tinyint, tinytext, varbinary, varchar, year, check, foreignKey, index, primaryKey, unique, uniqueIndex, } from 'drizzle-orm/mysql-core';
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import mysql from'mysql2/promise';import {drizzle}from'drizzle-orm/mysql2';import*as native from'drizzle-orm';import {isTable,getTableColumns,sql,is,SQL,eq,and,count,defineRelations}from'drizzle-orm';export{asc,avg,avgDistinct,count,countDistinct,desc,exists,max,min,not,notExists,sum,sumDistinct}from'drizzle-orm';import {AsyncLocalStorage}from'node:async_hooks';import {alias}from'drizzle-orm/mysql-core/alias';import {MySqlTable,getTableConfig,MySqlColumn}from'drizzle-orm/mysql-core';export{bigint,binary,blob,boolean,char,check,customType,date,datetime,decimal,double,float,foreignKey,index,int,json,longblob,longtext,mediumblob,mediumint,mediumtext,mysqlDatabase,mysqlEnum,mysqlSchema,mysqlTable,mysqlTableCreator,mysqlView,primaryKey,real,serial,smallint,text,time,timestamp,tinyblob,tinyint,tinytext,unique,uniqueIndex,varbinary,varchar,year}from'drizzle-orm/mysql-core';function createAlias(schema) {
1
+ import mysql from'mysql2/promise';import {drizzle}from'drizzle-orm/mysql2';import*as native from'drizzle-orm';import {isTable,getTableColumns,sql,is,SQL,eq,and,count,defineRelations}from'drizzle-orm';export{asc,avg,avgDistinct,count,countDistinct,desc,exists,max,min,not,notExists,sum,sumDistinct}from'drizzle-orm';import {AsyncLocalStorage}from'node:async_hooks';import {alias}from'drizzle-orm/mysql-core/alias';import {MySqlTable,mysqlTable as mysqlTable$1,getTableConfig,MySqlColumn}from'drizzle-orm/mysql-core';export{bigint,binary,blob,boolean,char,check,customType,date,datetime,decimal,double,float,foreignKey,index,int,json,longblob,longtext,mediumblob,mediumint,mediumtext,mysqlDatabase,mysqlEnum,mysqlSchema,mysqlTableCreator,mysqlView,primaryKey,real,serial,smallint,text,time,timestamp,tinyblob,tinyint,tinytext,unique,uniqueIndex,varbinary,varchar,year}from'drizzle-orm/mysql-core';import {ColumnBuilder}from'drizzle-orm/column-builder';function createAlias(schema) {
2
2
  /********************************************************************************************************************
3
3
  * getDefaultAlias
4
4
  * ******************************************************************************************************************/
@@ -192,22 +192,49 @@ import mysql from'mysql2/promise';import {drizzle}from'drizzle-orm/mysql2';impor
192
192
  throw new Error('columns: expected a column object.');
193
193
  return [column.name, column];
194
194
  }));
195
+ }const policies = new WeakMap();
196
+ for (const [method, policy] of Object.entries({
197
+ insertBlocked: { insert: 'blocked' },
198
+ insertAllowed: { insert: 'allowed' },
199
+ updateBlocked: { update: 'blocked' },
200
+ updateAllowed: { update: 'allowed' },
201
+ updateRequired: { update: 'required' },
202
+ createdAt: { timestamp: 'created' },
203
+ updatedAt: { timestamp: 'updated' },
204
+ })) {
205
+ Object.defineProperty(ColumnBuilder.prototype, method, {
206
+ configurable: true,
207
+ value: function () {
208
+ policies.set(this, { ...policies.get(this), ...policy });
209
+ return this;
210
+ },
211
+ });
212
+ }
213
+ const tablePolicies = new WeakMap();
214
+ function getColumnPolicies(table) {
215
+ return tablePolicies.get(table) ?? {};
216
+ }
217
+ function mysqlTable(name, columns, extraConfig) {
218
+ let builders = {};
219
+ const table = typeof columns === 'function'
220
+ ? mysqlTable$1(name, (types) => (builders = columns(types)), extraConfig)
221
+ : mysqlTable$1(name, (builders = columns), extraConfig);
222
+ tablePolicies.set(table, Object.fromEntries(Object.entries(builders).map(([key, builder]) => [key, policies.get(builder) ?? {}])));
223
+ return table;
195
224
  }/********************************************************************************************************************
196
225
  * MySqlQuery
197
226
  * ******************************************************************************************************************/
198
227
  class MySqlQuery {
199
228
  current;
200
229
  getTimestamp;
201
- timestampColumns;
202
230
  // Table
203
231
  t;
204
232
  /********************************************************************************************************************
205
233
  * constructor
206
234
  * ******************************************************************************************************************/
207
- constructor(table, current, getTimestamp, timestampColumns = {}) {
235
+ constructor(table, current, getTimestamp) {
208
236
  this.current = current;
209
237
  this.getTimestamp = getTimestamp;
210
- this.timestampColumns = timestampColumns;
211
238
  this.t = table;
212
239
  }
213
240
  drizzle = { ...createConditions({}), sqlNumber: (value) => sql `${value}`.mapWith(Number) };
@@ -368,6 +395,32 @@ class MySqlQuery {
368
395
  const [{ cnt }] = await this.select({ cnt: count() }).where(condition);
369
396
  return cnt;
370
397
  }
398
+ prepareValues(input, operation) {
399
+ const values = { ...input };
400
+ const columns = getTableColumns(this.t);
401
+ const policies = getColumnPolicies(this.t);
402
+ let timestamp;
403
+ let generated = false;
404
+ for (const [key, column] of Object.entries(columns)) {
405
+ const policy = policies[key] ?? {};
406
+ const auto = 'autoIncrement' in column && column.autoIncrement === true;
407
+ const rule = operation === 'insert' ? policy.insert : policy.update;
408
+ const blocked = !!policy.timestamp || rule === 'blocked' || (auto && rule !== 'allowed' && rule !== 'required');
409
+ if (blocked && Object.hasOwn(values, key))
410
+ throw new Error(`${operation}: column "${key}" is blocked.`);
411
+ if (operation === 'update' && rule === 'required' && values[key] === undefined) {
412
+ throw new Error(`update: column "${key}" is required.`);
413
+ }
414
+ if (policy.timestamp && (operation === 'insert' || policy.timestamp === 'updated')) {
415
+ if (!generated) {
416
+ timestamp = this.getTimestamp();
417
+ generated = true;
418
+ }
419
+ values[key] = timestamp;
420
+ }
421
+ }
422
+ return values;
423
+ }
371
424
  /********************************************************************************************************************
372
425
  * (PRIVATE) insertValues
373
426
  * ******************************************************************************************************************/
@@ -399,26 +452,9 @@ class MySqlQuery {
399
452
  }
400
453
  }
401
454
  add(value) {
402
- return this.insertValues(value);
403
- }
404
- addWithCreatedAt(value) {
405
- const created_at = this.getTimestamp();
406
455
  const items = Array.isArray(value) ? value : [value];
407
- const values = items.map((item) => ({
408
- ...item,
409
- [this.timestampColumns.createdAt ?? 'created_at']: created_at,
410
- }));
411
- return this.insertValues(Array.isArray(value) ? values : values[0]);
412
- }
413
- addWithCreatedUpdatedAt(value) {
414
- const dateTime = this.getTimestamp();
415
- const items = Array.isArray(value) ? value : [value];
416
- const values = items.map((item) => ({
417
- ...item,
418
- [this.timestampColumns.createdAt ?? 'created_at']: dateTime,
419
- [this.timestampColumns.updatedAt ?? 'updated_at']: dateTime,
420
- }));
421
- return this.insertValues(Array.isArray(value) ? values : values[0]);
456
+ const values = items.map((item) => this.prepareValues(item, 'insert'));
457
+ return this.insertValues((Array.isArray(value) ? values : values[0]));
422
458
  }
423
459
  /********************************************************************************************************************
424
460
  * edit
@@ -429,7 +465,10 @@ class MySqlQuery {
429
465
  throw new Error('edit: a SQL where condition is required.');
430
466
  }
431
467
  const tx = this.getTx();
432
- return tx.update(this.t).set(set).where(condition);
468
+ return tx
469
+ .update(this.t)
470
+ .set(this.prepareValues(set, 'update'))
471
+ .where(condition);
433
472
  }
434
473
  /********************************************************************************************************************
435
474
  * editByPrimaryKey
@@ -437,27 +476,6 @@ class MySqlQuery {
437
476
  editByPrimaryKey(set, key) {
438
477
  return this.edit(set, this.primaryKeyCondition(key, 'editByPrimaryKey'));
439
478
  }
440
- /********************************************************************************************************************
441
- * editWithUpdatedAt
442
- * ******************************************************************************************************************/
443
- editWithUpdatedAt(set, where) {
444
- const condition = typeof where === 'function' ? where(this) : where;
445
- if (!is(condition, SQL)) {
446
- throw new Error('editWithUpdatedAt: a SQL where condition is required.');
447
- }
448
- const tx = this.getTx();
449
- const values = {
450
- ...set,
451
- [this.timestampColumns.updatedAt ?? 'updated_at']: this.getTimestamp(),
452
- };
453
- return tx.update(this.t).set(values).where(condition);
454
- }
455
- /********************************************************************************************************************
456
- * editWithUpdatedAtByPrimaryKey
457
- * ******************************************************************************************************************/
458
- editWithUpdatedAtByPrimaryKey(set, key) {
459
- return this.editWithUpdatedAt(set, this.primaryKeyCondition(key, 'editWithUpdatedAtByPrimaryKey'));
460
- }
461
479
  /********************************************************************************************************************
462
480
  * remove
463
481
  * ******************************************************************************************************************/
@@ -658,9 +676,9 @@ const normalizeFields = (fields) => {
658
676
  if (!options.timestamp)
659
677
  throw new Error('timestamp generator is not configured');
660
678
  return options.timestamp();
661
- }, options.timestampColumns),
679
+ }),
662
680
  trans,
663
681
  paginate,
664
682
  close: () => pool.end(),
665
683
  };
666
- }export{MySqlQuery,TableColumns,createConditions,drizzleMySql as default,drizzleMySql};
684
+ }export{MySqlQuery,TableColumns,createConditions,drizzleMySql as default,drizzleMySql,mysqlTable};
@@ -0,0 +1,60 @@
1
+ import { type ColumnBuilderBase } from 'drizzle-orm/column-builder';
2
+ import { type MySqlTable, type MySqlTableWithColumns } from 'drizzle-orm/mysql-core';
3
+ import type { BuildColumns } from 'drizzle-orm/column-builder';
4
+ import type { MySqlColumnBuilders } from 'drizzle-orm/mysql-core/columns/all';
5
+ import type { MySqlTableExtraConfig, MySqlTableExtraConfigValue } from 'drizzle-orm/mysql-core/table';
6
+ export type ColumnPolicy = {
7
+ insert?: 'blocked' | 'allowed';
8
+ update?: 'blocked' | 'allowed' | 'required';
9
+ timestamp?: 'created' | 'updated';
10
+ };
11
+ declare const policyType: unique symbol;
12
+ declare const tablePolicyType: unique symbol;
13
+ type Mark<T, P extends ColumnPolicy> = T & {
14
+ readonly [policyType]: P;
15
+ };
16
+ declare module 'drizzle-orm/column-builder' {
17
+ interface ColumnBuilder<T, TRuntimeConfig, TExtraConfig> {
18
+ insertBlocked(): Mark<this, {
19
+ insert: 'blocked';
20
+ }>;
21
+ insertAllowed(): Mark<this, {
22
+ insert: 'allowed';
23
+ }>;
24
+ updateBlocked(): Mark<this, {
25
+ update: 'blocked';
26
+ }>;
27
+ updateAllowed(): Mark<this, {
28
+ update: 'allowed';
29
+ }>;
30
+ updateRequired(): Mark<this, {
31
+ update: 'required';
32
+ }>;
33
+ createdAt(): Mark<this, {
34
+ timestamp: 'created';
35
+ }>;
36
+ updatedAt(): Mark<this, {
37
+ timestamp: 'updated';
38
+ }>;
39
+ }
40
+ }
41
+ type Policies<C> = {
42
+ [K in keyof C]: C[K] extends {
43
+ readonly [policyType]: infer P;
44
+ } ? P : {};
45
+ };
46
+ export type TablePolicies<T> = T extends {
47
+ readonly [tablePolicyType]: infer P;
48
+ } ? P : {};
49
+ type TableResult<N extends string, C extends Record<string, ColumnBuilderBase>> = MySqlTableWithColumns<{
50
+ name: N;
51
+ schema: undefined;
52
+ columns: BuildColumns<N, C, 'mysql'>;
53
+ dialect: 'mysql';
54
+ isAlias: false;
55
+ }> & {
56
+ readonly [tablePolicyType]: Policies<C>;
57
+ };
58
+ export declare function getColumnPolicies(table: MySqlTable): Record<string, ColumnPolicy>;
59
+ export declare function mysqlTable<N extends string, C extends Record<string, ColumnBuilderBase>>(name: N, columns: C | ((types: MySqlColumnBuilders) => C), extraConfig?: (self: BuildColumns<N, C, 'mysql'>) => MySqlTableExtraConfig | (MySqlTableExtraConfigValue | MySqlTableExtraConfigValue[])[]): TableResult<N, C>;
60
+ export {};
@@ -0,0 +1,60 @@
1
+ import { type ColumnBuilderBase } from 'drizzle-orm/column-builder';
2
+ import { type MySqlTable, type MySqlTableWithColumns } from 'drizzle-orm/mysql-core';
3
+ import type { BuildColumns } from 'drizzle-orm/column-builder';
4
+ import type { MySqlColumnBuilders } from 'drizzle-orm/mysql-core/columns/all';
5
+ import type { MySqlTableExtraConfig, MySqlTableExtraConfigValue } from 'drizzle-orm/mysql-core/table';
6
+ export type ColumnPolicy = {
7
+ insert?: 'blocked' | 'allowed';
8
+ update?: 'blocked' | 'allowed' | 'required';
9
+ timestamp?: 'created' | 'updated';
10
+ };
11
+ declare const policyType: unique symbol;
12
+ declare const tablePolicyType: unique symbol;
13
+ type Mark<T, P extends ColumnPolicy> = T & {
14
+ readonly [policyType]: P;
15
+ };
16
+ declare module 'drizzle-orm/column-builder' {
17
+ interface ColumnBuilder<T, TRuntimeConfig, TExtraConfig> {
18
+ insertBlocked(): Mark<this, {
19
+ insert: 'blocked';
20
+ }>;
21
+ insertAllowed(): Mark<this, {
22
+ insert: 'allowed';
23
+ }>;
24
+ updateBlocked(): Mark<this, {
25
+ update: 'blocked';
26
+ }>;
27
+ updateAllowed(): Mark<this, {
28
+ update: 'allowed';
29
+ }>;
30
+ updateRequired(): Mark<this, {
31
+ update: 'required';
32
+ }>;
33
+ createdAt(): Mark<this, {
34
+ timestamp: 'created';
35
+ }>;
36
+ updatedAt(): Mark<this, {
37
+ timestamp: 'updated';
38
+ }>;
39
+ }
40
+ }
41
+ type Policies<C> = {
42
+ [K in keyof C]: C[K] extends {
43
+ readonly [policyType]: infer P;
44
+ } ? P : {};
45
+ };
46
+ export type TablePolicies<T> = T extends {
47
+ readonly [tablePolicyType]: infer P;
48
+ } ? P : {};
49
+ type TableResult<N extends string, C extends Record<string, ColumnBuilderBase>> = MySqlTableWithColumns<{
50
+ name: N;
51
+ schema: undefined;
52
+ columns: BuildColumns<N, C, 'mysql'>;
53
+ dialect: 'mysql';
54
+ isAlias: false;
55
+ }> & {
56
+ readonly [tablePolicyType]: Policies<C>;
57
+ };
58
+ export declare function getColumnPolicies(table: MySqlTable): Record<string, ColumnPolicy>;
59
+ export declare function mysqlTable<N extends string, C extends Record<string, ColumnBuilderBase>>(name: N, columns: C | ((types: MySqlColumnBuilders) => C), extraConfig?: (self: BuildColumns<N, C, 'mysql'>) => MySqlTableExtraConfig | (MySqlTableExtraConfigValue | MySqlTableExtraConfigValue[])[]): TableResult<N, C>;
60
+ export {};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@pdg/drizzle-mysql",
3
3
  "title": "Drizzle for MySql",
4
4
  "description": "Drizzle for MySql",
5
- "version": "1.0.0",
5
+ "version": "1.0.1",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",
8
8
  "module": "./dist/index.esm.js",