From 0a59ce20de317d6fe31350a64dc36b9acf645671 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Thu, 13 May 2021 00:06:11 +0800 Subject: [PATCH 01/17] Add TypeScriptTypes --- src/lib/TypeScriptTypes.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/lib/TypeScriptTypes.ts diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts new file mode 100644 index 00000000..882e2063 --- /dev/null +++ b/src/lib/TypeScriptTypes.ts @@ -0,0 +1,32 @@ +import { PostgresMeta } from "." + +export default class TypeScriptTypes { + pgMeta: PostgresMeta + + constructor() { + this.pgMeta = new PostgresMeta({ + connectionString: "postgres://postgres:postgres@localhost:5432/postgres", + max: 1 + }) + } + + async dump(): Promise { + const { data, error } = await this.pgMeta.columns.list(); + // TODO: handle error + + if (data) { + return data.reduce((prev, current) => { + if (current.table in prev) { + prev[current.table].push(current) + } else { + prev[current.table] = [] + } + + return prev + }, {} as { [key: string]: Array }) + } + } +} + + +new TypeScriptTypes().dump().then(console.log) From 5146c0bdb6a467a18f33c8ca58e05fabea3d0e9a Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Tue, 18 May 2021 23:47:29 +0800 Subject: [PATCH 02/17] build: Add sinon --- package-lock.json | 106 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 107 insertions(+) diff --git a/package-lock.json b/package-lock.json index cc77b956..11046586 100644 --- a/package-lock.json +++ b/package-lock.json @@ -103,6 +103,37 @@ "fastq": "^1.6.0" } }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2303,6 +2334,11 @@ "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", "dev": true }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2385,6 +2421,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", @@ -2813,6 +2854,18 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", + "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -3159,6 +3212,21 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -4012,6 +4080,39 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "sinon": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-10.0.0.tgz", + "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", + "requires": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/samsam": "^5.3.1", + "diff": "^4.0.2", + "nise": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4768,6 +4869,11 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", diff --git a/package.json b/package.json index f825a2ae..3f919989 100755 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "pkg": "^4.4.8", "prettier": "^2.0.5", "rimraf": "^3.0.2", + "sinon": "^10.0.0", "ts-node-dev": "^1.1.6", "typescript": "^3.9.3" } From 7f2b2af54a7460c6b4734afdee9dbf98004ea662 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Wed, 19 May 2021 22:06:56 +0800 Subject: [PATCH 03/17] test: Write first test --- src/lib/TypeScriptTypes.ts | 10 +--- test/lib/TypeScriptTypes.spec.js | 81 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 test/lib/TypeScriptTypes.spec.js diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index 882e2063..fc4f8c73 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -3,11 +3,8 @@ import { PostgresMeta } from "." export default class TypeScriptTypes { pgMeta: PostgresMeta - constructor() { - this.pgMeta = new PostgresMeta({ - connectionString: "postgres://postgres:postgres@localhost:5432/postgres", - max: 1 - }) + constructor({ pgMeta }: { pgMeta: PostgresMeta }) { + this.pgMeta = pgMeta; } async dump(): Promise { @@ -27,6 +24,3 @@ export default class TypeScriptTypes { } } } - - -new TypeScriptTypes().dump().then(console.log) diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js new file mode 100644 index 00000000..873fe821 --- /dev/null +++ b/test/lib/TypeScriptTypes.spec.js @@ -0,0 +1,81 @@ +var assert = require('assert') +var sinon = require('sinon') + +import TypeScriptTypes from '../../bin/src/lib/TypeScriptTypes' +import { PostgresMeta } from '../../bin/src/lib' + + +describe('dump()', () => { + it('returns a string of TypeScript types', async () => { + const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) + const columnsData = [ + { + table_id: 16402, + schema: 'public', + table: 'todos', + id: '16402.1', + ordinal_position: 1, + name: 'id', + default_value: null, + data_type: 'bigint', + format: 'int8', + is_identity: true, + identity_generation: 'BY DEFAULT', + is_nullable: false, + is_updatable: true, + enums: [], + comment: null + }, + { + table_id: 16402, + schema: 'public', + table: 'todos', + id: '16402.2', + ordinal_position: 2, + name: 'details', + default_value: null, + data_type: 'text', + format: 'text', + is_identity: false, + identity_generation: null, + is_nullable: true, + is_updatable: true, + enums: [], + comment: null + }, + { + table_id: 16402, + schema: 'public', + table: 'todos', + id: '16402.3', + ordinal_position: 3, + name: 'user-id', + default_value: null, + data_type: 'bigint', + format: 'int8', + is_identity: false, + identity_generation: null, + is_nullable: false, + is_updatable: true, + enums: [], + comment: null + }, + ] + sinon + .stub(pgMeta.columns, "list") + .returns(Promise.resolve({ data: columnsData })) + + const example = new TypeScriptTypes({ pgMeta: pgMeta }); + + // TODO: ewww + const expected = `export interface definitions { + todos: { + id: number; + details?: string; + user_id: number; + }; +}` + + assert.equal(await example.dump(), expected) + }) +}) From cd556da1b3ff7feb0c1b5d56b9bc34875ddb9675 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Wed, 19 May 2021 22:53:59 +0800 Subject: [PATCH 04/17] feat: Get first test passing --- src/lib/TypeScriptTypes.ts | 37 +++++++++++++++++++++--------- test/lib/TypeScriptTypes.spec.js | 39 +++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index fc4f8c73..632ea692 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -1,26 +1,41 @@ +import { parse } from "path" import { PostgresMeta } from "." +// TODO: move to it's own class/file later +const parseColumn = (columnData: { name: string, format: string }) => { + let dataType: string = '' + switch (columnData.format) { + case 'int8': + dataType = 'number' + break + } + + return `${columnData.name}: ${dataType};` +} + export default class TypeScriptTypes { pgMeta: PostgresMeta constructor({ pgMeta }: { pgMeta: PostgresMeta }) { - this.pgMeta = pgMeta; + this.pgMeta = pgMeta } async dump(): Promise { - const { data, error } = await this.pgMeta.columns.list(); + const { data, error } = await this.pgMeta.columns.list() // TODO: handle error if (data) { - return data.reduce((prev, current) => { - if (current.table in prev) { - prev[current.table].push(current) - } else { - prev[current.table] = [] - } - - return prev - }, {} as { [key: string]: Array }) + // types = data.reduce((prev, current) => { + // if (current.table in prev) { + // prev[current.table].push(parseColumn(current)) + // } else { + // prev[current.table] = [parseColumn(current)] + // } + + // return prev + // }, {} as { [key: string]: Array }) + + return 'export interface definitions {\n todos: {\n ' + parseColumn(data[0]) + '\n };\n}' } } } diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index 873fe821..4b2d2c73 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -5,7 +5,44 @@ import TypeScriptTypes from '../../bin/src/lib/TypeScriptTypes' import { PostgresMeta } from '../../bin/src/lib' -describe('dump()', () => { +describe('.dump()', () => { + it.only('returns definition for an int8 column', async () => { + const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) + const columnsData = [ + { + table_id: 16402, + schema: 'public', + table: 'todos', + id: '16402.1', + ordinal_position: 1, + name: 'id', + default_value: null, + data_type: 'bigint', + format: 'int8', + is_identity: true, + identity_generation: 'BY DEFAULT', + is_nullable: false, + is_updatable: true, + enums: [], + comment: null + } + ] + sinon + .stub(pgMeta.columns, "list") + .returns(Promise.resolve({ data: columnsData })) + + const example = new TypeScriptTypes({ pgMeta: pgMeta }); + + // TODO: ewww + const expected = `export interface definitions { + todos: { + id: number; + }; +}` + + assert.equal(await example.dump(), expected) + }) + it('returns a string of TypeScript types', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ From 489278435e57303407f3f540e824b2d7804c1de5 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Wed, 19 May 2021 23:06:58 +0800 Subject: [PATCH 05/17] build: Add Prettier Types --- package-lock.json | 36 +++++++++++++++++++++++++++--------- package.json | 8 +++++--- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 11046586..94e9f851 100644 --- a/package-lock.json +++ b/package-lock.json @@ -107,6 +107,7 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, "requires": { "type-detect": "4.0.8" } @@ -115,6 +116,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } @@ -123,6 +125,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, "requires": { "@sinonjs/commons": "^1.6.0", "lodash.get": "^4.4.2", @@ -132,7 +135,8 @@ "@sinonjs/text-encoding": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true }, "@types/color-name": { "version": "1.1.1", @@ -202,6 +206,11 @@ "integrity": "sha512-L8ogeT6vDzT1vxlW3KITTCt+BVXXVkLXfZ/XNm6UqbcJgxf+KPO7yjWx7dQQE8RW07KopL10x2gNMs41+IkMGQ==", "dev": true }, + "@types/prettier": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", + "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==" + }, "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -2337,7 +2346,8 @@ "just-extend": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true }, "kind-of": { "version": "6.0.3", @@ -2424,7 +2434,8 @@ "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true }, "log-symbols": { "version": "3.0.0", @@ -2858,6 +2869,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "dev": true, "requires": { "@sinonjs/commons": "^1.7.0", "@sinonjs/fake-timers": "^6.0.0", @@ -3216,6 +3228,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, "requires": { "isarray": "0.0.1" }, @@ -3223,7 +3236,8 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true } } }, @@ -3627,8 +3641,7 @@ "prettier": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", - "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", - "dev": true + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==" }, "process-nextick-args": { "version": "2.0.1", @@ -4084,6 +4097,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-10.0.0.tgz", "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", + "dev": true, "requires": { "@sinonjs/commons": "^1.8.1", "@sinonjs/fake-timers": "^6.0.1", @@ -4096,17 +4110,20 @@ "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -4872,7 +4889,8 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, "type-fest": { "version": "0.13.1", diff --git a/package.json b/package.json index 3f919989..bc637086 100755 --- a/package.json +++ b/package.json @@ -22,11 +22,14 @@ "start": "ts-node-dev src/server/app.ts | pino-pretty --colorize", "dev": "run-s clean format start", "pkg": "run-s clean format build:server && pkg --out-path bin .pkg.config.json", - "test": "run-s build:server && node -r esm ./node_modules/.bin/mocha 'test/**/*.js' --recursive" + "test": "run-s build:server && node -r esm ./node_modules/.bin/mocha 'test/**/*.js' --recursive", + "unit-test": "run-s build:server && node -r esm ./node_modules/.bin/mocha 'test/lib/*.js' --recursive" }, "dependencies": { + "@types/prettier": "^2.2.3", "pg": "^7.0.0", - "pg-format": "^1.0.4" + "pg-format": "^1.0.4", + "prettier": "^2.0.5" }, "devDependencies": { "@types/crypto-js": "^3.1.47", @@ -43,7 +46,6 @@ "npm-run-all": "^4.1.5", "pino-pretty": "^4.7.1", "pkg": "^4.4.8", - "prettier": "^2.0.5", "rimraf": "^3.0.2", "sinon": "^10.0.0", "ts-node-dev": "^1.1.6", From f2038b3539f94f971c103007a4aa5f23db2f0cd0 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Wed, 19 May 2021 23:07:44 +0800 Subject: [PATCH 06/17] feat: Use prettier instead of manual formatting --- src/lib/TypeScriptTypes.ts | 12 +++++++++++- test/lib/TypeScriptTypes.spec.js | 7 +++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index 632ea692..a8343b9f 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -1,4 +1,7 @@ import { parse } from "path" +import prettier from "prettier" +import parserTypescript from "prettier/parser-typescript" + import { PostgresMeta } from "." // TODO: move to it's own class/file later @@ -35,7 +38,14 @@ export default class TypeScriptTypes { // return prev // }, {} as { [key: string]: Array }) - return 'export interface definitions {\n todos: {\n ' + parseColumn(data[0]) + '\n };\n}' + let output = 'export interface definitions { todos: {' + parseColumn(data[0]) + '}; };' + + // Prettify output + let prettierOptions: prettier.Options = { + parser: "typescript", + plugins: [parserTypescript], + }; + return prettier.format(output, prettierOptions); } } } diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index 4b2d2c73..9bce2281 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -35,10 +35,9 @@ describe('.dump()', () => { // TODO: ewww const expected = `export interface definitions { - todos: { - id: number; - }; -}` + todos: { id: number }; +} +` assert.equal(await example.dump(), expected) }) From f8594b501fb9730bcd602cb1b155c4623758c7e2 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 20:59:09 +0800 Subject: [PATCH 07/17] Handle multiple columns --- src/lib/TypeScriptTypes.ts | 7 +++++-- test/lib/TypeScriptTypes.spec.js | 33 +++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index a8343b9f..ea5d3a32 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -11,9 +11,12 @@ const parseColumn = (columnData: { name: string, format: string }) => { case 'int8': dataType = 'number' break + default: + dataType = 'any' + break } - return `${columnData.name}: ${dataType};` + return `${columnData.name}: ${dataType}` } export default class TypeScriptTypes { @@ -38,7 +41,7 @@ export default class TypeScriptTypes { // return prev // }, {} as { [key: string]: Array }) - let output = 'export interface definitions { todos: {' + parseColumn(data[0]) + '}; };' + let output = 'export interface definitions { todos: {' + data.map(parseColumn).join(';') + '}; };' // Prettify output let prettierOptions: prettier.Options = { diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index 9bce2281..9aa63627 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -33,7 +33,6 @@ describe('.dump()', () => { const example = new TypeScriptTypes({ pgMeta: pgMeta }); - // TODO: ewww const expected = `export interface definitions { todos: { id: number }; } @@ -42,6 +41,38 @@ describe('.dump()', () => { assert.equal(await example.dump(), expected) }) + it.only('returns definitions for multiple columns', async () => { + const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) + const columnsData = [ + { + table: 'todos', + name: 'id', + default_value: null, + format: 'int8', + enums: [], + }, + { + table: 'todos', + name: 'name', + default_value: null, + format: 'text', + enums: [], + } + ] + sinon + .stub(pgMeta.columns, "list") + .returns(Promise.resolve({ data: columnsData })) + + const example = new TypeScriptTypes({ pgMeta: pgMeta }); + + const expected = `export interface definitions { + todos: { id: number; name: any }; +} +` + + assert.equal(await example.dump(), expected) + }) + it('returns a string of TypeScript types', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ From f1dbcfc7abf673daa901fb718c9ebac837364b7e Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 21:11:01 +0800 Subject: [PATCH 08/17] Handle multiple tables --- src/lib/TypeScriptTypes.ts | 30 +++++++++++++++--------- test/lib/TypeScriptTypes.spec.js | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index ea5d3a32..c36ddbd3 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -1,8 +1,10 @@ import { parse } from "path" +import { string } from "pg-format" import prettier from "prettier" import parserTypescript from "prettier/parser-typescript" import { PostgresMeta } from "." +import { PostgresColumn } from "./types" // TODO: move to it's own class/file later const parseColumn = (columnData: { name: string, format: string }) => { @@ -31,17 +33,23 @@ export default class TypeScriptTypes { // TODO: handle error if (data) { - // types = data.reduce((prev, current) => { - // if (current.table in prev) { - // prev[current.table].push(parseColumn(current)) - // } else { - // prev[current.table] = [parseColumn(current)] - // } - - // return prev - // }, {} as { [key: string]: Array }) - - let output = 'export interface definitions { todos: {' + data.map(parseColumn).join(';') + '}; };' + const tableGroupings = data.reduce((prev, current) => { + if (current.table in prev) { + prev[current.table].push(current) + } else { + prev[current.table] = [current] + } + + return prev + }, {} as { [key: string]: PostgresColumn[] }) + + const tableDefString = Object + .entries(tableGroupings) + .map(([table, columns]: [string, PostgresColumn[]]) => { + return `${table}: { ${columns.map(parseColumn).join(';')} };` + }).join('') + + let output = `export interface definitions { ${tableDefString} };` // Prettify output let prettierOptions: prettier.Options = { diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index 9aa63627..adcf4eb8 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -73,6 +73,46 @@ describe('.dump()', () => { assert.equal(await example.dump(), expected) }) + it.only('returns definitions for multiple tables', async () => { + const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) + const columnsData = [ + { + table: 'todos', + name: 'id', + default_value: null, + format: 'int8', + enums: [], + }, + { + table: 'todos', + name: 'name', + default_value: null, + format: 'text', + enums: [], + }, + { + table: 'memes', + name: 'id', + default_value: null, + format: 'int8', + enums: [], + } + ] + sinon + .stub(pgMeta.columns, "list") + .returns(Promise.resolve({ data: columnsData })) + + const example = new TypeScriptTypes({ pgMeta: pgMeta }); + + const expected = `export interface definitions { + todos: { id: number; name: any }; + memes: { id: number }; +} +` + + assert.equal(await example.dump(), expected) + }) + it('returns a string of TypeScript types', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ From a2af95ed5b3bc5899e32b2104ff3aaf89f743e51 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 21:15:27 +0800 Subject: [PATCH 09/17] feat: Handle nullable columns --- src/lib/TypeScriptTypes.ts | 6 ++++-- test/lib/TypeScriptTypes.spec.js | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index c36ddbd3..8ab948ba 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -7,7 +7,7 @@ import { PostgresMeta } from "." import { PostgresColumn } from "./types" // TODO: move to it's own class/file later -const parseColumn = (columnData: { name: string, format: string }) => { +const parseColumn = (columnData: PostgresColumn) => { let dataType: string = '' switch (columnData.format) { case 'int8': @@ -18,7 +18,9 @@ const parseColumn = (columnData: { name: string, format: string }) => { break } - return `${columnData.name}: ${dataType}` + const nullableSuffix = columnData.is_nullable ? '?' : '' + + return `${columnData.name}${nullableSuffix}: ${dataType}` } export default class TypeScriptTypes { diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index adcf4eb8..3e890970 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -113,6 +113,30 @@ describe('.dump()', () => { assert.equal(await example.dump(), expected) }) + it.only('handles nullable columns', async () => { + const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) + const columnsData = [ + { + table: 'todos', + name: 'name', + format: 'text', + is_nullable: true + } + ] + sinon + .stub(pgMeta.columns, "list") + .returns(Promise.resolve({ data: columnsData })) + + const example = new TypeScriptTypes({ pgMeta: pgMeta }); + + const expected = `export interface definitions { + todos: { name?: any }; +} +` + + assert.equal(await example.dump(), expected) + }) + it('returns a string of TypeScript types', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ From e15116605389eca23e399b2e91c3340981420056 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 21:33:01 +0800 Subject: [PATCH 10/17] refactor: Extract parseColumns logic --- src/lib/TypeScriptTypes.ts | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index 8ab948ba..396330b6 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -6,7 +6,24 @@ import parserTypescript from "prettier/parser-typescript" import { PostgresMeta } from "." import { PostgresColumn } from "./types" -// TODO: move to it's own class/file later +const parseColumns = (columns: PostgresColumn[]) => { + const tableGroupings = columns.reduce((prev, current) => { + if (current.table in prev) { + prev[current.table].push(current) + } else { + prev[current.table] = [current] + } + + return prev + }, {} as { [key: string]: PostgresColumn[] }) + + return Object + .entries(tableGroupings) + .map(([table, columns]: [string, PostgresColumn[]]) => { + return `${table}: { ${columns.map(parseColumn).join(';')} };` + }).join('') +} + const parseColumn = (columnData: PostgresColumn) => { let dataType: string = '' switch (columnData.format) { @@ -35,22 +52,7 @@ export default class TypeScriptTypes { // TODO: handle error if (data) { - const tableGroupings = data.reduce((prev, current) => { - if (current.table in prev) { - prev[current.table].push(current) - } else { - prev[current.table] = [current] - } - - return prev - }, {} as { [key: string]: PostgresColumn[] }) - - const tableDefString = Object - .entries(tableGroupings) - .map(([table, columns]: [string, PostgresColumn[]]) => { - return `${table}: { ${columns.map(parseColumn).join(';')} };` - }).join('') - + const tableDefString = parseColumns(data) let output = `export interface definitions { ${tableDefString} };` // Prettify output From 1e673b7e2ace0ab7e8929d29353f252a5a4e06d5 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:12:22 +0800 Subject: [PATCH 11/17] feat: Support more data formats --- src/lib/TypeScriptTypes.ts | 32 ++++ test/lib/TypeScriptTypes.spec.js | 73 +++------ types/supabase.ts | 256 +++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+), 52 deletions(-) create mode 100644 types/supabase.ts diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index 396330b6..d7afaa2a 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -27,9 +27,41 @@ const parseColumns = (columns: PostgresColumn[]) => { const parseColumn = (columnData: PostgresColumn) => { let dataType: string = '' switch (columnData.format) { + // adapted from https://github.com/jawj/zapatos/blob/master/src/generate/pgTypes.ts case 'int8': + case 'int2': + case 'int4': + case 'float4': + case 'float8': + case 'numeric': + case 'money': + case 'oid': dataType = 'number' break + case 'date': + case 'timestamp': + case 'timestamptz': + dataType = 'Date' + break + case 'bpchar': + case 'char': + case 'varchar': + case 'text': + case 'citext': + case 'uuid': + case 'bytea': + case 'inet': + case 'time': + case 'timetz': + case 'interval': + case 'name': + case 'json': + case 'jsonb': + dataType = 'string' + break + case 'bool': + dataType = 'boolean' + break default: dataType = 'any' break diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptTypes.spec.js index 3e890970..db3b5688 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptTypes.spec.js @@ -6,7 +6,7 @@ import { PostgresMeta } from '../../bin/src/lib' describe('.dump()', () => { - it.only('returns definition for an int8 column', async () => { + it('returns definition for an int8 column', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { @@ -41,7 +41,7 @@ describe('.dump()', () => { assert.equal(await example.dump(), expected) }) - it.only('returns definitions for multiple columns', async () => { + it('returns definitions for multiple columns', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { @@ -66,14 +66,14 @@ describe('.dump()', () => { const example = new TypeScriptTypes({ pgMeta: pgMeta }); const expected = `export interface definitions { - todos: { id: number; name: any }; + todos: { id: number; name: string }; } ` assert.equal(await example.dump(), expected) }) - it.only('returns definitions for multiple tables', async () => { + it('returns definitions for multiple tables', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { @@ -105,7 +105,7 @@ describe('.dump()', () => { const example = new TypeScriptTypes({ pgMeta: pgMeta }); const expected = `export interface definitions { - todos: { id: number; name: any }; + todos: { id: number; name: string }; memes: { id: number }; } ` @@ -113,7 +113,7 @@ describe('.dump()', () => { assert.equal(await example.dump(), expected) }) - it.only('handles nullable columns', async () => { + it('handles nullable columns', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { @@ -130,7 +130,7 @@ describe('.dump()', () => { const example = new TypeScriptTypes({ pgMeta: pgMeta }); const expected = `export interface definitions { - todos: { name?: any }; + todos: { name?: string }; } ` @@ -141,56 +141,28 @@ describe('.dump()', () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { - table_id: 16402, - schema: 'public', table: 'todos', - id: '16402.1', - ordinal_position: 1, name: 'id', - default_value: null, - data_type: 'bigint', format: 'int8', - is_identity: true, - identity_generation: 'BY DEFAULT', - is_nullable: false, - is_updatable: true, enums: [], - comment: null }, { - table_id: 16402, - schema: 'public', table: 'todos', - id: '16402.2', - ordinal_position: 2, - name: 'details', - default_value: null, - data_type: 'text', - format: 'text', - is_identity: false, - identity_generation: null, - is_nullable: true, - is_updatable: true, + name: 'done', + format: 'bool', enums: [], - comment: null }, { - table_id: 16402, - schema: 'public', table: 'todos', - id: '16402.3', - ordinal_position: 3, - name: 'user-id', - default_value: null, - data_type: 'bigint', - format: 'int8', - is_identity: false, - identity_generation: null, - is_nullable: false, - is_updatable: true, - enums: [], - comment: null + name: 'done_at', + is_nullable: true, + format: 'date', }, + { + table: 'memes', + name: 'example', + format: 'some-invalid-format', + } ] sinon .stub(pgMeta.columns, "list") @@ -198,14 +170,11 @@ describe('.dump()', () => { const example = new TypeScriptTypes({ pgMeta: pgMeta }); - // TODO: ewww const expected = `export interface definitions { - todos: { - id: number; - details?: string; - user_id: number; - }; -}` + todos: { id: number; done: boolean; done_at?: Date }; + memes: { example: any }; +} +` assert.equal(await example.dump(), expected) }) diff --git a/types/supabase.ts b/types/supabase.ts new file mode 100644 index 00000000..14bf1738 --- /dev/null +++ b/types/supabase.ts @@ -0,0 +1,256 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/": { + get: { + responses: { + /** OK */ + 200: unknown; + }; + }; + }; + "/blog_posts": { + get: { + parameters: { + query: { + id?: parameters["rowFilter.blog_posts.id"]; + /** Filtering Columns */ + select?: parameters["select"]; + /** Ordering */ + order?: parameters["order"]; + /** Limiting and Pagination */ + offset?: parameters["offset"]; + /** Limiting and Pagination */ + limit?: parameters["limit"]; + }; + header: { + /** Limiting and Pagination */ + Range?: parameters["range"]; + /** Limiting and Pagination */ + "Range-Unit"?: parameters["rangeUnit"]; + /** Preference */ + Prefer?: parameters["preferCount"]; + }; + }; + responses: { + /** OK */ + 200: { + schema: definitions["blog_posts"][]; + }; + /** Partial Content */ + 206: unknown; + }; + }; + post: { + parameters: { + body: { + /** blog_posts */ + blog_posts?: definitions["blog_posts"]; + }; + query: { + /** Filtering Columns */ + select?: parameters["select"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** Created */ + 201: unknown; + }; + }; + delete: { + parameters: { + query: { + id?: parameters["rowFilter.blog_posts.id"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** No Content */ + 204: never; + }; + }; + patch: { + parameters: { + query: { + id?: parameters["rowFilter.blog_posts.id"]; + }; + body: { + /** blog_posts */ + blog_posts?: definitions["blog_posts"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** No Content */ + 204: never; + }; + }; + }; + "/inline_comments": { + get: { + parameters: { + query: { + id?: parameters["rowFilter.inline_comments.id"]; + text?: parameters["rowFilter.inline_comments.text"]; + custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; + blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; + /** Filtering Columns */ + select?: parameters["select"]; + /** Ordering */ + order?: parameters["order"]; + /** Limiting and Pagination */ + offset?: parameters["offset"]; + /** Limiting and Pagination */ + limit?: parameters["limit"]; + }; + header: { + /** Limiting and Pagination */ + Range?: parameters["range"]; + /** Limiting and Pagination */ + "Range-Unit"?: parameters["rangeUnit"]; + /** Preference */ + Prefer?: parameters["preferCount"]; + }; + }; + responses: { + /** OK */ + 200: { + schema: definitions["inline_comments"][]; + }; + /** Partial Content */ + 206: unknown; + }; + }; + post: { + parameters: { + body: { + /** inline_comments */ + inline_comments?: definitions["inline_comments"]; + }; + query: { + /** Filtering Columns */ + select?: parameters["select"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** Created */ + 201: unknown; + }; + }; + delete: { + parameters: { + query: { + id?: parameters["rowFilter.inline_comments.id"]; + text?: parameters["rowFilter.inline_comments.text"]; + custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; + blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** No Content */ + 204: never; + }; + }; + patch: { + parameters: { + query: { + id?: parameters["rowFilter.inline_comments.id"]; + text?: parameters["rowFilter.inline_comments.text"]; + custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; + blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; + }; + body: { + /** inline_comments */ + inline_comments?: definitions["inline_comments"]; + }; + header: { + /** Preference */ + Prefer?: parameters["preferReturn"]; + }; + }; + responses: { + /** No Content */ + 204: never; + }; + }; + }; +} + +export interface definitions { + blog_posts: { + /** + * Note: + * This is a Primary Key. + */ + id: number; + }; + inline_comments: { + /** + * Note: + * This is a Primary Key. + */ + id: number; + text?: string; + custom_attributes?: string; + /** + * Note: + * This is a Foreign Key to `blog_posts.id`. + */ + blog_post_id?: number; + }; +} + +export interface parameters { + /** Preference */ + preferParams: "params=single-object"; + /** Preference */ + preferReturn: "return=representation" | "return=minimal" | "return=none"; + /** Preference */ + preferCount: "count=none"; + /** Filtering Columns */ + select: string; + /** On Conflict */ + on_conflict: string; + /** Ordering */ + order: string; + /** Limiting and Pagination */ + range: string; + /** Limiting and Pagination */ + rangeUnit: string; + /** Limiting and Pagination */ + offset: string; + /** Limiting and Pagination */ + limit: string; + /** blog_posts */ + "body.blog_posts": definitions["blog_posts"]; + "rowFilter.blog_posts.id": string; + /** inline_comments */ + "body.inline_comments": definitions["inline_comments"]; + "rowFilter.inline_comments.id": string; + "rowFilter.inline_comments.text": string; + "rowFilter.inline_comments.custom_attributes": string; + "rowFilter.inline_comments.blog_post_id": string; +} + +export interface operations {} From 5184409ac396f2eeb490459645cee9684609b4be Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:14:40 +0800 Subject: [PATCH 12/17] refactor: Extract postgresToTypescriptType --- src/lib/TypeScriptTypes.ts | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index d7afaa2a..b74e340d 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -24,9 +24,15 @@ const parseColumns = (columns: PostgresColumn[]) => { }).join('') } -const parseColumn = (columnData: PostgresColumn) => { - let dataType: string = '' - switch (columnData.format) { +const parseColumn = (column: PostgresColumn) => { + const dataType = postgresToTypescriptType(column.format) + const nullableSuffix = column.is_nullable ? '?' : '' + + return `${column.name}${nullableSuffix}: ${dataType}` +} + +const postgresToTypescriptType = (format: string) => { + switch (format) { // adapted from https://github.com/jawj/zapatos/blob/master/src/generate/pgTypes.ts case 'int8': case 'int2': @@ -36,13 +42,11 @@ const parseColumn = (columnData: PostgresColumn) => { case 'numeric': case 'money': case 'oid': - dataType = 'number' - break + return 'number' case 'date': case 'timestamp': case 'timestamptz': - dataType = 'Date' - break + return 'Date' case 'bpchar': case 'char': case 'varchar': @@ -57,19 +61,12 @@ const parseColumn = (columnData: PostgresColumn) => { case 'name': case 'json': case 'jsonb': - dataType = 'string' - break + return 'string' case 'bool': - dataType = 'boolean' - break + return 'boolean' default: - dataType = 'any' - break + return 'any' } - - const nullableSuffix = columnData.is_nullable ? '?' : '' - - return `${columnData.name}${nullableSuffix}: ${dataType}` } export default class TypeScriptTypes { From c7db84cf2bcd7a56331834b328f4d9bac90b6c0d Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:15:01 +0800 Subject: [PATCH 13/17] refactor: Remove unused imports --- src/lib/TypeScriptTypes.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptTypes.ts index b74e340d..74caee4d 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptTypes.ts @@ -1,5 +1,3 @@ -import { parse } from "path" -import { string } from "pg-format" import prettier from "prettier" import parserTypescript from "prettier/parser-typescript" From a1b9331a568d940efb2ec7a65f50f4861ae0dbf9 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:38:39 +0800 Subject: [PATCH 14/17] refactor: Rename to TypeScriptInterfaces --- .../{TypeScriptTypes.ts => TypeScriptInterfaces.ts} | 2 +- ...iptTypes.spec.js => TypeScriptInterfaces.spec.js} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename src/lib/{TypeScriptTypes.ts => TypeScriptInterfaces.ts} (98%) rename test/lib/{TypeScriptTypes.spec.js => TypeScriptInterfaces.spec.js} (90%) diff --git a/src/lib/TypeScriptTypes.ts b/src/lib/TypeScriptInterfaces.ts similarity index 98% rename from src/lib/TypeScriptTypes.ts rename to src/lib/TypeScriptInterfaces.ts index 74caee4d..a662a1f3 100644 --- a/src/lib/TypeScriptTypes.ts +++ b/src/lib/TypeScriptInterfaces.ts @@ -67,7 +67,7 @@ const postgresToTypescriptType = (format: string) => { } } -export default class TypeScriptTypes { +export default class TypeScriptInterfaces { pgMeta: PostgresMeta constructor({ pgMeta }: { pgMeta: PostgresMeta }) { diff --git a/test/lib/TypeScriptTypes.spec.js b/test/lib/TypeScriptInterfaces.spec.js similarity index 90% rename from test/lib/TypeScriptTypes.spec.js rename to test/lib/TypeScriptInterfaces.spec.js index db3b5688..87d45d6c 100644 --- a/test/lib/TypeScriptTypes.spec.js +++ b/test/lib/TypeScriptInterfaces.spec.js @@ -1,7 +1,7 @@ var assert = require('assert') var sinon = require('sinon') -import TypeScriptTypes from '../../bin/src/lib/TypeScriptTypes' +import TypeScriptInterfaces from '../../bin/src/lib/TypeScriptInterfaces' import { PostgresMeta } from '../../bin/src/lib' @@ -31,7 +31,7 @@ describe('.dump()', () => { .stub(pgMeta.columns, "list") .returns(Promise.resolve({ data: columnsData })) - const example = new TypeScriptTypes({ pgMeta: pgMeta }); + const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); const expected = `export interface definitions { todos: { id: number }; @@ -63,7 +63,7 @@ describe('.dump()', () => { .stub(pgMeta.columns, "list") .returns(Promise.resolve({ data: columnsData })) - const example = new TypeScriptTypes({ pgMeta: pgMeta }); + const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); const expected = `export interface definitions { todos: { id: number; name: string }; @@ -102,7 +102,7 @@ describe('.dump()', () => { .stub(pgMeta.columns, "list") .returns(Promise.resolve({ data: columnsData })) - const example = new TypeScriptTypes({ pgMeta: pgMeta }); + const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); const expected = `export interface definitions { todos: { id: number; name: string }; @@ -127,7 +127,7 @@ describe('.dump()', () => { .stub(pgMeta.columns, "list") .returns(Promise.resolve({ data: columnsData })) - const example = new TypeScriptTypes({ pgMeta: pgMeta }); + const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); const expected = `export interface definitions { todos: { name?: string }; @@ -168,7 +168,7 @@ describe('.dump()', () => { .stub(pgMeta.columns, "list") .returns(Promise.resolve({ data: columnsData })) - const example = new TypeScriptTypes({ pgMeta: pgMeta }); + const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); const expected = `export interface definitions { todos: { id: number; done: boolean; done_at?: Date }; From 0b4bd01e43601876c5b33e4af0955f26431cf60a Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:40:49 +0800 Subject: [PATCH 15/17] test: Clean up tests a little --- test/lib/TypeScriptInterfaces.spec.js | 61 +++------------------------ 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/test/lib/TypeScriptInterfaces.spec.js b/test/lib/TypeScriptInterfaces.spec.js index 87d45d6c..76b4dacf 100644 --- a/test/lib/TypeScriptInterfaces.spec.js +++ b/test/lib/TypeScriptInterfaces.spec.js @@ -6,57 +6,18 @@ import { PostgresMeta } from '../../bin/src/lib' describe('.dump()', () => { - it('returns definition for an int8 column', async () => { - const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) - const columnsData = [ - { - table_id: 16402, - schema: 'public', - table: 'todos', - id: '16402.1', - ordinal_position: 1, - name: 'id', - default_value: null, - data_type: 'bigint', - format: 'int8', - is_identity: true, - identity_generation: 'BY DEFAULT', - is_nullable: false, - is_updatable: true, - enums: [], - comment: null - } - ] - sinon - .stub(pgMeta.columns, "list") - .returns(Promise.resolve({ data: columnsData })) - - const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); - - const expected = `export interface definitions { - todos: { id: number }; -} -` - - assert.equal(await example.dump(), expected) - }) - it('returns definitions for multiple columns', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ { table: 'todos', name: 'id', - default_value: null, - format: 'int8', - enums: [], + format: 'int8' }, { table: 'todos', name: 'name', - default_value: null, - format: 'text', - enums: [], + format: 'text' } ] sinon @@ -79,23 +40,17 @@ describe('.dump()', () => { { table: 'todos', name: 'id', - default_value: null, - format: 'int8', - enums: [], + format: 'int8' }, { table: 'todos', name: 'name', - default_value: null, - format: 'text', - enums: [], + format: 'text' }, { table: 'memes', name: 'id', - default_value: null, - format: 'int8', - enums: [], + format: 'int8' } ] sinon @@ -143,14 +98,12 @@ describe('.dump()', () => { { table: 'todos', name: 'id', - format: 'int8', - enums: [], + format: 'int8' }, { table: 'todos', name: 'done', - format: 'bool', - enums: [], + format: 'bool' }, { table: 'todos', From ec260e8a381bdfd4f0bb6e665d7666a4d6dbfb65 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:43:14 +0800 Subject: [PATCH 16/17] test: Remove more test overlaps --- test/lib/TypeScriptInterfaces.spec.js | 62 --------------------------- 1 file changed, 62 deletions(-) diff --git a/test/lib/TypeScriptInterfaces.spec.js b/test/lib/TypeScriptInterfaces.spec.js index 76b4dacf..5169fdd4 100644 --- a/test/lib/TypeScriptInterfaces.spec.js +++ b/test/lib/TypeScriptInterfaces.spec.js @@ -6,68 +6,6 @@ import { PostgresMeta } from '../../bin/src/lib' describe('.dump()', () => { - it('returns definitions for multiple columns', async () => { - const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) - const columnsData = [ - { - table: 'todos', - name: 'id', - format: 'int8' - }, - { - table: 'todos', - name: 'name', - format: 'text' - } - ] - sinon - .stub(pgMeta.columns, "list") - .returns(Promise.resolve({ data: columnsData })) - - const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); - - const expected = `export interface definitions { - todos: { id: number; name: string }; -} -` - - assert.equal(await example.dump(), expected) - }) - - it('returns definitions for multiple tables', async () => { - const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) - const columnsData = [ - { - table: 'todos', - name: 'id', - format: 'int8' - }, - { - table: 'todos', - name: 'name', - format: 'text' - }, - { - table: 'memes', - name: 'id', - format: 'int8' - } - ] - sinon - .stub(pgMeta.columns, "list") - .returns(Promise.resolve({ data: columnsData })) - - const example = new TypeScriptInterfaces({ pgMeta: pgMeta }); - - const expected = `export interface definitions { - todos: { id: number; name: string }; - memes: { id: number }; -} -` - - assert.equal(await example.dump(), expected) - }) - it('handles nullable columns', async () => { const pgMeta = new PostgresMeta({ connectionString: '', max: 1 }) const columnsData = [ From 0471fbd72bf0d12619ffae337bd82f5da65da1d9 Mon Sep 17 00:00:00 2001 From: Nicholas Koh Date: Sat, 22 May 2021 22:46:41 +0800 Subject: [PATCH 17/17] refactor: Remove accidental file commit --- types/supabase.ts | 256 ---------------------------------------------- 1 file changed, 256 deletions(-) delete mode 100644 types/supabase.ts diff --git a/types/supabase.ts b/types/supabase.ts deleted file mode 100644 index 14bf1738..00000000 --- a/types/supabase.ts +++ /dev/null @@ -1,256 +0,0 @@ -/** - * This file was auto-generated by openapi-typescript. - * Do not make direct changes to the file. - */ - -export interface paths { - "/": { - get: { - responses: { - /** OK */ - 200: unknown; - }; - }; - }; - "/blog_posts": { - get: { - parameters: { - query: { - id?: parameters["rowFilter.blog_posts.id"]; - /** Filtering Columns */ - select?: parameters["select"]; - /** Ordering */ - order?: parameters["order"]; - /** Limiting and Pagination */ - offset?: parameters["offset"]; - /** Limiting and Pagination */ - limit?: parameters["limit"]; - }; - header: { - /** Limiting and Pagination */ - Range?: parameters["range"]; - /** Limiting and Pagination */ - "Range-Unit"?: parameters["rangeUnit"]; - /** Preference */ - Prefer?: parameters["preferCount"]; - }; - }; - responses: { - /** OK */ - 200: { - schema: definitions["blog_posts"][]; - }; - /** Partial Content */ - 206: unknown; - }; - }; - post: { - parameters: { - body: { - /** blog_posts */ - blog_posts?: definitions["blog_posts"]; - }; - query: { - /** Filtering Columns */ - select?: parameters["select"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** Created */ - 201: unknown; - }; - }; - delete: { - parameters: { - query: { - id?: parameters["rowFilter.blog_posts.id"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** No Content */ - 204: never; - }; - }; - patch: { - parameters: { - query: { - id?: parameters["rowFilter.blog_posts.id"]; - }; - body: { - /** blog_posts */ - blog_posts?: definitions["blog_posts"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** No Content */ - 204: never; - }; - }; - }; - "/inline_comments": { - get: { - parameters: { - query: { - id?: parameters["rowFilter.inline_comments.id"]; - text?: parameters["rowFilter.inline_comments.text"]; - custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; - blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; - /** Filtering Columns */ - select?: parameters["select"]; - /** Ordering */ - order?: parameters["order"]; - /** Limiting and Pagination */ - offset?: parameters["offset"]; - /** Limiting and Pagination */ - limit?: parameters["limit"]; - }; - header: { - /** Limiting and Pagination */ - Range?: parameters["range"]; - /** Limiting and Pagination */ - "Range-Unit"?: parameters["rangeUnit"]; - /** Preference */ - Prefer?: parameters["preferCount"]; - }; - }; - responses: { - /** OK */ - 200: { - schema: definitions["inline_comments"][]; - }; - /** Partial Content */ - 206: unknown; - }; - }; - post: { - parameters: { - body: { - /** inline_comments */ - inline_comments?: definitions["inline_comments"]; - }; - query: { - /** Filtering Columns */ - select?: parameters["select"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** Created */ - 201: unknown; - }; - }; - delete: { - parameters: { - query: { - id?: parameters["rowFilter.inline_comments.id"]; - text?: parameters["rowFilter.inline_comments.text"]; - custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; - blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** No Content */ - 204: never; - }; - }; - patch: { - parameters: { - query: { - id?: parameters["rowFilter.inline_comments.id"]; - text?: parameters["rowFilter.inline_comments.text"]; - custom_attributes?: parameters["rowFilter.inline_comments.custom_attributes"]; - blog_post_id?: parameters["rowFilter.inline_comments.blog_post_id"]; - }; - body: { - /** inline_comments */ - inline_comments?: definitions["inline_comments"]; - }; - header: { - /** Preference */ - Prefer?: parameters["preferReturn"]; - }; - }; - responses: { - /** No Content */ - 204: never; - }; - }; - }; -} - -export interface definitions { - blog_posts: { - /** - * Note: - * This is a Primary Key. - */ - id: number; - }; - inline_comments: { - /** - * Note: - * This is a Primary Key. - */ - id: number; - text?: string; - custom_attributes?: string; - /** - * Note: - * This is a Foreign Key to `blog_posts.id`. - */ - blog_post_id?: number; - }; -} - -export interface parameters { - /** Preference */ - preferParams: "params=single-object"; - /** Preference */ - preferReturn: "return=representation" | "return=minimal" | "return=none"; - /** Preference */ - preferCount: "count=none"; - /** Filtering Columns */ - select: string; - /** On Conflict */ - on_conflict: string; - /** Ordering */ - order: string; - /** Limiting and Pagination */ - range: string; - /** Limiting and Pagination */ - rangeUnit: string; - /** Limiting and Pagination */ - offset: string; - /** Limiting and Pagination */ - limit: string; - /** blog_posts */ - "body.blog_posts": definitions["blog_posts"]; - "rowFilter.blog_posts.id": string; - /** inline_comments */ - "body.inline_comments": definitions["inline_comments"]; - "rowFilter.inline_comments.id": string; - "rowFilter.inline_comments.text": string; - "rowFilter.inline_comments.custom_attributes": string; - "rowFilter.inline_comments.blog_post_id": string; -} - -export interface operations {}