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

Handling domains #155

Merged
merged 1 commit into from
Jan 19, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -299,7 +299,8 @@ This is required for some SQL operations that cannot be run within a transaction
- `column_options` _[object]_ - optional new column options
- `default` _[string or null]_ - null, string
- `type` _[string]_ - new datatype
- `notNull` _[boolean]_ - sets NOT NULL if true
- `notNull` _[boolean]_ - sets NOT NULL if true or NULL if false
- `allowNull` _[boolean]_ - sets NULL if true (alternative to `notNull`)
- `using` _[string]_ - adds USING clause to change values in column
- `collation` _[string]_ - adds COLLATE clause to change values in column

@@ -689,6 +690,64 @@ This is required for some SQL operations that cannot be run within a transaction

-----------------------------------------------------

### Domain Operations

#### `pgm.createDomain( domain_name, type, options )`

> Create a new domain - [postgres docs](https://www.postgresql.org/docs/current/static/sql-createdomain.html)

**Arguments:**
- `domain_name` _[string]_ - name of the new domain
- `type` _[string]_ - type of the new domain
- `options` _[object]_ - options:
- `default` _[string]_ - default value of domain
- `collation` _[string]_ - collation of data type
- `notNull` _[boolean]_ - sets NOT NULL if true ([not recommended](https://www.postgresql.org/docs/10/static/sql-createdomain.html#idm46428678330368))
- `check` _[string]_ - sql for a check constraint for this column
- `constraintName` _[string]_ - name for constraint

**Reverse Operation:** `dropDomain`

-----------------------------------------------------

#### `pgm.dropDomain( domain_name, drop_options )`

> Drop a domain - [postgres docs](http://www.postgresql.org/docs/current/static/sql-dropdomain.html)

**Arguments:**
- `domain_name` _[string]_ - name of the the domain to drop
- `drop_options` _[object]_ - options:
- `ifExists` _[boolean]_ - drops domain only if it exists
- `cascade` _[boolean]_ - drops also dependent objects

-----------------------------------------------------

#### `pgm.alterDomain( domain_name, type, options )`

> Alter a domain - [postgres docs](https://www.postgresql.org/docs/current/static/sql-alterdomain.html)

**Arguments:**
- `domain_name` _[string]_ - name of the new domain
- `options` _[object]_ - options:
- `default` _[string]_ - default value of domain
- `collation` _[string]_ - collation of data type
- `notNull` _[boolean]_ - sets NOT NULL if true or NULL if false
- `allowNull` _[boolean]_ - sets NULL if true (alternative to `notNull`)
- `check` _[string]_ - sql for a check constraint for this column
- `constraintName` _[string]_ - name for constraint

-----------------------------------------------------

#### `pgm.renameDomain( old_domain_name, new_domain_name )`

> Rename a domain - [postgres docs](http://www.postgresql.org/docs/current/static/sql-alterdomain.html)

**Arguments:**
- `old_domain_name` _[string]_ - old name of the domain
- `new_domain_name` _[string]_ - new name of the domain

-----------------------------------------------------

### Miscellaneous Operations

#### `pgm.sql( sql )`
23 changes: 23 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -188,6 +188,22 @@ export interface TriggerOptionsEn {
deferred: boolean
}

export interface DomainOptionsCreate {
default?: Value
collation?: string
notNull?: boolean
check?: string
constraintName?: string
}

export interface DomainOptionsAlter {
default?: Value
notNull?: boolean
allowNull?: boolean
check?: string
constraintName?: string
}

export type TriggerOptions = TriggerOptionsEn & FunctionOptions

export interface MigrationBuilder {
@@ -251,6 +267,13 @@ export interface MigrationBuilder {
createSchema(schema_name: string, schema_options: { ifNotExists?: boolean, authorization?: string }): void
dropSchema(schema_name: string, drop_options: DropOptions): void
renameSchema(old_schema_name: string, new_schema_name: string): void

// Domains
createDomain(domain_name: Name, domain_options: DomainOptionsCreate): void
dropDomain(domain_name: Name, drop_options: DropOptions): void
alterDomain(domain_name: Name, domain_options: DomainOptionsAlter): void
renameDomain(old_domain_name: Name, new_domain_name: Name): void

sql(sql: string, args?: object): void
func(sql: string): PgLiteral
noTransaction(): void
6 changes: 6 additions & 0 deletions lib/migration-builder.js
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ import * as roles from './operations/roles';
import * as functions from './operations/functions';
import * as triggers from './operations/triggers';
import * as schemas from './operations/schemas';
import * as domains from './operations/domains';
import * as other from './operations/other';

export default class MigrationBuilder {
@@ -95,6 +96,11 @@ export default class MigrationBuilder {
this.dropSchema = wrap(schemas.drop);
this.renameSchema = wrap(schemas.rename);

this.createDomain = wrap(domains.create(options.typeShorthands));
this.dropDomain = wrap(domains.drop);
this.alterDomain = wrap(domains.alter);
this.renameDomain = wrap(domains.rename);

this.sql = wrap(other.sql);

// Other utilities which may be useful
76 changes: 76 additions & 0 deletions lib/operations/domains.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { template, applyType, escapeValue } from '../utils';

export const drop = (domain_name, { ifExists, cascade } = {}) =>
template`DROP DOMAIN${ifExists ? ' IF EXISTS' : ''} "${domain_name}"${cascade ? ' CASCADE' : ''};`;

export const create = (type_shorthands) => {
const _create = (domain_name, type, options) => {
const {
default: defaultValue,
collation,
notNull,
check,
constraintName,
} = options;
const constraints = [];
if (collation) {
constraints.push(`COLLATE ${collation}`);
}
if (defaultValue !== undefined) {
constraints.push(`DEFAULT ${escapeValue(defaultValue)}`);
}
if (notNull && check) {
throw new Error('"notNull" and "check" can\'t be specified together');
} else if (notNull || check) {
if (constraintName) {
constraints.push(`CONSTRAINT ${constraintName}`);
}
if (notNull) {
constraints.push('NOT NULL');
} else if (check) {
constraints.push(`CHECK (${check})`);
}
}

const constraintsString = constraints.length ? ` ${constraints.join(' ')}` : '';

return template`CREATE DOMAIN "${domain_name}" AS ${applyType(type, type_shorthands).type}${constraintsString};`;
};
_create.reverse = drop;
return _create;
};

export const alter = (domain_name, options) => {
const {
default: defaultValue,
notNull,
allowNull,
check,
constraintName,
} = options;
const actions = [];
if (defaultValue === null) {
actions.push('DROP DEFAULT');
} else if (defaultValue !== undefined) {
actions.push(`SET DEFAULT ${escapeValue(defaultValue)}`);
}
if (notNull) {
actions.push('SET NOT NULL');
} else if (notNull === false || allowNull) {
actions.push('DROP NOT NULL');
}
if (check) {
actions.push(`${constraintName ? `CONSTRAINT ${constraintName} ` : ''}CHECK (${check})`);
}

return `${actions.map(action => template`ALTER DOMAIN "${domain_name}" ${action}`).join(';\n')};`;
};

// RENAME
export const rename = (domain_name, new_domain_name) =>
template`ALTER DOMAIN "${domain_name}" RENAME TO "${new_domain_name}";`;

export const undoRename = (domain_name, new_domain_name) =>
rename(new_domain_name, domain_name);

rename.reverse = undoRename;