Skip to content
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"scripts": {
"check": "yarn clean && yarn lint && yarn prepack:all && yarn test",
"lint": "eslint packages && lerna run tslint",
"lint:fix": "eslint --fix 'packages/**/*.{ts,js}'",
"flow": "flow",
"flow:check": "flow check",
"test": "lerna run --concurrency 1 test",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @flow
import { LiveProvider } from "graphile-build";
import type { PgClass } from "./plugins/PgIntrospectionPlugin";
import { PgClass } from "./plugins/PgIntrospectionPlugin";

export default class PgLiveProvider extends LiveProvider {
// eslint-disable-next-line flowtype/no-weak-types
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// @flow
import * as sql from "pg-sql2";
import type { SQL } from "pg-sql2";
import { SQL } from "pg-sql2";
import isSafeInteger from "lodash/isSafeInteger";
import chunk from "lodash/chunk";
import type { PgClass, PgType } from "./plugins/PgIntrospectionPlugin";
import { PgClass, PgType } from "./plugins/PgIntrospectionPlugin";

// eslint-disable-next-line flowtype/no-weak-types
type GraphQLContext = any;

const isDev = process.env.POSTGRAPHILE_ENV === "development";

type GenContext = {
queryBuilder: QueryBuilder,
queryBuilder: QueryBuilder;
};

type Gen<T> = (context: GenContext) => T;

function callIfNecessary<T>(o: Gen<T> | T, context: GenContext): T {
Expand All @@ -39,10 +39,10 @@ type SQLAlias = SQL;
type SQLGen = Gen<SQL> | SQL;
type NumberGen = Gen<number> | number;
type CursorValue = {};
type CursorComparator = (val: CursorValue, isAfter: boolean) => void;
type CursorComparator = (val: CursorValue, isAfter: boolean) => undefined;

export type QueryBuilderOptions = {
supportsJSONB?: boolean, // Defaults to true
supportsJSONB?: boolean;
};

function escapeLarge(sqlFragment: SQL, type: PgType) {
Expand All @@ -66,62 +66,71 @@ function escapeLarge(sqlFragment: SQL, type: PgType) {
}

class QueryBuilder {
parentQueryBuilder: QueryBuilder | void;
parentQueryBuilder: QueryBuilder | undefined;
context: GraphQLContext;
rootValue: any; // eslint-disable-line flowtype/no-weak-types
supportsJSONB: boolean;
locks: {
[string]: false | true | string,
[a: string]: false | true | string;
};

finalized: boolean;
selectedIdentifiers: boolean;
data: {
cursorPrefix: Array<string>,
select: Array<[SQLGen, RawAlias]>,
selectCursor: ?SQLGen,
from: ?[SQLGen, SQLAlias],
join: Array<SQLGen>,
where: Array<SQLGen>,
cursorPrefix: Array<string>;
select: Array<[SQLGen, RawAlias]>;
selectCursor: SQLGen | null | undefined;
from: [SQLGen, SQLAlias] | null | undefined;
join: Array<SQLGen>;
where: Array<SQLGen>;
whereBound: {
lower: Array<SQLGen>,
upper: Array<SQLGen>,
},
orderBy: Array<[SQLGen, boolean, boolean | null]>,
orderIsUnique: boolean,
limit: ?NumberGen,
offset: ?NumberGen,
first: ?number,
last: ?number,
lower: Array<SQLGen>;
upper: Array<SQLGen>;
};

orderBy: Array<[SQLGen, boolean, boolean | null]>;
orderIsUnique: boolean;
limit: NumberGen | null | undefined;
offset: NumberGen | null | undefined;
first: number | null | undefined;
last: number | null | undefined;
beforeLock: {
[string]: Array<() => void> | null,
},
cursorComparator: ?CursorComparator,
[a: string]: Array<() => undefined> | null;
};

cursorComparator: CursorComparator | null | undefined;
liveConditions: Array<
// eslint-disable-next-line flowtype/no-weak-types
[(data: {}) => (record: any) => boolean, { [key: string]: SQL } | void]
>,
[
(data: {}) => (record: any) => boolean,
{ [key: string]: SQL } | undefined
]
>;
};

compiledData: {
cursorPrefix: Array<string>,
select: Array<[SQL, RawAlias]>,
selectCursor: ?SQL,
from: ?[SQL, SQLAlias],
join: Array<SQL>,
where: Array<SQL>,
cursorPrefix: Array<string>;
select: Array<[SQL, RawAlias]>;
selectCursor: SQL | null | undefined;
from: [SQL, SQLAlias] | null | undefined;
join: Array<SQL>;
where: Array<SQL>;
whereBound: {
lower: Array<SQL>,
upper: Array<SQL>,
},
orderBy: Array<[SQL, boolean, boolean | null]>,
orderIsUnique: boolean,
limit: ?number,
offset: ?number,
first: ?number,
last: ?number,
cursorComparator: ?CursorComparator,
lower: Array<SQL>;
upper: Array<SQL>;
};

orderBy: Array<[SQL, boolean, boolean | null]>;
orderIsUnique: boolean;
limit: number | null | undefined;
offset: number | null | undefined;
first: number | null | undefined;
last: number | null | undefined;
cursorComparator: CursorComparator | null | undefined;
};

lockContext: {
queryBuilder: QueryBuilder,
queryBuilder: QueryBuilder;
};

constructor(
Expand Down Expand Up @@ -154,6 +163,7 @@ class QueryBuilder {
limit: false,
offset: false,
};

this.finalized = false;
this.selectedIdentifiers = false;
this.data = {
Expand All @@ -168,6 +178,7 @@ class QueryBuilder {
lower: [],
upper: [],
},

orderBy: [],
orderIsUnique: false,
limit: null,
Expand All @@ -191,9 +202,11 @@ class QueryBuilder {
limit: [],
offset: [],
},

cursorComparator: null,
liveConditions: [],
};

this.compiledData = {
cursorPrefix: ["natural"],
select: [],
Expand All @@ -205,6 +218,7 @@ class QueryBuilder {
lower: [],
upper: [],
},

orderBy: [],
orderIsUnique: false,
limit: null,
Expand All @@ -213,6 +227,7 @@ class QueryBuilder {
last: null,
cursorComparator: null,
};

this.beforeLock("select", () => {
this.lock("selectCursor");
if (this.compiledData.selectCursor) {
Expand Down Expand Up @@ -254,6 +269,7 @@ class QueryBuilder {
([expr, alias]) =>
sql.fragment`${sql.literal(alias)}::text, ${expr}`
),

", "
)})`;
return sql.fragment`(${sql.join(
Expand All @@ -266,14 +282,15 @@ class QueryBuilder {
fields.map(
([expr, alias]) => sql.fragment`${sql.literal(alias)}::text, ${expr}`
),

", "
)})`;
}
}

// ----------------------------------------

beforeLock(field: string, fn: () => void) {
beforeLock(field: string, fn: () => undefined) {
this.checkLock(field);
if (!this.data.beforeLock[field]) {
this.data.beforeLock[field] = [];
Expand All @@ -285,7 +302,7 @@ class QueryBuilder {
makeLiveCollection(
table: PgClass,
// eslint-disable-next-line flowtype/no-weak-types
cb?: (checker: (data: any) => (record: any) => boolean) => void
cb?: (checker: (data: any) => (record: any) => boolean) => undefined
) {
/* the actual condition doesn't matter hugely, 'select' should work */
if (!this.rootValue || !this.rootValue.liveConditions) return;
Expand All @@ -295,6 +312,7 @@ class QueryBuilder {
const checkers = liveConditions.map(([checkerGenerator]) =>
checkerGenerator(data)
);

return record => checkers.every(checker => checker(record));
};
if (this.parentQueryBuilder) {
Expand All @@ -311,6 +329,7 @@ class QueryBuilder {
requirements ? Object.assign(memo, requirements) : memo,
{}
);

// $FlowFixMe
this.parentQueryBuilder.select(
sql.fragment`\
Expand All @@ -319,6 +338,7 @@ ${sql.join(
Object.keys(allRequirements).map(
key => sql.fragment`, ${sql.literal(key)}::text, ${allRequirements[key]}`
),

""
)})`,
"__live"
Expand Down Expand Up @@ -392,10 +412,12 @@ ${sql.join(
key.type
)
),

", "
)})`,
"__identifiers"
);

this.selectedIdentifiers = true;
}
selectCursor(exprGen: SQLGen) {
Expand Down Expand Up @@ -574,15 +596,16 @@ ${sql.join(
([sqlFragment, alias]) =>
sql.fragment`to_json(${sqlFragment}) as ${sql.identifier(alias)}`
),

", "
);
}
buildSelectJson({
addNullCase,
addNotDistinctFromNullCase,
}: {
addNullCase?: boolean,
addNotDistinctFromNullCase?: boolean,
addNullCase?: boolean;
addNotDistinctFromNullCase?: boolean;
}) {
this.lockEverything();
let buildObject = this.compiledData.select.length
Expand Down Expand Up @@ -622,7 +645,7 @@ ${sql.join(
{
addNullCase,
addNotDistinctFromNullCase,
}: { addNullCase?: boolean, addNotDistinctFromNullCase?: boolean }
}: { addNullCase?: boolean; addNotDistinctFromNullCase?: boolean }
) {
this.lock("where");
const clauses = [
Expand Down Expand Up @@ -658,18 +681,19 @@ ${sql.join(
...(includeLowerBound ? [this.buildWhereBoundClause(true)] : []),
...(includeUpperBound ? [this.buildWhereBoundClause(false)] : []),
];

return clauses.length
? sql.fragment`(${sql.join(clauses, ") and (")})`
: sql.fragment`1 = 1`;
}
build(
options: {
asJson?: boolean,
asJsonAggregate?: boolean,
onlyJsonField?: boolean,
addNullCase?: boolean,
addNotDistinctFromNullCase?: boolean,
useAsterisk?: boolean,
asJson?: boolean;
asJsonAggregate?: boolean;
onlyJsonField?: boolean;
addNullCase?: boolean;
addNotDistinctFromNullCase?: boolean;
useAsterisk?: boolean;
} = {}
) {
const {
Expand Down Expand Up @@ -717,6 +741,7 @@ ${
: null
}`
),

","
)}`
: ""
Expand Down Expand Up @@ -775,6 +800,7 @@ order by (row_number() over (partition by 1)) desc`;
this.data[type].lower,
context
);

this.compiledData[type].upper = callIfNecessaryArray(
this.data[type].upper,
context
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @flow
import PgBasicsPlugin from "./plugins/PgBasicsPlugin";
import PgIntrospectionPlugin from "./plugins/PgIntrospectionPlugin";
import PgTypesPlugin from "./plugins/PgTypesPlugin";
Expand Down
Loading