graphile-search-plugin 0.1.2 → 0.1.3

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/LICENSE CHANGED
@@ -1,6 +1,8 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Dan Lynch <pyramation@gmail.com>
3
+ Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
+ Copyright (c) 2025 Hyperweb <developers@hyperweb.io>
5
+ Copyright (c) 2020-present, Interweb, Inc.
4
6
 
5
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
8
  of this software and associated documentation files (the "Software"), to deal
package/index.js ADDED
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // plugins/PgSearchPlugin.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PgSearchPlugin = void 0;
5
+ /**
6
+ * PgSearchPlugin - Generates search conditions for tsvector columns
7
+ */
8
+ const PgSearchPlugin = (builder, options = {}) => {
9
+ const { pgSearchPrefix = 'tsv' } = options;
10
+ builder.hook('GraphQLInputObjectType:fields', (fields, build, context) => {
11
+ const { inflection } = build;
12
+ const { scope: { isPgCondition, pgIntrospection: table }, fieldWithHooks } = context;
13
+ if (!isPgCondition || !table || table.kind !== 'class')
14
+ return fields;
15
+ const tsvs = table.attributes.filter((attr) => attr.type.name === 'tsvector');
16
+ if (!tsvs.length)
17
+ return fields;
18
+ return build.extend(fields, tsvs.reduce((memo, attr) => {
19
+ const fieldName = inflection.camelCase(`${pgSearchPrefix}_${attr.name}`);
20
+ memo[fieldName] = fieldWithHooks(fieldName, { type: build.graphql.GraphQLString }, {});
21
+ return memo;
22
+ }, {}));
23
+ });
24
+ builder.hook('GraphQLObjectType:fields:field:args', (args, build, context) => {
25
+ const { pgSql: sql, inflection } = build;
26
+ const { scope: { isPgFieldConnection, isPgFieldSimpleCollection, pgFieldIntrospection: procOrTable, pgFieldIntrospectionTable: tableIfProc, }, addArgDataGenerator, } = context;
27
+ const table = tableIfProc || procOrTable;
28
+ if ((!isPgFieldConnection && !isPgFieldSimpleCollection) ||
29
+ !table ||
30
+ table.kind !== 'class') {
31
+ return args;
32
+ }
33
+ const tsvs = table.attributes.filter((attr) => attr.type.name === 'tsvector');
34
+ if (!tsvs.length)
35
+ return args;
36
+ tsvs.forEach((tsv) => {
37
+ const conditionFieldName = inflection.camelCase(`${pgSearchPrefix}_${tsv.name}`);
38
+ addArgDataGenerator(function addSearchCondition({ condition }) {
39
+ if (!condition || !(conditionFieldName in condition))
40
+ return {};
41
+ const value = condition[conditionFieldName];
42
+ if (value == null)
43
+ return {};
44
+ return {
45
+ pgQuery: (queryBuilder) => {
46
+ const tsquery = sql.fragment `websearch_to_tsquery('english', ${sql.value(value)})`;
47
+ const tableAlias = queryBuilder.getTableAlias();
48
+ // WHERE condition
49
+ queryBuilder.where(sql.fragment `${tableAlias}.${sql.identifier(tsv.name)} @@ ${tsquery}`);
50
+ // Automatically add ordering by relevance (descending)
51
+ queryBuilder.orderBy(sql.fragment `ts_rank(${tableAlias}.${sql.identifier(tsv.name)}, ${tsquery})`, false);
52
+ },
53
+ };
54
+ });
55
+ });
56
+ return args;
57
+ }, [], ['PgConnectionArgOrderBy']);
58
+ };
59
+ exports.PgSearchPlugin = PgSearchPlugin;
package/package.json CHANGED
@@ -1,34 +1,33 @@
1
1
  {
2
2
  "name": "graphile-search-plugin",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "generate search conditions for your tsvector columns",
5
5
  "author": "Dan Lynch <pyramation@gmail.com>",
6
6
  "homepage": "https://github.com/pyramation/graphile-search-plugin#readme",
7
7
  "license": "SEE LICENSE IN LICENSE",
8
- "main": "main/index.js",
9
- "module": "module/index.js",
8
+ "main": "index.js",
9
+ "module": "esm/index.js",
10
+ "types": "index.d.ts",
10
11
  "directories": {
11
12
  "lib": "src",
12
13
  "test": "__tests__"
13
14
  },
14
15
  "files": [
15
- "main",
16
- "module"
16
+ "dist"
17
17
  ],
18
18
  "scripts": {
19
- "build:main": "cross-env BABEL_ENV=production babel src --out-dir main --delete-dir-on-start",
20
- "build:module": "cross-env MODULE=true babel src --out-dir module --delete-dir-on-start",
21
- "build": "npm run build:module && npm run build:main",
22
- "prepublish": "npm run build",
23
- "dev": "cross-env NODE_ENV=development babel-node src/index",
24
- "watch": "cross-env NODE_ENV=development babel-watch src/index",
25
- "lint": "eslint src --fix",
19
+ "copy": "copyfiles -f ../../LICENSE README.md package.json dist",
20
+ "clean": "rimraf dist/**",
21
+ "prepack": "pnpm run build",
22
+ "build": "pnpm run clean; tsc -p tsconfig.json; tsc -p tsconfig.esm.json; pnpm run copy",
23
+ "build:dev": "pnpm run clean; tsc -p tsconfig.json --declarationMap; tsc -p tsconfig.esm.json; pnpm run copy",
24
+ "lint": "eslint . --fix",
26
25
  "test": "jest",
27
- "test:watch": "jest --watch",
28
- "test:debug": "node --inspect node_modules/.bin/jest --runInBand"
26
+ "test:watch": "jest --watch"
29
27
  },
30
28
  "publishConfig": {
31
- "access": "public"
29
+ "access": "public",
30
+ "directory": "dist"
32
31
  },
33
32
  "repository": {
34
33
  "type": "git",
@@ -46,33 +45,15 @@
46
45
  "url": "https://github.com/pyramation/graphile-search-plugin/issues"
47
46
  },
48
47
  "devDependencies": {
49
- "@babel/cli": "7.11.6",
50
- "@babel/core": "7.11.6",
51
- "@babel/node": "^7.10.5",
52
- "@babel/plugin-proposal-class-properties": "7.10.4",
53
- "@babel/plugin-proposal-export-default-from": "7.10.4",
54
- "@babel/plugin-proposal-object-rest-spread": "7.11.0",
55
- "@babel/plugin-transform-runtime": "7.11.5",
56
- "@babel/preset-env": "7.11.5",
57
48
  "@pyramation/postgraphile-plugin-fulltext-filter": "2.0.0",
58
- "babel-core": "7.0.0-bridge.0",
59
- "babel-eslint": "10.1.0",
60
- "babel-jest": "25.1.0",
61
- "babel-watch": "^7.0.0",
62
- "cross-env": "^7.0.2",
63
- "envalid": "^6.0.2",
64
- "eslint": "6.8.0",
65
- "eslint-config-prettier": "^6.10.0",
66
- "eslint-plugin-prettier": "^3.1.2",
67
49
  "graphile-simple-inflector": "^0.1.1",
68
- "graphile-test": "^0.1.1",
69
- "jest": "^24.5.0",
70
- "jest-in-case": "^1.0.2",
71
- "postgraphile-plugin-connection-filter": "^2.0.0",
72
- "prettier": "^2.1.2",
73
- "regenerator-runtime": "^0.13.7"
50
+ "graphile-test": "^2.8.0",
51
+ "pgsql-test": "^2.14.3",
52
+ "postgraphile-plugin-connection-filter": "^2.0.0"
74
53
  },
75
54
  "dependencies": {
76
- "@babel/runtime": "^7.11.2"
77
- }
55
+ "graphile-build": "^4.14.1",
56
+ "graphql-tag": "2.12.6"
57
+ },
58
+ "gitHead": "da2bd9606bd5e1d4e63b7d74f08920975980e541"
78
59
  }
package/main/index.js DELETED
@@ -1,158 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
8
- exports["default"] = exports.PgSearchPlugin = void 0;
9
-
10
- var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
-
12
- function _templateObject3() {
13
- var data = (0, _taggedTemplateLiteral2["default"])(["", ".", " @@ ", ""]);
14
-
15
- _templateObject3 = function _templateObject3() {
16
- return data;
17
- };
18
-
19
- return data;
20
- }
21
-
22
- function _templateObject2() {
23
- var data = (0, _taggedTemplateLiteral2["default"])(["ts_rank ( ", ".", ", ", " )"]);
24
-
25
- _templateObject2 = function _templateObject2() {
26
- return data;
27
- };
28
-
29
- return data;
30
- }
31
-
32
- function _templateObject() {
33
- var data = (0, _taggedTemplateLiteral2["default"])(["websearch_to_tsquery('english', ", ")"]);
34
-
35
- _templateObject = function _templateObject() {
36
- return data;
37
- };
38
-
39
- return data;
40
- }
41
-
42
- function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
43
-
44
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
45
-
46
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
47
-
48
- var PgSearchPlugin = function PgSearchPlugin(builder, _ref) {
49
- var _ref$pgSearchPrefix = _ref.pgSearchPrefix,
50
- pgSearchPrefix = _ref$pgSearchPrefix === void 0 ? 'tsv' : _ref$pgSearchPrefix;
51
- builder.hook('GraphQLInputObjectType:fields', function addConditionInputField(fields, build, context) {
52
- var inflection = build.inflection;
53
- var _context$scope = context.scope,
54
- isPgCondition = _context$scope.isPgCondition,
55
- table = _context$scope.pgIntrospection,
56
- fieldWithHooks = context.fieldWithHooks;
57
-
58
- if (!isPgCondition || !table || table.kind !== 'class') {
59
- return fields;
60
- }
61
-
62
- var tsvs = table.attributes.filter(function (attr) {
63
- return attr.type.name === 'tsvector';
64
- });
65
- if (!tsvs.length) return fields;
66
- return build.extend(fields, tsvs.reduce(function (m, v) {
67
- var key = inflection.camelCase("".concat(pgSearchPrefix, "_").concat(v.name));
68
- m[key] = fieldWithHooks(key, {
69
- type: build.graphql.GraphQLString
70
- }, {});
71
- return m;
72
- }, {}));
73
- });
74
- builder.hook('GraphQLObjectType:fields:field:args', function addSqlWhereClause(args, build, context) {
75
- var sql = build.pgSql,
76
- inflection = build.inflection;
77
- var _context$scope2 = context.scope,
78
- isPgFieldConnection = _context$scope2.isPgFieldConnection,
79
- isPgFieldSimpleCollection = _context$scope2.isPgFieldSimpleCollection,
80
- procOrTable = _context$scope2.pgFieldIntrospection,
81
- tableIfProc = _context$scope2.pgFieldIntrospectionTable,
82
- addArgDataGenerator = context.addArgDataGenerator;
83
- var table = tableIfProc || procOrTable;
84
-
85
- if (!isPgFieldConnection && !isPgFieldSimpleCollection || !table || table.kind !== 'class') {
86
- return args;
87
- }
88
-
89
- var tsvs = table.attributes.filter(function (attr) {
90
- return attr.type.name === 'tsvector';
91
- });
92
- if (!tsvs.length) return args;
93
-
94
- var _iterator = _createForOfIteratorHelper(tsvs),
95
- _step;
96
-
97
- try {
98
- var _loop = function _loop() {
99
- var tsv = _step.value;
100
- var conditionFieldName = inflection.camelCase(pgSearchPrefix + '_' + tsv.name);
101
-
102
- var conditionGenerator = function conditionGenerator(value, _ref2) {
103
- var queryBuilder = _ref2.queryBuilder,
104
- sql = _ref2.sql,
105
- sqlTableAlias = _ref2.sqlTableAlias;
106
-
107
- if (value == null) {
108
- return;
109
- }
110
-
111
- var tsquery = sql.fragment(_templateObject(), sql.value(value));
112
- queryBuilder.orderBy(sql.fragment(_templateObject2(), sqlTableAlias, sql.identifier(tsv.name), tsquery), false, false);
113
- return sql.fragment(_templateObject3(), sqlTableAlias, sql.identifier(tsv.name), tsquery);
114
- };
115
-
116
- addArgDataGenerator(function conditionSQLBuilder(_ref3) {
117
- var condition = _ref3.condition;
118
-
119
- if (!condition || !(conditionFieldName in condition)) {
120
- return {};
121
- }
122
-
123
- var conditionValue = condition[conditionFieldName];
124
- return {
125
- pgQuery: function pgQuery(queryBuilder) {
126
- var sqlCondition = conditionGenerator(conditionValue, {
127
- queryBuilder: queryBuilder,
128
- sql: sql,
129
- sqlTableAlias: queryBuilder.getTableAlias()
130
- }, build);
131
-
132
- if (sqlCondition) {
133
- queryBuilder.where(sqlCondition);
134
- }
135
- }
136
- };
137
- });
138
- };
139
-
140
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
141
- _loop();
142
- }
143
- } catch (err) {
144
- _iterator.e(err);
145
- } finally {
146
- _iterator.f();
147
- }
148
-
149
- return args;
150
- }, [], // Make sure we're loaded before PgConnectionArgOrderBy, otherwise
151
- // ordering added by conditions will be overridden by the default
152
- // ordering.
153
- ['PgConnectionArgOrderBy'], []);
154
- };
155
-
156
- exports.PgSearchPlugin = PgSearchPlugin;
157
- var _default = PgSearchPlugin;
158
- exports["default"] = _default;
package/module/index.js DELETED
@@ -1,102 +0,0 @@
1
- export const PgSearchPlugin = (builder, {
2
- pgSearchPrefix = 'tsv'
3
- }) => {
4
- builder.hook('GraphQLInputObjectType:fields', function addConditionInputField(fields, build, context) {
5
- const {
6
- inflection
7
- } = build;
8
- const {
9
- scope: {
10
- isPgCondition,
11
- pgIntrospection: table
12
- },
13
- fieldWithHooks
14
- } = context;
15
-
16
- if (!isPgCondition || !table || table.kind !== 'class') {
17
- return fields;
18
- }
19
-
20
- const tsvs = table.attributes.filter(attr => attr.type.name === 'tsvector');
21
- if (!tsvs.length) return fields;
22
- return build.extend(fields, tsvs.reduce((m, v) => {
23
- const key = inflection.camelCase(`${pgSearchPrefix}_${v.name}`);
24
- m[key] = fieldWithHooks(key, {
25
- type: build.graphql.GraphQLString
26
- }, {});
27
- return m;
28
- }, {}));
29
- });
30
- builder.hook('GraphQLObjectType:fields:field:args', function addSqlWhereClause(args, build, context) {
31
- const {
32
- pgSql: sql,
33
- inflection
34
- } = build;
35
- const {
36
- scope: {
37
- isPgFieldConnection,
38
- isPgFieldSimpleCollection,
39
- pgFieldIntrospection: procOrTable,
40
- pgFieldIntrospectionTable: tableIfProc
41
- },
42
- addArgDataGenerator
43
- } = context;
44
- const table = tableIfProc || procOrTable;
45
-
46
- if (!isPgFieldConnection && !isPgFieldSimpleCollection || !table || table.kind !== 'class') {
47
- return args;
48
- }
49
-
50
- const tsvs = table.attributes.filter(attr => attr.type.name === 'tsvector');
51
- if (!tsvs.length) return args;
52
-
53
- for (const tsv of tsvs) {
54
- const conditionFieldName = inflection.camelCase(pgSearchPrefix + '_' + tsv.name);
55
-
56
- const conditionGenerator = (value, {
57
- queryBuilder,
58
- sql,
59
- sqlTableAlias
60
- }) => {
61
- if (value == null) {
62
- return;
63
- }
64
-
65
- const tsquery = sql.fragment`websearch_to_tsquery('english', ${sql.value(value)})`;
66
- queryBuilder.orderBy(sql.fragment`ts_rank ( ${sqlTableAlias}.${sql.identifier(tsv.name)}, ${tsquery} )`, false, false);
67
- return sql.fragment`${sqlTableAlias}.${sql.identifier(tsv.name)} @@ ${tsquery}`;
68
- };
69
-
70
- addArgDataGenerator(function conditionSQLBuilder({
71
- condition
72
- }) {
73
- if (!condition || !(conditionFieldName in condition)) {
74
- return {};
75
- }
76
-
77
- const {
78
- [conditionFieldName]: conditionValue
79
- } = condition;
80
- return {
81
- pgQuery: queryBuilder => {
82
- const sqlCondition = conditionGenerator(conditionValue, {
83
- queryBuilder,
84
- sql,
85
- sqlTableAlias: queryBuilder.getTableAlias()
86
- }, build);
87
-
88
- if (sqlCondition) {
89
- queryBuilder.where(sqlCondition);
90
- }
91
- }
92
- };
93
- });
94
- }
95
-
96
- return args;
97
- }, [], // Make sure we're loaded before PgConnectionArgOrderBy, otherwise
98
- // ordering added by conditions will be overridden by the default
99
- // ordering.
100
- ['PgConnectionArgOrderBy'], []);
101
- };
102
- export default PgSearchPlugin;