DatabaseTestHelper.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import {
  2. FieldType,
  3. SingleSelectTypeOptionPB,
  4. ViewLayoutTypePB,
  5. ViewPB,
  6. WorkspaceSettingPB,
  7. } from '../../../services/backend';
  8. import { FolderEventReadCurrentWorkspace } from '../../../services/backend/events/flowy-folder';
  9. import { AppBackendService } from '../../stores/effects/folder/app/app_bd_svc';
  10. import { DatabaseController } from '../../stores/effects/database/database_controller';
  11. import { RowInfo } from '../../stores/effects/database/row/row_cache';
  12. import { RowController } from '../../stores/effects/database/row/row_controller';
  13. import {
  14. CellControllerBuilder,
  15. DateCellController,
  16. NumberCellController,
  17. SelectOptionCellController,
  18. TextCellController,
  19. URLCellController,
  20. } from '../../stores/effects/database/cell/controller_builder';
  21. import { None, Option, Some } from 'ts-results';
  22. import { TypeOptionBackendService } from '../../stores/effects/database/field/type_option/type_option_bd_svc';
  23. import { DatabaseBackendService } from '../../stores/effects/database/database_bd_svc';
  24. import { FieldInfo } from '../../stores/effects/database/field/field_controller';
  25. import { TypeOptionController } from '../../stores/effects/database/field/type_option/type_option_controller';
  26. import { makeSingleSelectTypeOptionContext } from '../../stores/effects/database/field/type_option/type_option_context';
  27. import { SelectOptionBackendService } from '../../stores/effects/database/cell/select_option_bd_svc';
  28. // Create a database view for specific layout type
  29. // Do not use it production code. Just for testing
  30. export async function createTestDatabaseView(layout: ViewLayoutTypePB): Promise<ViewPB> {
  31. const workspaceSetting: WorkspaceSettingPB = await FolderEventReadCurrentWorkspace().then((result) => result.unwrap());
  32. const app = workspaceSetting.workspace.apps.items[0];
  33. const appService = new AppBackendService(app.id);
  34. return await appService.createView({ name: 'New Grid', layoutType: layout });
  35. }
  36. export async function openTestDatabase(viewId: string): Promise<DatabaseController> {
  37. return new DatabaseController(viewId);
  38. }
  39. export async function assertTextCell(
  40. fieldId: string,
  41. rowInfo: RowInfo,
  42. databaseController: DatabaseController,
  43. expectedContent: string
  44. ) {
  45. const cellController = await makeTextCellController(fieldId, rowInfo, databaseController).then((result) =>
  46. result.unwrap()
  47. );
  48. cellController.subscribeChanged({
  49. onCellChanged: (value) => {
  50. const cellContent = value.unwrap();
  51. if (cellContent !== expectedContent) {
  52. throw Error('Text cell content is not match');
  53. }
  54. },
  55. });
  56. await cellController.getCellData();
  57. }
  58. export async function editTextCell(
  59. fieldId: string,
  60. rowInfo: RowInfo,
  61. databaseController: DatabaseController,
  62. content: string
  63. ) {
  64. const cellController = await makeTextCellController(fieldId, rowInfo, databaseController).then((result) =>
  65. result.unwrap()
  66. );
  67. await cellController.saveCellData(content);
  68. }
  69. export async function makeTextCellController(
  70. fieldId: string,
  71. rowInfo: RowInfo,
  72. databaseController: DatabaseController
  73. ): Promise<Option<TextCellController>> {
  74. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.RichText, databaseController).then(
  75. (result) => result.unwrap()
  76. );
  77. return Some(builder.build() as TextCellController);
  78. }
  79. export async function makeNumberCellController(
  80. fieldId: string,
  81. rowInfo: RowInfo,
  82. databaseController: DatabaseController
  83. ): Promise<Option<NumberCellController>> {
  84. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.Number, databaseController).then(
  85. (result) => result.unwrap()
  86. );
  87. return Some(builder.build() as NumberCellController);
  88. }
  89. export async function makeSingleSelectCellController(
  90. fieldId: string,
  91. rowInfo: RowInfo,
  92. databaseController: DatabaseController
  93. ): Promise<Option<SelectOptionCellController>> {
  94. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.SingleSelect, databaseController).then(
  95. (result) => result.unwrap()
  96. );
  97. return Some(builder.build() as SelectOptionCellController);
  98. }
  99. export async function makeMultiSelectCellController(
  100. fieldId: string,
  101. rowInfo: RowInfo,
  102. databaseController: DatabaseController
  103. ): Promise<Option<SelectOptionCellController>> {
  104. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.MultiSelect, databaseController).then(
  105. (result) => result.unwrap()
  106. );
  107. return Some(builder.build() as SelectOptionCellController);
  108. }
  109. export async function makeDateCellController(
  110. fieldId: string,
  111. rowInfo: RowInfo,
  112. databaseController: DatabaseController
  113. ): Promise<Option<DateCellController>> {
  114. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.DateTime, databaseController).then(
  115. (result) => result.unwrap()
  116. );
  117. return Some(builder.build() as DateCellController);
  118. }
  119. export async function makeURLCellController(
  120. fieldId: string,
  121. rowInfo: RowInfo,
  122. databaseController: DatabaseController
  123. ): Promise<Option<URLCellController>> {
  124. const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.DateTime, databaseController).then(
  125. (result) => result.unwrap()
  126. );
  127. return Some(builder.build() as URLCellController);
  128. }
  129. export async function makeCellControllerBuilder(
  130. fieldId: string,
  131. rowInfo: RowInfo,
  132. fieldType: FieldType,
  133. databaseController: DatabaseController
  134. ): Promise<Option<CellControllerBuilder>> {
  135. const rowCache = databaseController.databaseViewCache.getRowCache();
  136. const cellCache = rowCache.getCellCache();
  137. const fieldController = databaseController.fieldController;
  138. const rowController = new RowController(rowInfo, fieldController, rowCache);
  139. const cellByFieldId = await rowController.loadCells();
  140. for (const cellIdentifier of cellByFieldId.values()) {
  141. const builder = new CellControllerBuilder(cellIdentifier, cellCache, fieldController);
  142. if (cellIdentifier.fieldId === fieldId) {
  143. return Some(builder);
  144. }
  145. }
  146. return None;
  147. }
  148. export function findFirstFieldInfoWithFieldType(rowInfo: RowInfo, fieldType: FieldType) {
  149. const fieldInfo = rowInfo.fieldInfos.find((element) => element.field.field_type === fieldType);
  150. if (fieldInfo === undefined) {
  151. return None;
  152. } else {
  153. return Some(fieldInfo);
  154. }
  155. }
  156. export async function assertFieldName(viewId: string, fieldId: string, fieldType: FieldType, expected: string) {
  157. const svc = new TypeOptionBackendService(viewId);
  158. const typeOptionPB = await svc.getTypeOption(fieldId, fieldType).then((result) => result.unwrap());
  159. if (typeOptionPB.field.name !== expected) {
  160. throw Error('Expect field name:' + expected + 'but receive:' + typeOptionPB.field.name);
  161. }
  162. }
  163. export async function assertNumberOfFields(viewId: string, expected: number) {
  164. const svc = new DatabaseBackendService(viewId);
  165. const databasePB = await svc.openDatabase().then((result) => result.unwrap());
  166. if (databasePB.fields.length !== expected) {
  167. throw Error('Expect number of fields:' + expected + 'but receive:' + databasePB.fields.length);
  168. }
  169. }
  170. export async function assertNumberOfRows(viewId: string, expected: number) {
  171. const svc = new DatabaseBackendService(viewId);
  172. const databasePB = await svc.openDatabase().then((result) => result.unwrap());
  173. if (databasePB.rows.length !== expected) {
  174. throw Error('Expect number of rows:' + expected + 'but receive:' + databasePB.rows.length);
  175. }
  176. }
  177. export async function assertNumberOfRowsInGroup(viewId: string, groupId: string, expected: number) {
  178. const svc = new DatabaseBackendService(viewId);
  179. await svc.openDatabase();
  180. const group = await svc.getGroup(groupId).then((result) => result.unwrap());
  181. if (group.rows.length !== expected) {
  182. throw Error('Expect number of rows in group:' + expected + 'but receive:' + group.rows.length);
  183. }
  184. }
  185. export async function createSingleSelectOptions(viewId: string, fieldInfo: FieldInfo, optionNames: string[]) {
  186. assert(fieldInfo.field.field_type === FieldType.SingleSelect, 'Only work on single select');
  187. const typeOptionController = new TypeOptionController(viewId, Some(fieldInfo));
  188. const singleSelectTypeOptionContext = makeSingleSelectTypeOptionContext(typeOptionController);
  189. const singleSelectTypeOptionPB: SingleSelectTypeOptionPB = await singleSelectTypeOptionContext
  190. .getTypeOption()
  191. .then((result) => result.unwrap());
  192. const backendSvc = new SelectOptionBackendService(viewId, fieldInfo.field.id);
  193. for (const optionName of optionNames) {
  194. const option = await backendSvc.createOption({ name: optionName }).then((result) => result.unwrap());
  195. singleSelectTypeOptionPB.options.splice(0, 0, option);
  196. }
  197. await singleSelectTypeOptionContext.setTypeOption(singleSelectTypeOptionPB);
  198. return singleSelectTypeOptionContext;
  199. }
  200. export function assert(condition: boolean, msg?: string) {
  201. if (!condition) {
  202. throw Error(msg);
  203. }
  204. }