publications.test.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import { afterAll, beforeAll, expect, test } from 'vitest'
  2. import pgMeta from '../src/index'
  3. import { cleanupRoot, createTestDatabase } from './db/utils'
  4. beforeAll(async () => {
  5. // Any global setup if needed
  6. })
  7. afterAll(async () => {
  8. await cleanupRoot()
  9. })
  10. const withTestDatabase = (
  11. name: string,
  12. fn: (db: Awaited<ReturnType<typeof createTestDatabase>>) => Promise<void>
  13. ) => {
  14. test(name, async () => {
  15. const db = await createTestDatabase()
  16. try {
  17. await fn(db)
  18. } finally {
  19. await db.cleanup()
  20. }
  21. })
  22. }
  23. const cleanNondet = (res: any) => {
  24. if (!res.data?.tables) return res
  25. const tables = res.data.tables.map(({ id, ...rest }: any) => rest)
  26. return { ...res, data: { ...res.data, tables } }
  27. }
  28. withTestDatabase('retrieve, create, update, delete', async ({ executeQuery }) => {
  29. // Create publication
  30. const { sql: createSql } = pgMeta.publications.create({
  31. name: 'a',
  32. publish_insert: true,
  33. publish_update: true,
  34. publish_delete: true,
  35. publish_truncate: false,
  36. tables: ['users'],
  37. })
  38. await executeQuery(createSql)
  39. // Retrieve publication
  40. const { sql: retrieveSql, zod: retrieveZod } = pgMeta.publications.retrieve({ name: 'a' })
  41. const res = retrieveZod.parse((await executeQuery(retrieveSql))[0])
  42. expect(cleanNondet({ data: res })).toMatchInlineSnapshot(
  43. { data: { id: expect.any(Number) } },
  44. `
  45. {
  46. "data": {
  47. "id": Any<Number>,
  48. "name": "a",
  49. "owner": "postgres",
  50. "publish_delete": true,
  51. "publish_insert": true,
  52. "publish_truncate": false,
  53. "publish_update": true,
  54. "tables": [
  55. {
  56. "name": "users",
  57. "schema": "public",
  58. },
  59. ],
  60. },
  61. }
  62. `
  63. )
  64. // Update publication
  65. const { sql: updateSql } = pgMeta.publications.update(res!.id, {
  66. name: 'b',
  67. publish_insert: false,
  68. tables: [],
  69. })
  70. await executeQuery(updateSql)
  71. // Verify update
  72. const { sql: retrieveUpdatedSql, zod: retrieveUpdatedZod } = pgMeta.publications.retrieve({
  73. name: 'b',
  74. })
  75. const updatedRes = retrieveUpdatedZod.parse((await executeQuery(retrieveUpdatedSql))[0])
  76. expect(cleanNondet({ data: updatedRes })).toMatchInlineSnapshot(
  77. { data: { id: expect.any(Number) } },
  78. `
  79. {
  80. "data": {
  81. "id": Any<Number>,
  82. "name": "b",
  83. "owner": "postgres",
  84. "publish_delete": true,
  85. "publish_insert": false,
  86. "publish_truncate": false,
  87. "publish_update": true,
  88. "tables": [],
  89. },
  90. }
  91. `
  92. )
  93. // Remove publication
  94. const { sql: removeSql } = pgMeta.publications.remove(updatedRes!)
  95. await executeQuery(removeSql)
  96. // Verify removal
  97. const { sql: verifyRemoveSql } = pgMeta.publications.retrieve({ id: updatedRes!.id })
  98. const finalRes = await executeQuery(verifyRemoveSql)
  99. expect(finalRes).toHaveLength(0)
  100. })
  101. withTestDatabase('tables with uppercase', async ({ executeQuery }) => {
  102. // Create table with uppercase name
  103. await executeQuery(`
  104. CREATE TABLE public."T" (
  105. id SERIAL PRIMARY KEY
  106. );
  107. `)
  108. // Create publication
  109. const { sql: createSql } = pgMeta.publications.create({
  110. name: 'pub',
  111. tables: ['T'],
  112. })
  113. await executeQuery(createSql)
  114. // Verify creation
  115. const { sql: retrieveSql, zod: retrieveZod } = pgMeta.publications.retrieve({ name: 'pub' })
  116. let res = retrieveZod.parse((await executeQuery(retrieveSql))[0])
  117. expect(cleanNondet({ data: res })).toMatchInlineSnapshot(
  118. { data: { id: expect.any(Number) } },
  119. `
  120. {
  121. "data": {
  122. "id": Any<Number>,
  123. "name": "pub",
  124. "owner": "postgres",
  125. "publish_delete": false,
  126. "publish_insert": false,
  127. "publish_truncate": false,
  128. "publish_update": false,
  129. "tables": [
  130. {
  131. "name": "T",
  132. "schema": "public",
  133. },
  134. ],
  135. },
  136. }
  137. `
  138. )
  139. // Update publication
  140. const { sql: updateSql } = pgMeta.publications.update(res!.id, {
  141. tables: ['T'],
  142. })
  143. await executeQuery(updateSql)
  144. // Verify update
  145. const { sql: retrieveUpdatedSql, zod: retrieveUpdatedZod } = pgMeta.publications.retrieve({
  146. name: 'pub',
  147. })
  148. res = retrieveUpdatedZod.parse((await executeQuery(retrieveUpdatedSql))[0])
  149. expect(cleanNondet({ data: res })).toMatchInlineSnapshot(
  150. { data: { id: expect.any(Number) } },
  151. `
  152. {
  153. "data": {
  154. "id": Any<Number>,
  155. "name": "pub",
  156. "owner": "postgres",
  157. "publish_delete": false,
  158. "publish_insert": false,
  159. "publish_truncate": false,
  160. "publish_update": false,
  161. "tables": [
  162. {
  163. "name": "T",
  164. "schema": "public",
  165. },
  166. ],
  167. },
  168. }
  169. `
  170. )
  171. // Remove publication
  172. const { sql: removeSql } = pgMeta.publications.remove(res!)
  173. await executeQuery(removeSql)
  174. })
  175. withTestDatabase('FOR ALL TABLES', async ({ executeQuery }) => {
  176. // Create publication
  177. const { sql: createSql } = pgMeta.publications.create({
  178. name: 'for_all',
  179. publish_insert: true,
  180. publish_update: true,
  181. publish_delete: true,
  182. publish_truncate: false,
  183. })
  184. await executeQuery(createSql)
  185. // Retrieve and verify
  186. const { sql: retrieveSql, zod: retrieveZod } = pgMeta.publications.retrieve({ name: 'for_all' })
  187. const res = retrieveZod.parse((await executeQuery(retrieveSql))[0])
  188. expect(cleanNondet({ data: res })).toMatchInlineSnapshot(
  189. { data: { id: expect.any(Number) } },
  190. `
  191. {
  192. "data": {
  193. "id": Any<Number>,
  194. "name": "for_all",
  195. "owner": "postgres",
  196. "publish_delete": true,
  197. "publish_insert": true,
  198. "publish_truncate": false,
  199. "publish_update": true,
  200. "tables": null,
  201. },
  202. }
  203. `
  204. )
  205. // Remove publication
  206. const { sql: removeSql } = pgMeta.publications.remove(res!)
  207. await executeQuery(removeSql)
  208. })
  209. withTestDatabase('update no tables -> all tables', async ({ executeQuery }) => {
  210. // Create publication
  211. const { sql: createSql } = pgMeta.publications.create({
  212. name: 'pub',
  213. tables: [],
  214. })
  215. await executeQuery(createSql)
  216. // Retrieve created publication
  217. const { sql: retrieveSql, zod: retrieveZod } = pgMeta.publications.retrieve({ name: 'pub' })
  218. const res = retrieveZod.parse((await executeQuery(retrieveSql))[0])
  219. // Update publication
  220. const { sql: updateSql } = pgMeta.publications.update(res!.id, {
  221. tables: null,
  222. })
  223. await executeQuery(updateSql)
  224. // Verify update
  225. const { sql: verifyRetrieveSql, zod: verifyRetrieveZod } = pgMeta.publications.retrieve({
  226. name: 'pub',
  227. })
  228. const updatedRes = verifyRetrieveZod.parse((await executeQuery(verifyRetrieveSql))[0])
  229. expect(cleanNondet({ data: updatedRes })).toMatchInlineSnapshot(
  230. { data: { id: expect.any(Number) } },
  231. `
  232. {
  233. "data": {
  234. "id": Any<Number>,
  235. "name": "pub",
  236. "owner": "postgres",
  237. "publish_delete": false,
  238. "publish_insert": false,
  239. "publish_truncate": false,
  240. "publish_update": false,
  241. "tables": null,
  242. },
  243. }
  244. `
  245. )
  246. // Remove publication
  247. const { sql: removeSql } = pgMeta.publications.remove(updatedRes!)
  248. await executeQuery(removeSql)
  249. })
  250. withTestDatabase('update all tables -> no tables', async ({ executeQuery }) => {
  251. // Create publication
  252. const { sql: createSql } = pgMeta.publications.create({
  253. name: 'pub',
  254. tables: null,
  255. })
  256. await executeQuery(createSql)
  257. // Retrieve created publication
  258. const { sql: retrieveSql, zod: retrieveZod } = pgMeta.publications.retrieve({ name: 'pub' })
  259. const res = retrieveZod.parse((await executeQuery(retrieveSql))[0])
  260. // Update publication
  261. const { sql: updateSql } = pgMeta.publications.update(res!.id, {
  262. tables: [],
  263. })
  264. await executeQuery(updateSql)
  265. // Verify update
  266. const { sql: verifyRetrieveSql, zod: verifyRetrieveZod } = pgMeta.publications.retrieve({
  267. name: 'pub',
  268. })
  269. const updatedRes = verifyRetrieveZod.parse((await executeQuery(verifyRetrieveSql))[0])
  270. expect(cleanNondet({ data: updatedRes })).toMatchInlineSnapshot(
  271. { data: { id: expect.any(Number) } },
  272. `
  273. {
  274. "data": {
  275. "id": Any<Number>,
  276. "name": "pub",
  277. "owner": "postgres",
  278. "publish_delete": false,
  279. "publish_insert": false,
  280. "publish_truncate": false,
  281. "publish_update": false,
  282. "tables": [],
  283. },
  284. }
  285. `
  286. )
  287. // Remove publication
  288. const { sql: removeSql } = pgMeta.publications.remove(updatedRes!)
  289. await executeQuery(removeSql)
  290. })