Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/0.9.16 #7

Merged
merged 11 commits into from
Dec 27, 2021
76 changes: 76 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Changelog

### 0.9.16 (December 27, 2021)

---

### Breaking changes:
- Delete `autoincrement` type on columns. Right now you should use `serial` type

#### Previous serial column defining:
```typescript
public id = this.int('id').autoincrement();
```
#### Current serial column defining:
```typescript
public id = this.serial('id');
```

- Move `notNull` from column type metadata to builder chain
#### Previous notNull defining:
```typescript
public phone = this.varchar('phone', { notNull: true });
```
#### Current notNull defining:
```typescript
public phone = this.varchar('phone').notNull();
```

- Divide `BigInt` into 2 types -> `BigInt53` and `BigInt64`
- Divide `BigSerial` into 2 types -> `BigSerial53` and `BigSerial64`

Due to have max value for big integers in postgres as 2^64 and javascript max value for integers is 2^53

If you sure, that value in this column won't be more than 2^53 you could use:
```typescript
public bigIntField = this.bigint('test1', 'max_bytes_53');
```
that will be of type `number` in typescript

If value in this column could be more than 2^53 you could use:
```typescript
public bigIntField = this.bigint('test1', 'max_bytes_64');
```
that will be of type `bigint` in typescript
---

### Fixes and Functionality:
- Add `SET NULL` and `SET DEFAULT` for `ON DELETE` and `ON UPDATE` constraints

#### Example of usage
```typescript
public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, { onUpdate: 'SET NULL' });

public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, { onDelete: 'SET DEFAULT' });
```
- Add default value for timestamp
```typescript
public createdAt = this.timestamp('created_at').defaultValue(Defaults.CURRENT_TIMESTAMP);
```
- Add `timestamp with timezone` type
```typescript
public createdAt = this.timestamptz('created_at');
```
- Add migrator function to use `drizzle-kit` generated migrations
##### Provide drizzle-kit config path
```typescript
await drizzle.migrator(db).migrate('src/drizzle.config.yaml');
```
##### Provide object with path to folder with migrations
```typescript
await drizzle.migrator(db).migrate({ migrationFolder: 'drizzle' });
```
---

### Documentation:
- Change README documentation for all changes in current release
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,20 @@ const db = await new DbConnector()
export const rolesEnum = createEnum({ alias: 'test-enum', values: ['user', 'guest', 'admin'] });

export default class UsersTable extends AbstractTable<UsersTable> {
public id = this.int('id').autoIncrement().primaryKey();
public id = this.serial('id').primaryKey();
public fullName = this.text('full_name');

public phone = this.varchar('phone', { size: 256 });
public media = this.jsonb<string[]>('media');
public decimalField = this.decimal('test', { notNull: true, precision: 100, scale: 2 });
public bigIntField = this.bigint('test1');
public role = this.type(rolesEnum, 'name_in_table', { notNull: true });
public decimalField = this.decimal('test', { precision: 100, scale: 2 }).notNull();
public bigIntField = this.bigint('test1', 'max_bytes_53');
public role = this.type(rolesEnum, 'name_in_table').notNull();

public createdAt = this.timestamp('created_at', { notNull: true });
public updatedAt = this.timestamp('updated_at');
public createdAt = this.timestamp('created_at').notNull();

public createdAtWithTimezone = this.timestamptz('created_at_time_zone');

public updatedAt = this.timestamp('updated_at').defaultValue(Defaults.CURRENT_TIMESTAMP);
public isArchived = this.bool('is_archived').defaultValue(false);

public phoneFullNameIndex = this.index([this.phone, this.fullName]);
Expand All @@ -90,12 +93,12 @@ interface CityMeta {
}

export default class CitiesTable extends AbstractTable<CitiesTable> {
public id = this.int('id').autoIncrement().primaryKey();
public id = this.serial('id').primaryKey();

public foundationDate = this.timestamp('name', { notNull: true });
public foundationDate = this.timestamp('name').notNull();
public location = this.varchar('page', { size: 256 });

public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, OnDelete.CASCADE);
public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, { onUpdate: 'CASCADE' });

public metadata = this.jsonb<CityMeta>('metadata');

Expand All @@ -108,7 +111,7 @@ export default class CitiesTable extends AbstractTable<CitiesTable> {
---
```typescript
export default class UserGroupsTable extends AbstractTable<UserGroupsTable> {
public id = this.int('id').autoIncrement().primaryKey();
public id = this.serial('id').primaryKey();

public name = this.varchar('name');
public description = this.varchar('description');
Expand All @@ -123,8 +126,8 @@ export default class UserGroupsTable extends AbstractTable<UserGroupsTable> {
#### Many to many connection between Users and User Groups
```typescript
export default class UsersToUserGroupsTable extends AbstractTable<UsersToUserGroupsTable> {
public groupId = this.int('city_id').foreignKey(UserGroupsTable, (table) => table.id, OnDelete.CASCADE);
public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, OnDelete.CASCADE);
public groupId = this.int('city_id').foreignKey(UserGroupsTable, (table) => table.id, { onDelete: 'CASCADE' });
public userId = this.int('user_id').foreignKey(UsersTable, (table) => table.id, { onDelete: 'CASCADE' });

public manyToManyIndex = this.index([this.groupId, this.userId]);

Expand Down Expand Up @@ -382,4 +385,15 @@ const citiesWithUserObject = userWithCities.map((city, user) => ({ ...city, user
...userGroupWithUsers.one,
users: userGroupWithUsers.many,
};
```

## Migrations
#### To run migrations generated by drizzle-kit you could use `Migtator` class
##### Provide drizzle-kit config path
```typescript
await drizzle.migrator(db).migrate('src/drizzle.config.yaml');
```
##### Provide object with path to folder with migrations
```typescript
await drizzle.migrator(db).migrate({ migrationFolder: 'drizzle' });
```
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-orm",
"version": "0.9.14",
"version": "0.9.16",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/builders/lowLvlBuilders/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default class Create<TTable extends AbstractTable<TTable>> {
}
this.columnsBuilder.push(ecranate(column.getColumnName()));
this.columnsBuilder.push(' ');
this.columnsBuilder.push(column.isAutoIncrement() ? 'SERIAL' : column.getColumnType().getDbName());
this.columnsBuilder.push(column.getColumnType().getDbName());
this.columnsBuilder.push(' ');
this.columnsBuilder.push(column.getDefaultValue() != null ? `DEFAULT ${column.getColumnType().insertStrategy(column.getDefaultValue())}` : '');
this.columnsBuilder.push(column.isNullableFlag ? '' : ' NOT NULL');
Expand Down
76 changes: 29 additions & 47 deletions src/columns/column.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable max-len */
/* eslint-disable max-classes-per-file */
import { PgTime, PgTimestamp } from '.';
import DB from '../db/db';
import { AbstractTable } from '../tables';
import ColumnType from './types/columnType';
import PgTimestamptz from './types/pgTimestamptz';

type ExtractColumnType<T extends ColumnType> =
T extends ColumnType<infer TCodeType> ?
TCodeType
: never;

export enum OnDelete {
RESTRICT = 'ON DELETE RESTRICT',
CASCADE = 'ON DELETE CASCADE',
export enum Defaults {
CURRENT_TIMESTAMP = 'CURRENT_TIMESTAMP',
}

export enum OnUpdate {
RESTRICT = 'ON UPDATE RESTRICT',
CASCADE = 'ON UPDATE RESTRICT',
}
type PgTimes = PgTimestamptz | PgTime | PgTimestamp;

export type ExtractColumnType<T extends ColumnType> =
T extends ColumnType<infer TCodeType> ?
T extends PgTimes ? TCodeType | Defaults : TCodeType
: never;

// eslint-disable-next-line max-len
export abstract class AbstractColumn<T extends ColumnType, TNullable extends boolean = true, TAutoIncrement extends boolean = false> {
public isNullableFlag: TNullable;
public autoIncrementType: TAutoIncrement;
public isNullableFlag: boolean = true;
public primaryKeyName?: string;
public uniqueKeyName?: string;

Expand All @@ -33,17 +31,15 @@ export abstract class AbstractColumn<T extends ColumnType, TNullable extends boo
protected parentTableName: string;
protected columnType: T;
protected columnName: string;
protected autoIncrementFlag: boolean = false;
protected defaultParam: any = null;
protected referenced: AbstractColumn<T, boolean, boolean>;

public constructor(parent: AbstractTable<any>, columnName: string,
columnType: T, nullable: TNullable) {
columnType: T) {
this.columnType = columnType;
this.columnName = columnName;
this.parentTableName = parent.tableName();
this.parent = parent;
this.isNullableFlag = nullable;
}

public getOnDelete = (): string | undefined => this.onDelete;
Expand All @@ -58,8 +54,8 @@ export abstract class AbstractColumn<T extends ColumnType, TNullable extends boo
public abstract foreignKey <ITable extends AbstractTable<ITable>>(table: { new(db: DB): ITable ;},
callback: (table: ITable) => AbstractColumn<T, boolean, boolean>,
onConstraint: {
onDelete?: 'CASCADE' | 'RESTRICT',
onUpdate?: 'CASCADE' | 'RESTRICT'
onDelete?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT',
onUpdate?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT'
})
: AbstractColumn<T, TNullable, TAutoIncrement>;

Expand All @@ -68,18 +64,14 @@ export abstract class AbstractColumn<T extends ColumnType, TNullable extends boo
return this;
};

public abstract autoIncrement(): AbstractColumn<T, boolean, boolean>;

public abstract primaryKey(): AbstractColumn<T, boolean, boolean>;

public abstract serial(): AbstractColumn<T, boolean, boolean>;

public unique = () => {
this.uniqueKeyName = this.columnName;
return this;
};

public isAutoIncrement = (): boolean => this.autoIncrementFlag;
public abstract notNull(): AbstractColumn<T, boolean, boolean>;

public getColumnName = (): string => this.columnName;

Expand All @@ -94,13 +86,13 @@ export abstract class AbstractColumn<T extends ColumnType, TNullable extends boo
export class Column<T extends ColumnType, TNullable extends boolean = true, TAutoIncrement extends boolean = false>
extends AbstractColumn<T, TNullable, TAutoIncrement> {
public constructor(parent: AbstractTable<any>, columnName: string,
columnType: T, nullable: TNullable) {
super(parent, columnName, columnType, nullable);
columnType: T) {
super(parent, columnName, columnType);
}

public serial() {
this.autoIncrementFlag = true;
return this as unknown as Column<T, false, true>;
public notNull() {
this.isNullableFlag = false;
return this as unknown as Column<T, TAutoIncrement extends true ? true : TNullable extends true? false : true, TAutoIncrement>;
}

public primaryKey() {
Expand All @@ -113,8 +105,8 @@ export class Column<T extends ColumnType, TNullable extends boolean = true, TAut
table: new (db: DB) => ITable,
callback: (table: ITable) => Column<T, boolean, boolean>,
onConstraint?: {
onDelete?: 'CASCADE' | 'RESTRICT',
onUpdate?: 'CASCADE' | 'RESTRICT'
onDelete?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT',
onUpdate?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT'
},
): Column<T, TNullable, TAutoIncrement> {
const tableInstance = this.getParent().db.create(table);
Expand All @@ -123,23 +115,18 @@ export class Column<T extends ColumnType, TNullable extends boolean = true, TAut
this.onUpdate = onConstraint?.onUpdate ? `ON UPDATE ${onConstraint.onUpdate}` : undefined;
return this;
}

public autoIncrement() {
this.autoIncrementFlag = true;
return this as unknown as IndexedColumn<T, true, true>;
}
}

// eslint-disable-next-line max-len
export class IndexedColumn<T extends ColumnType, TNullable extends boolean = true, TAutoIncrement extends boolean = false> extends AbstractColumn<T, TNullable, TAutoIncrement> {
public constructor(parent: AbstractTable<any>, columnName: string,
columnType: T, nullable: TNullable) {
super(parent, columnName, columnType, nullable);
super(parent, columnName, columnType);
}

public serial() {
this.autoIncrementFlag = true;
return this as unknown as IndexedColumn<T, false, true>;
public notNull() {
this.isNullableFlag = false;
return this as unknown as IndexedColumn<T, TAutoIncrement extends true ? true : TNullable extends true? false : true, TAutoIncrement>;
}

public primaryKey() {
Expand All @@ -152,8 +139,8 @@ export class IndexedColumn<T extends ColumnType, TNullable extends boolean = tru
table: new (db: DB) => ITable,
callback: (table: ITable) => IndexedColumn<T, boolean, boolean>,
onConstraint?: {
onDelete?: 'CASCADE' | 'RESTRICT',
onUpdate?: 'CASCADE' | 'RESTRICT'
onDelete?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT',
onUpdate?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT'
},
): IndexedColumn<T, TNullable, TAutoIncrement> {
// eslint-disable-next-line new-cap
Expand All @@ -162,9 +149,4 @@ export class IndexedColumn<T extends ColumnType, TNullable extends boolean = tru
this.onUpdate = onConstraint?.onUpdate ? `ON UPDATE ${onConstraint.onUpdate}` : undefined;
return this;
}

public autoIncrement() {
this.autoIncrementFlag = true;
return this as unknown as IndexedColumn<T, true, true>;
}
}
2 changes: 1 addition & 1 deletion src/columns/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Column } from './column';
export { Column, ExtractColumnType, Defaults } from './column';
export { default as PgBigDecimal } from './types/pgBigDecimal';
export { default as PgBigInt } from './types/pgBigInt';
export { default as PgBoolean } from './types/pgBoolean';
Expand Down
24 changes: 20 additions & 4 deletions src/columns/types/pgBigInt.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
// eslint-disable-next-line max-classes-per-file
import ColumnType from './columnType';

export default class PgBigInt extends ColumnType<number> {
export default class PgBigInt53 extends ColumnType<number> {
public dbName: string;

public constructor() {
super();
this.dbName = 'BIGINT';
}

public getDbName(): string {
return this.dbName;
}
public getDbName = (): string => this.dbName;

public insertStrategy = (value: number): string => `${value}`;

public selectStrategy(value: string): number | undefined {
return value ? parseInt(value, 10) : undefined;
}
}

export class PgBigInt64 extends ColumnType<bigint> {
public dbName: string;

public constructor() {
super();
this.dbName = 'BIGINT';
}

public getDbName = (): string => this.dbName;

public insertStrategy = (value: bigint): string => `${value}`;

public selectStrategy(value: string): bigint | undefined {
return value ? BigInt(value) : undefined;
}
}
Loading