SidePanelEditor.utils.test.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import { describe, expect, test } from 'vitest'
  2. import { formatRowsForInsert, getRowFromSidePanel } from './SidePanelEditor.utils'
  3. import type { SupaRow } from '@/components/grid/types'
  4. import type { SidePanel } from '@/state/table-editor'
  5. describe('SidePanelEditor.utils.test.ts', () => {
  6. test('formatRowsForInsert should for format rows with basic data types correctly', () => {
  7. const rows = [
  8. { id: 1, text: 'A' },
  9. { id: 2, text: 'B' },
  10. { id: 3, text: 'C' },
  11. ]
  12. const headers = ['id', 'text']
  13. const columns = [
  14. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  15. { id: '2', name: 'text', data_type: 'text', format: 'text', is_nullable: true },
  16. ]
  17. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  18. expect(formattedRows).toEqual(rows)
  19. })
  20. test('formatRowsForInsert should handle nullable columns if value is an empty string', () => {
  21. const rows = [
  22. { id: 1, text: 'A' },
  23. { id: 2, text: '' },
  24. { id: 3, text: 'C' },
  25. ]
  26. const headers = ['id', 'text']
  27. const columns = [
  28. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  29. { id: '2', name: 'text', data_type: 'text', format: 'text', is_nullable: true },
  30. ]
  31. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  32. expect(formattedRows).toEqual([
  33. { id: 1, text: 'A' },
  34. { id: 2, text: null },
  35. { id: 3, text: 'C' },
  36. ])
  37. })
  38. test('formatRowsForInsert should only convert empty strings to null for selected columns', () => {
  39. const rows = [
  40. { id: 1, name: '', email: '' },
  41. { id: 2, name: 'Bob', email: '' },
  42. ]
  43. const headers = ['id', 'name', 'email']
  44. const columns = [
  45. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  46. { id: '2', name: 'name', data_type: 'text', format: 'text', is_nullable: true },
  47. { id: '3', name: 'email', data_type: 'text', format: 'text', is_nullable: true },
  48. ]
  49. const formattedRows = formatRowsForInsert({
  50. rows,
  51. headers,
  52. columns: columns as any,
  53. emptyStringAsNullHeaders: ['email'],
  54. })
  55. expect(formattedRows).toEqual([
  56. { id: 1, name: '', email: null },
  57. { id: 2, name: 'Bob', email: null },
  58. ])
  59. })
  60. test('formatRowsForInsert should handle JSON object values properly', () => {
  61. const rows = [{ id: 1, value: '{"key": "value"}' }]
  62. const headers = ['id', 'value']
  63. const columns = [
  64. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  65. { id: '2', name: 'value', data_type: 'json', format: 'jsonb', is_nullable: true },
  66. ]
  67. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  68. expect(formattedRows).toEqual([{ id: 1, value: { key: 'value' } }])
  69. })
  70. test('formatRowsForInsert should handle JSON array values properly', () => {
  71. const rows = [{ id: 1, value: '["item1", "item2", "item3"]' }]
  72. const headers = ['id', 'value']
  73. const columns = [
  74. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  75. { id: '2', name: 'value', data_type: 'json', format: 'jsonb', is_nullable: true },
  76. ]
  77. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  78. expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
  79. })
  80. test('formatRowsForInsert should handle Postgres array values properly', () => {
  81. const rows = [{ id: 1, value: '{"item1", "item2", "item3"}' }]
  82. const headers = ['id', 'value']
  83. const columns = [
  84. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  85. { id: '2', name: 'value', data_type: 'ARRAY', format: '_text', is_nullable: true },
  86. ]
  87. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  88. expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
  89. })
  90. test('formatRowsForInsert should handle Postgres array values properly if provided JSON string', () => {
  91. const rows = [{ id: 1, value: '["item1", "item2", "item3"]' }]
  92. const headers = ['id', 'value']
  93. const columns = [
  94. { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
  95. { id: '2', name: 'value', data_type: 'ARRAY', format: '_text', is_nullable: true },
  96. ]
  97. const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
  98. expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
  99. })
  100. })
  101. describe('getRowFromSidePanel', () => {
  102. const mockRow: SupaRow = { idx: 1, id: 123, name: 'Test Row' }
  103. test('returns undefined when sidePanel is undefined', () => {
  104. expect(getRowFromSidePanel(undefined)).toBeUndefined()
  105. })
  106. test('returns row from json side panel', () => {
  107. const sidePanel: SidePanel = {
  108. type: 'json',
  109. jsonValue: { row: mockRow, column: 'data', value: '{}' },
  110. }
  111. expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
  112. })
  113. test('returns row from cell side panel', () => {
  114. const sidePanel: SidePanel = {
  115. type: 'cell',
  116. value: { row: mockRow, column: 'name' },
  117. }
  118. expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
  119. })
  120. test('returns undefined from cell side panel when value is undefined', () => {
  121. const sidePanel: SidePanel = {
  122. type: 'cell',
  123. }
  124. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  125. })
  126. test('returns row from row side panel', () => {
  127. const sidePanel: SidePanel = {
  128. type: 'row',
  129. row: mockRow,
  130. }
  131. expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
  132. })
  133. test('returns undefined from row side panel when row is undefined', () => {
  134. const sidePanel: SidePanel = {
  135. type: 'row',
  136. }
  137. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  138. })
  139. test('returns row from foreign-row-selector side panel', () => {
  140. const sidePanel: SidePanel = {
  141. type: 'foreign-row-selector',
  142. foreignKey: {
  143. foreignKey: {
  144. schema: 'public',
  145. table: 'users',
  146. columns: [{ source: 'user_id', target: 'id' }],
  147. deletionAction: 'NO ACTION',
  148. updateAction: 'NO ACTION',
  149. },
  150. row: mockRow,
  151. column: { name: 'user_id' } as any,
  152. },
  153. }
  154. expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
  155. })
  156. test('returns undefined for table side panel', () => {
  157. const sidePanel: SidePanel = {
  158. type: 'table',
  159. mode: 'new',
  160. }
  161. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  162. })
  163. test('returns undefined for column side panel', () => {
  164. const sidePanel: SidePanel = {
  165. type: 'column',
  166. }
  167. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  168. })
  169. test('returns undefined for schema side panel', () => {
  170. const sidePanel: SidePanel = {
  171. type: 'schema',
  172. mode: 'new',
  173. }
  174. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  175. })
  176. test('returns undefined for csv-import side panel', () => {
  177. const sidePanel: SidePanel = {
  178. type: 'csv-import',
  179. }
  180. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  181. })
  182. test('returns undefined for operation-queue side panel', () => {
  183. const sidePanel: SidePanel = {
  184. type: 'operation-queue',
  185. }
  186. expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
  187. })
  188. })