@juit/pgproxy-model 0.0.0

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 ADDED
@@ -0,0 +1,12 @@
1
+ # PostgreSQL Proxy Persister Model Types
2
+
3
+ This package exports _only the types_ required by the [PGProxy Persister
4
+ interface](https://github.com/juitnow/juit-pgproxy/blob/main/workspaces/persister/README.md).
5
+
6
+ This simplifies type management allowing **consumers** of libraries and APIs
7
+ using Persister to ship this (and their inferred types) as a simple dependency
8
+ without bringing in any extra code.
9
+
10
+ * [PGProxy](https://github.com/juitnow/juit-pgproxy/blob/main/README.md)
11
+ * [Copyright Notice](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
12
+ * [License](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
package/dist/index.cjs ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // index.ts
17
+ var index_exports = {};
18
+ module.exports = __toCommonJS(index_exports);
19
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
5
+ "names": []
6
+ }
@@ -0,0 +1,2 @@
1
+ export type * from './model';
2
+ export type * from './search';
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "mappings": "",
5
+ "names": []
6
+ }
package/dist/model.cjs ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // model.ts
17
+ var model_exports = {};
18
+ module.exports = __toCommonJS(model_exports);
19
+ //# sourceMappingURL=model.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/model.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
5
+ "names": []
6
+ }
@@ -0,0 +1,34 @@
1
+ import type { OnlyStrings, Prettify } from './utils';
2
+ /** The definition of a column */
3
+ export interface ColumnDefinition<T = any> {
4
+ /** The TypeScript type of the column (from the type parser) */
5
+ type: T;
6
+ /** Whether the column is _generated_ or not */
7
+ isGenerated?: boolean;
8
+ /** Whether the column is _nullable_ or not */
9
+ isNullable?: boolean;
10
+ /** Whether the column _specifies a default value_ or not */
11
+ hasDefault?: boolean;
12
+ }
13
+ /** Infer the TypeScript type suitable for an `INSERT` in a table */
14
+ export type InferInsertType<Table extends Record<string, ColumnDefinition>> = Prettify<{
15
+ [Column in keyof Table as Column extends string ? Table[Column]['isGenerated'] extends true ? never : Table[Column]['isNullable'] extends true ? Column : Table[Column]['hasDefault'] extends true ? Column : never : never]?: Table[Column]['isNullable'] extends true ? Table[Column]['type'] | null : Table[Column]['type'];
16
+ } & {
17
+ [Column in keyof Table as Column extends string ? Table[Column]['isGenerated'] extends true ? never : Table[Column]['isNullable'] extends true ? never : Table[Column]['hasDefault'] extends true ? never : Column : never]-?: Table[Column]['isNullable'] extends true ? Table[Column]['type'] | null : Table[Column]['type'];
18
+ }>;
19
+ /** Infer the TypeScript type suitable for a `SELECT` from a table */
20
+ export type InferSelectType<Table extends Record<string, ColumnDefinition>> = {
21
+ [Column in keyof Table as Column extends string ? Column : never]-?: (Table[Column]['isNullable'] extends true ? Table[Column]['type'] | null : Table[Column]['type']) & (Table[Column] extends {
22
+ branding: infer Brand;
23
+ } ? Brand : unknown);
24
+ };
25
+ /** Infer the TypeScript type suitable for a `UPDATE` in a table */
26
+ export type InferUpdateType<Table extends Record<string, ColumnDefinition>> = {
27
+ [Column in keyof Table as Column extends string ? Table[Column]['isGenerated'] extends true ? never : Column : never]?: Table[Column]['isNullable'] extends true ? Table[Column]['type'] | null : Table[Column]['type'];
28
+ };
29
+ /** Infer the TypeScript type used for querying records */
30
+ export type InferQueryType<Table extends Record<string, ColumnDefinition>> = {
31
+ [Column in keyof Table as Column extends string ? Column : never]?: Table[Column]['isNullable'] extends true ? Table[Column]['type'] | null : Table[Column]['type'];
32
+ };
33
+ /** Infer the available sort values for a table (as required by `ORDER BY`) */
34
+ export type InferSort<Table extends Record<string, ColumnDefinition>> = `${OnlyStrings<keyof Table>}${' ASC' | ' asc' | ' DESC' | ' desc' | ''}`;
package/dist/model.mjs ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=model.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "mappings": "",
5
+ "names": []
6
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // search.ts
17
+ var search_exports = {};
18
+ module.exports = __toCommonJS(search_exports);
19
+ //# sourceMappingURL=search.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/search.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
5
+ "names": []
6
+ }
@@ -0,0 +1,131 @@
1
+ import type { ColumnDefinition, InferSelectType } from './model';
2
+ import type { Prettify } from './utils';
3
+ /** Simple type to extract joins with a specified sortcolumn */
4
+ type SortableJoins<Joins> = keyof {
5
+ [key in keyof Joins as Joins[key] extends {
6
+ sortColumn: string;
7
+ } ? key : never]: undefined;
8
+ };
9
+ /**
10
+ * Definition for a simple (straight) join in a {@link Search}
11
+ */
12
+ export interface SearchJoin<Schema> {
13
+ /**
14
+ * The column in _the search table_ (passed to the constructor of
15
+ * {@link Search}) referencing the specified `refTable` (defined here).
16
+ *
17
+ * ```sql
18
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
19
+ * ^^^^^^
20
+ * ```
21
+ */
22
+ column: string;
23
+ /**
24
+ * The name of the table to _left join_.
25
+ *
26
+ * ```sql
27
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
28
+ * ^^^^^^^^ ^^^^^^^^
29
+ * ```
30
+ */
31
+ refTable: string & keyof Schema;
32
+ /**
33
+ * The column in the `refTable` referenced by the _the search table_.
34
+ *
35
+ * ```sql
36
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
37
+ * ^^^^^^^^^
38
+ * ```
39
+ */
40
+ refColumn: string;
41
+ /**
42
+ * The column in the referenced table to use as default sort column, when
43
+ * sorting by this join.
44
+ */
45
+ sortColumn?: string;
46
+ }
47
+ /**
48
+ * Definition for joins in a {@link Search}
49
+ *
50
+ * Each key is the name of the join as it will appear in the results, and the
51
+ * value defines how to perform the join.
52
+ *
53
+ * See {@link StraightJoin} and {@link LinkedJoin} for details on the fields.
54
+ */
55
+ export interface SearchJoins<Schema> {
56
+ [key: string]: SearchJoin<Schema>;
57
+ }
58
+ /** Internal interface defining operators available to *single values* */
59
+ interface ValueSearchFilter<Schema, Table extends string & keyof Schema> {
60
+ name: string & keyof Schema[Table];
61
+ field?: string;
62
+ op?: '=' | '!=' | '>' | '>=' | '<' | '<=' | '~' | 'like' | 'ilike';
63
+ value: string | number | Date | boolean | null;
64
+ }
65
+ /** Internal interface defining operators available to *array values* */
66
+ interface ArraySearchFilter<Schema, Table extends string & keyof Schema> {
67
+ name: string & keyof Schema[Table];
68
+ field?: string;
69
+ op: 'in' | 'not in';
70
+ value: (string | number | Date | boolean | null)[];
71
+ }
72
+ /** Internal interface defining operators available to *json values* */
73
+ interface JsonSearchFilter<Schema, Table extends string & keyof Schema> {
74
+ name: string & keyof Schema[Table];
75
+ field?: never;
76
+ op: '@>' | '<@';
77
+ value: any;
78
+ }
79
+ /**
80
+ * A filter for a search that matches a single value
81
+ *
82
+ * - `name` is the column name to filter on
83
+ * - `field` is a field to filter on when the column is a complex type (JSONB)
84
+ * - `op` is the operator to use for the filter (default: `=`)
85
+ * - `value` is the value to filter for
86
+ *
87
+ * All operators are defined as per PostgreSQL documentation, with few notable
88
+ * exceptions:
89
+ *
90
+ * - `~` is an alias to the `ilike` operator
91
+ * - `in` and `not in` are used to match a value against an array of possible
92
+ * values using the `... = ANY(...)` or `... != ALL(...)` constructs
93
+ * - `@>` and `<@` will accept single values as well as arrays.
94
+ * - `!=` and `=` will use the PostgreSQL `IS (NOT) DISTINCT FROM` semantics
95
+ * to properly handle `NULL` comparisons.
96
+ */
97
+ export type SearchFilter<Schema, Table extends string & keyof Schema> = Prettify<ValueSearchFilter<Schema, Table>> | Prettify<ArraySearchFilter<Schema, Table>> | Prettify<JsonSearchFilter<Schema, Table>>;
98
+ /**
99
+ * Base interface for querying results via our {@link Search}.
100
+ */
101
+ export type SearchQuery<Schema, Table extends string & keyof Schema, Joins extends SearchJoins<Schema>> = Prettify<{
102
+ /** An optional set of filters to apply */
103
+ filters?: Prettify<SearchFilter<Schema, Table>[]>;
104
+ /** An optional column to sort by */
105
+ sort?: string & (keyof Schema[Table] | SortableJoins<Joins>);
106
+ /** The order to sort by (if `sort` is specified, default: 'asc') */
107
+ order?: 'asc' | 'desc';
108
+ /** An optional full-text search query, available for full-text search */
109
+ q?: string;
110
+ }>;
111
+ /**
112
+ * Full options for querying a limited set of results via our {@link Search}.
113
+ */
114
+ export type SearchOptions<Schema, Table extends string & keyof Schema, Joins extends SearchJoins<Schema>> = Prettify<SearchQuery<Schema, Table, Joins> & {
115
+ /** Offset to start returning rows from (default: 0) */
116
+ offset?: number;
117
+ /** Maximum number of rows to return (default: 20, unlimited if 0) */
118
+ limit?: number;
119
+ }>;
120
+ /** A single search result row (with joins) */
121
+ export type SearchResult<Schema, Table extends string & keyof Schema, Joins extends SearchJoins<Schema> = {}> = Prettify<Schema[Table] extends Record<string, ColumnDefinition> ? InferSelectType<Schema[Table]> & {
122
+ [key in keyof Joins]: Joins[key]['refTable'] extends keyof Schema ? Schema[Joins[key]['refTable']] extends Record<string, ColumnDefinition> ? Schema[Table][Joins[key]['column']]['isNullable'] extends true ? Prettify<InferSelectType<Schema[Joins[key]['refTable']]>> | null : Prettify<InferSelectType<Schema[Joins[key]['refTable']]>> : unknown : unknown;
123
+ } : never>;
124
+ /** What's being returned by our `search` */
125
+ export interface SearchResults<Schema, Table extends string & keyof Schema, Joins extends SearchJoins<Schema> = {}> {
126
+ /** The total length of all available results (without offset or limit) */
127
+ total: number;
128
+ /** The lines queried (truncated by offset and limit) */
129
+ rows: SearchResult<Schema, Table, Joins>[];
130
+ }
131
+ export {};
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=search.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "mappings": "",
5
+ "names": []
6
+ }
package/dist/utils.cjs ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // utils.ts
17
+ var utils_exports = {};
18
+ module.exports = __toCommonJS(utils_exports);
19
+ //# sourceMappingURL=utils.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/utils.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
5
+ "names": []
6
+ }
@@ -0,0 +1,6 @@
1
+ /** Prettify a type by flattening intersections */
2
+ export type Prettify<T extends object> = {
3
+ [K in keyof T]: T[K];
4
+ } & {};
5
+ /** Extract only the string keys from a type */
6
+ export type OnlyStrings<T> = T extends string ? T : never;
package/dist/utils.mjs ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "mappings": "",
5
+ "names": []
6
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@juit/pgproxy-model",
3
+ "version": "0.0.0",
4
+ "main": "./dist/index.cjs",
5
+ "module": "./dist/index.mjs",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.cjs"
12
+ },
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.mjs"
16
+ }
17
+ }
18
+ },
19
+ "scripts": {},
20
+ "author": "Juit Developers <developers@juit.com>",
21
+ "license": "Apache-2.0",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+ssh://git@github.com/juitnow/juit-pgproxy.git"
25
+ },
26
+ "keywords": [
27
+ "database",
28
+ "pg",
29
+ "pool",
30
+ "postgres",
31
+ "proxy"
32
+ ],
33
+ "bugs": {
34
+ "url": "https://github.com/juitnow/juit-pgproxy/issues"
35
+ },
36
+ "homepage": "https://github.com/juitnow/juit-pgproxy#readme",
37
+ "directories": {
38
+ "test": "test"
39
+ },
40
+ "files": [
41
+ "*.md",
42
+ "dist/",
43
+ "src/"
44
+ ]
45
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type * from './model'
2
+ export type * from './search'
package/src/model.ts ADDED
@@ -0,0 +1,77 @@
1
+ import type { OnlyStrings, Prettify } from './utils'
2
+
3
+ /* ========================================================================== *
4
+ * TYPE INFERENCE: FROM SCHEMA->TABLE->COLUMN->... TO JS TYPES *
5
+ * ========================================================================== */
6
+
7
+ /** The definition of a column */
8
+ export interface ColumnDefinition<T = any> {
9
+ /** The TypeScript type of the column (from the type parser) */
10
+ type: T,
11
+ /** Whether the column is _generated_ or not */
12
+ isGenerated?: boolean,
13
+ /** Whether the column is _nullable_ or not */
14
+ isNullable?: boolean,
15
+ /** Whether the column _specifies a default value_ or not */
16
+ hasDefault?: boolean,
17
+ }
18
+
19
+ /** Infer the TypeScript type suitable for an `INSERT` in a table */
20
+ export type InferInsertType<Table extends Record<string, ColumnDefinition>> = Prettify<{
21
+ /* First part: all nullable or defaulted columns are optional */
22
+ [ Column in keyof Table as Column extends string
23
+ ? Table[Column]['isGenerated'] extends true ? never
24
+ : Table[Column]['isNullable'] extends true ? Column
25
+ : Table[Column]['hasDefault'] extends true ? Column
26
+ : never
27
+ : never
28
+ ] ? :
29
+ Table[Column]['isNullable'] extends true
30
+ ? Table[Column]['type'] | null
31
+ : Table[Column]['type']
32
+ } & {
33
+ /* Second part: all non-nullable or non-defaulted columns are required */
34
+ [ Column in keyof Table as Column extends string
35
+ ? Table[Column]['isGenerated'] extends true ? never
36
+ : Table[Column]['isNullable'] extends true ? never
37
+ : Table[Column]['hasDefault'] extends true ? never
38
+ : Column
39
+ : never
40
+ ] -? :
41
+ Table[Column]['isNullable'] extends true
42
+ ? Table[Column]['type'] | null
43
+ : Table[Column]['type']
44
+ }>
45
+
46
+ /** Infer the TypeScript type suitable for a `SELECT` from a table */
47
+ export type InferSelectType<Table extends Record<string, ColumnDefinition>> = {
48
+ [ Column in keyof Table as Column extends string ? Column : never ] -? :
49
+ ( Table[Column]['isNullable'] extends true
50
+ ? Table[Column]['type'] | null
51
+ : Table[Column]['type']
52
+ ) & ( Table[Column] extends { branding: infer Brand } ? Brand : unknown )
53
+ }
54
+
55
+ /** Infer the TypeScript type suitable for a `UPDATE` in a table */
56
+ export type InferUpdateType<Table extends Record<string, ColumnDefinition>> = {
57
+ [ Column in keyof Table as Column extends string
58
+ ? Table[Column]['isGenerated'] extends true ? never
59
+ : Column
60
+ : never
61
+ ] ? :
62
+ Table[Column]['isNullable'] extends true
63
+ ? Table[Column]['type'] | null
64
+ : Table[Column]['type']
65
+ }
66
+
67
+ /** Infer the TypeScript type used for querying records */
68
+ export type InferQueryType<Table extends Record<string, ColumnDefinition>> ={
69
+ [ Column in keyof Table as Column extends string ? Column : never ] ? :
70
+ Table[Column]['isNullable'] extends true
71
+ ? Table[Column]['type'] | null
72
+ : Table[Column]['type']
73
+ }
74
+
75
+ /** Infer the available sort values for a table (as required by `ORDER BY`) */
76
+ export type InferSort<Table extends Record<string, ColumnDefinition>> =
77
+ `${OnlyStrings<keyof Table>}${' ASC' | ' asc' | ' DESC' | ' desc' | ''}`
package/src/search.ts ADDED
@@ -0,0 +1,194 @@
1
+ import type { ColumnDefinition, InferSelectType } from './model'
2
+ import type { Prettify } from './utils'
3
+
4
+ /** Simple type to extract joins with a specified sortcolumn */
5
+ type SortableJoins<Joins> = keyof {
6
+ [ key in keyof Joins as Joins[key] extends { sortColumn: string } ? key : never ] : undefined
7
+ }
8
+
9
+ /* ========================================================================== *
10
+ * JOINS *
11
+ * ========================================================================== */
12
+
13
+ /**
14
+ * Definition for a simple (straight) join in a {@link Search}
15
+ */
16
+ export interface SearchJoin<Schema> {
17
+ /**
18
+ * The column in _the search table_ (passed to the constructor of
19
+ * {@link Search}) referencing the specified `refTable` (defined here).
20
+ *
21
+ * ```sql
22
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
23
+ * ^^^^^^
24
+ * ```
25
+ */
26
+ column: string
27
+ /**
28
+ * The name of the table to _left join_.
29
+ *
30
+ * ```sql
31
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
32
+ * ^^^^^^^^ ^^^^^^^^
33
+ * ```
34
+ */
35
+ refTable: string & keyof Schema
36
+ /**
37
+ * The column in the `refTable` referenced by the _the search table_.
38
+ *
39
+ * ```sql
40
+ * ... LEFT JOIN "refTable" ON "table"."column" = "refTable"."refColumn"
41
+ * ^^^^^^^^^
42
+ * ```
43
+ */
44
+ refColumn: string
45
+ /**
46
+ * The column in the referenced table to use as default sort column, when
47
+ * sorting by this join.
48
+ */
49
+ sortColumn?: string
50
+ }
51
+
52
+ /**
53
+ * Definition for joins in a {@link Search}
54
+ *
55
+ * Each key is the name of the join as it will appear in the results, and the
56
+ * value defines how to perform the join.
57
+ *
58
+ * See {@link StraightJoin} and {@link LinkedJoin} for details on the fields.
59
+ */
60
+ export interface SearchJoins<Schema> {
61
+ [ key: string ]: SearchJoin<Schema>
62
+ }
63
+
64
+ /* ========================================================================== *
65
+ * SEARCH OPTIONS *
66
+ * ========================================================================== */
67
+
68
+ /** Internal interface defining operators available to *single values* */
69
+ interface ValueSearchFilter<
70
+ Schema,
71
+ Table extends string & keyof Schema,
72
+ > {
73
+ name: string & keyof Schema[Table]
74
+ field?: string
75
+ op?: '=' | '!=' | '>' | '>=' | '<' | '<=' | '~' | 'like' | 'ilike'
76
+ value: string | number | Date | boolean | null
77
+ }
78
+
79
+ /** Internal interface defining operators available to *array values* */
80
+ interface ArraySearchFilter<
81
+ Schema,
82
+ Table extends string & keyof Schema,
83
+ > {
84
+ name: string & keyof Schema[Table]
85
+ field?: string
86
+ op: 'in' | 'not in'
87
+ value: (string | number | Date | boolean | null)[]
88
+ }
89
+
90
+ /** Internal interface defining operators available to *json values* */
91
+ interface JsonSearchFilter<
92
+ Schema,
93
+ Table extends string & keyof Schema,
94
+ > {
95
+ name: string & keyof Schema[Table]
96
+ field?: never
97
+ op: '@>' | '<@'
98
+ value: any
99
+ }
100
+
101
+ /**
102
+ * A filter for a search that matches a single value
103
+ *
104
+ * - `name` is the column name to filter on
105
+ * - `field` is a field to filter on when the column is a complex type (JSONB)
106
+ * - `op` is the operator to use for the filter (default: `=`)
107
+ * - `value` is the value to filter for
108
+ *
109
+ * All operators are defined as per PostgreSQL documentation, with few notable
110
+ * exceptions:
111
+ *
112
+ * - `~` is an alias to the `ilike` operator
113
+ * - `in` and `not in` are used to match a value against an array of possible
114
+ * values using the `... = ANY(...)` or `... != ALL(...)` constructs
115
+ * - `@>` and `<@` will accept single values as well as arrays.
116
+ * - `!=` and `=` will use the PostgreSQL `IS (NOT) DISTINCT FROM` semantics
117
+ * to properly handle `NULL` comparisons.
118
+ */
119
+ export type SearchFilter<
120
+ Schema,
121
+ Table extends string & keyof Schema,
122
+ > = Prettify<ValueSearchFilter<Schema, Table>>
123
+ | Prettify<ArraySearchFilter<Schema, Table>>
124
+ | Prettify<JsonSearchFilter<Schema, Table>>
125
+
126
+ /**
127
+ * Base interface for querying results via our {@link Search}.
128
+ */
129
+ export type SearchQuery<
130
+ Schema,
131
+ Table extends string & keyof Schema,
132
+ Joins extends SearchJoins<Schema>,
133
+ > = Prettify<{
134
+ /** An optional set of filters to apply */
135
+ filters?: Prettify<SearchFilter<Schema, Table>[]>
136
+ /** An optional column to sort by */
137
+ sort?: string & (keyof Schema[Table] | SortableJoins<Joins>)
138
+ /** The order to sort by (if `sort` is specified, default: 'asc') */
139
+ order?: 'asc' | 'desc'
140
+ /** An optional full-text search query, available for full-text search */
141
+ q?: string
142
+ }>
143
+
144
+ /**
145
+ * Full options for querying a limited set of results via our {@link Search}.
146
+ */
147
+ export type SearchOptions<
148
+ Schema,
149
+ Table extends string & keyof Schema,
150
+ Joins extends SearchJoins<Schema>,
151
+ > = Prettify<SearchQuery<Schema, Table, Joins> & {
152
+ /** Offset to start returning rows from (default: 0) */
153
+ offset?: number
154
+ /** Maximum number of rows to return (default: 20, unlimited if 0) */
155
+ limit?: number
156
+ }>
157
+
158
+ /* ========================================================================== *
159
+ * SEARCH RESULTS *
160
+ * ========================================================================== */
161
+
162
+ /** A single search result row (with joins) */
163
+ export type SearchResult<
164
+ Schema,
165
+ Table extends string & keyof Schema,
166
+ Joins extends SearchJoins<Schema> = {},
167
+ > = Prettify<
168
+ Schema[Table] extends Record<string, ColumnDefinition> ?
169
+ // This is the main table's column field
170
+ InferSelectType<Schema[Table]> & {
171
+ // For each join, add a field with the joined table's inferred type
172
+ [ key in keyof Joins ] : Joins[key]['refTable'] extends keyof Schema ?
173
+ // If the column referencing this join is nullable, the result can be null
174
+ Schema[Joins[key]['refTable']] extends Record<string, ColumnDefinition> ?
175
+ Schema[Table][Joins[key]['column']]['isNullable'] extends true ?
176
+ Prettify<InferSelectType<Schema[Joins[key]['refTable']]>> | null :
177
+ Prettify<InferSelectType<Schema[Joins[key]['refTable']]>> :
178
+ // If the joined table isn't a column def, we can't infer anything
179
+ unknown :
180
+ // If the table doesn't exist in the schema, we can't infer anything
181
+ unknown
182
+ } : never>
183
+
184
+ /** What's being returned by our `search` */
185
+ export interface SearchResults<
186
+ Schema,
187
+ Table extends string & keyof Schema,
188
+ Joins extends SearchJoins<Schema> = {},
189
+ > {
190
+ /** The total length of all available results (without offset or limit) */
191
+ total: number
192
+ /** The lines queried (truncated by offset and limit) */
193
+ rows: SearchResult<Schema, Table, Joins>[]
194
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** Prettify a type by flattening intersections */
2
+ export type Prettify<T extends object> = { [ K in keyof T ]: T[K] } & {}
3
+ /** Extract only the string keys from a type */
4
+ export type OnlyStrings<T> = T extends string ? T : never