goby-database 2.2.24 → 2.2.26

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/dist/index.d.ts CHANGED
@@ -76,7 +76,10 @@ export default class Project {
76
76
  property_id: number;
77
77
  value: any;
78
78
  }[]): void;
79
- action_make_relations(relations: [input_1: ItemRelationSide, input_2: ItemRelationSide][]): void;
79
+ action_edit_relations(relations: {
80
+ change: 'add' | 'remove';
81
+ sides: [input_1: ItemRelationSide, input_2: ItemRelationSide];
82
+ }[]): void;
80
83
  retrieve_class_items({ class_id, class_name, class_data, pagination }: {
81
84
  class_id: number;
82
85
  class_name?: string;
package/dist/index.js CHANGED
@@ -772,24 +772,33 @@ export default class Project {
772
772
  };
773
773
  }
774
774
  }
775
- action_make_relations(relations) {
775
+ action_edit_relations(relations) {
776
776
  // NOTE: changes to make to this in the future:
777
777
  // - for input readability, allow class_name and prop_name as input options, assuming they’re enforced as unique, and use them to look up IDs
778
778
  // - enforce max_values here
779
779
  var _a;
780
- for (let [input_1, input_2] of relations) {
781
- let column_names = {
780
+ for (let { change, sides } of relations) {
781
+ const [input_1, input_2] = sides;
782
+ const column_names = {
782
783
  input_1: junction_col_name(input_1.class_id, input_1.prop_id),
783
784
  input_2: junction_col_name(input_2.class_id, input_2.prop_id)
784
785
  };
785
- let junction_id = (_a = this.junction_cache.find(j => full_relation_match(j.sides, [input_1, input_2]))) === null || _a === void 0 ? void 0 : _a.id;
786
- const date_added = Date.now();
786
+ const junction_id = (_a = this.junction_cache.find(j => full_relation_match(j.sides, [input_1, input_2]))) === null || _a === void 0 ? void 0 : _a.id;
787
787
  if (junction_id) {
788
- this.db.prepare(`
789
- INSERT INTO junction_${junction_id}
790
- ("${column_names.input_1}", "${column_names.input_2}",date_added)
791
- VALUES (${input_1.item_id},${input_2.item_id},${date_added})
792
- `).run();
788
+ if (change == 'add') {
789
+ const date_added = Date.now();
790
+ this.db.prepare(`
791
+ INSERT INTO junction_${junction_id}
792
+ ("${column_names.input_1}", "${column_names.input_2}",date_added)
793
+ VALUES (${input_1.item_id},${input_2.item_id},${date_added})
794
+ `).run();
795
+ }
796
+ else if (change == 'remove') {
797
+ this.db.prepare(`
798
+ DELETE FROM junction_${junction_id}
799
+ WHERE "${column_names.input_1}" = ${input_1.item_id}
800
+ AND "${column_names.input_2}" = ${input_2.item_id}`).run();
801
+ }
793
802
  }
794
803
  else {
795
804
  throw Error('Something went wrong - junction table for relationship not found');
@@ -802,10 +811,10 @@ export default class Project {
802
811
  var _a, _b, _c, _d, _e;
803
812
  const pagination_defaults = {
804
813
  page_size: null,
805
- property_range: 'all'
814
+ property_range: 'all',
815
+ item_range: 'all'
806
816
  };
807
817
  pagination = Object.assign(Object.assign({}, pagination_defaults), pagination);
808
- const slim = pagination.property_range == 'slim';
809
818
  if (class_name == undefined || class_data == undefined) {
810
819
  class_data = this.lookup_class(class_id);
811
820
  class_name = class_data.name;
@@ -818,66 +827,76 @@ export default class Project {
818
827
  const cte_joins = [];
819
828
  // joined+added between SELECT and FROM, built from relations
820
829
  const relation_selections = [];
821
- // NOTE: in the future, if a property_range is defined, first filter class_data.properties by those IDs
822
- let relation_properties = class_data.properties.filter(a => a.type == 'relation');
823
- if (!slim) {
824
- for (let prop of relation_properties) {
825
- const target_selects = [];
826
- let property_junction_column_name = junction_col_name(class_id, prop.id);
827
- if (prop.relation_targets.length > 0) {
828
- for (let i = 0; i < prop.relation_targets.length; i++) {
829
- // find the side that does not match both the class and prop IDs
830
- let target = prop.relation_targets[i];
831
- const target_class = this.class_cache.find((a) => a.id == (target === null || target === void 0 ? void 0 : target.class_id));
832
- if (target && target_class) {
833
- let target_junction_column_name = junction_col_name(target.class_id, target.prop_id);
834
- // NOTE: as mentioned elsewhere, possibly allow multiple label props
835
- const target_label_id = (_b = (_a = target_class === null || target_class === void 0 ? void 0 : target_class.metadata) === null || _a === void 0 ? void 0 : _a.label) === null || _b === void 0 ? void 0 : _b.properties[0];
836
- const target_label = target_class === null || target_class === void 0 ? void 0 : target_class.properties.find((p) => p.id == target_label_id);
837
- const label_sql_string = target_label ? `,'user_${target_label.name}',target_class."user_${target_label.name}"` : '';
838
- let junction_id = target.junction_id;
839
- let target_select = `
840
- SELECT
841
- "${property_junction_column_name}",
842
- json_object('class_id',${target.class_id},'system_id',junction."${target_junction_column_name}"${label_sql_string}) AS target_data, junction.date_added AS date_added
843
- FROM junction_${junction_id} AS junction
844
- LEFT JOIN "class_${target_class === null || target_class === void 0 ? void 0 : target_class.name}" AS target_class ON junction."${target_junction_column_name}" = target_class.system_id
845
- `;
846
- target_selects.push(target_select);
847
- }
848
- else {
849
- throw Error('Something went wrong trying to retrieve relationship data');
850
- }
830
+ const label_prop_ids = (_b = (_a = class_data.metadata.label) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : [];
831
+ // if a property_range is defined, first filter class_data.properties by those IDs
832
+ const retrieved_properties = class_data.properties.filter((prop) => {
833
+ if (pagination.property_range == 'all' || !pagination.property_range) {
834
+ return true;
835
+ }
836
+ else if (pagination.property_range == 'slim') {
837
+ return label_prop_ids.includes(prop.id);
838
+ }
839
+ else {
840
+ return pagination.property_range.includes(prop.id);
841
+ }
842
+ });
843
+ const relation_properties = retrieved_properties.filter(a => a.type == 'relation');
844
+ const data_properties = retrieved_properties.filter(a => a.type == 'data');
845
+ for (let prop of relation_properties) {
846
+ const target_selects = [];
847
+ let property_junction_column_name = junction_col_name(class_id, prop.id);
848
+ if (prop.relation_targets.length > 0) {
849
+ for (let i = 0; i < prop.relation_targets.length; i++) {
850
+ // find the side that does not match both the class and prop IDs
851
+ let target = prop.relation_targets[i];
852
+ const target_class = this.class_cache.find((a) => a.id == (target === null || target === void 0 ? void 0 : target.class_id));
853
+ if (target && target_class) {
854
+ let target_junction_column_name = junction_col_name(target.class_id, target.prop_id);
855
+ // NOTE: as mentioned elsewhere, possibly allow multiple label props
856
+ const target_label_id = (_d = (_c = target_class === null || target_class === void 0 ? void 0 : target_class.metadata) === null || _c === void 0 ? void 0 : _c.label) === null || _d === void 0 ? void 0 : _d.properties[0];
857
+ const target_label = target_class === null || target_class === void 0 ? void 0 : target_class.properties.find((p) => p.id == target_label_id);
858
+ const label_sql_string = target_label ? `,'user_${target_label.name}',target_class."user_${target_label.name}"` : '';
859
+ let junction_id = target.junction_id;
860
+ let target_select = `
861
+ SELECT
862
+ "${property_junction_column_name}",
863
+ json_object('class_id',${target.class_id},'system_id',junction."${target_junction_column_name}"${label_sql_string}) AS target_data, junction.date_added AS date_added
864
+ FROM junction_${junction_id} AS junction
865
+ LEFT JOIN "class_${target_class === null || target_class === void 0 ? void 0 : target_class.name}" AS target_class ON junction."${target_junction_column_name}" = target_class.system_id
866
+ `;
867
+ target_selects.push(target_select);
868
+ }
869
+ else {
870
+ throw Error('Something went wrong trying to retrieve relationship data');
851
871
  }
852
- // uses built-in aggregate json function instead of group_concat craziness
853
- const cte = `[${prop.id}_cte] AS (
854
- SELECT "${property_junction_column_name}", json_group_array( json(target_data) ) AS [user_${prop.name}]
855
- FROM
856
- (
857
- ${target_selects.join(`
858
- UNION
859
- `)}
860
- ORDER BY date_added
861
- )
862
- GROUP BY "${property_junction_column_name}"
863
-
864
- )`;
865
- cte_strings.push(cte);
866
- relation_selections.push(`[${prop.id}_cte].[user_${prop.name}]`);
867
- cte_joins.push(`LEFT JOIN [${prop.id}_cte] ON [${prop.id}_cte]."${property_junction_column_name}" = ${class_string}.system_id`);
868
- }
869
- else {
870
- relation_selections.push(`'[]' AS [user_${prop.name}]`);
871
872
  }
873
+ // uses built-in aggregate json function instead of group_concat craziness
874
+ const cte = `[${prop.id}_cte] AS (
875
+ SELECT "${property_junction_column_name}", json_group_array( json(target_data) ) AS [user_${prop.name}]
876
+ FROM
877
+ (
878
+ ${target_selects.join(`
879
+ UNION
880
+ `)}
881
+ ORDER BY date_added
882
+ )
883
+ GROUP BY "${property_junction_column_name}"
884
+
885
+ )`;
886
+ cte_strings.push(cte);
887
+ relation_selections.push(`[${prop.id}_cte].[user_${prop.name}]`);
888
+ cte_joins.push(`LEFT JOIN [${prop.id}_cte] ON [${prop.id}_cte]."${property_junction_column_name}" = ${class_string}.system_id`);
889
+ }
890
+ else {
891
+ relation_selections.push(`'[]' AS [user_${prop.name}]`);
872
892
  }
873
893
  }
874
894
  let orderby = `ORDER BY ${class_string}.system_order`;
875
- let table_selection = `[class_${class_name}].*`;
876
- if (slim) {
877
- const label_prop_ids = (_d = (_c = class_data.metadata.label) === null || _c === void 0 ? void 0 : _c.properties) !== null && _d !== void 0 ? _d : [];
878
- const label_props = class_data.properties.filter((p) => label_prop_ids.includes(p.id));
879
- const label_prop_sql_string = label_props.map((p) => `[user_${p.name}]`).join(',');
880
- table_selection = `system_id,system_order,${label_prop_sql_string}`;
895
+ const data_prop_sql_string = data_properties.map((p) => `[user_${p.name}]`).join(',');
896
+ const table_selection = pagination.property_range == 'all' ? `[class_${class_name}].*` : `system_id,system_order,${data_prop_sql_string}`;
897
+ let filter_by_items = '';
898
+ if (pagination.item_range && pagination.item_range !== 'all') {
899
+ filter_by_items = `WHERE system_id in (${pagination.item_range.join(',')})`;
881
900
  }
882
901
  let comma_break = `,
883
902
  `;
@@ -886,6 +905,7 @@ export default class Project {
886
905
  SELECT ${table_selection} ${relation_selections.length > 0 ? ', ' + relation_selections.join(`, `) : ''}
887
906
  FROM [class_${class_name}]
888
907
  ${cte_joins.join(' ')}
908
+ ${filter_by_items}
889
909
  ${orderby}`;
890
910
  // possibly elaborate this any type a little more in the future, e.g. a CellValue or SQLCellValue type that expects some wildcards
891
911
  let items = this.db.prepare(query).all();
package/dist/types.d.ts CHANGED
@@ -145,7 +145,10 @@ export type ClassList = ClassData[];
145
145
  export type ItemPagination = {
146
146
  page_size?: number | null;
147
147
  page_range?: [start: number, end?: number];
148
+ /** Filters props by ID. If not specified, pulls all. "slim" pulls the ID and label */
148
149
  property_range?: number[] | 'slim' | 'all';
150
+ /** Filter by item IDs. If not specified, pulls all */
151
+ item_range?: number[] | 'all';
149
152
  };
150
153
  export type PaginatedItems = ItemPagination & {
151
154
  loaded: ClassRow[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goby-database",
3
- "version": "2.2.24",
3
+ "version": "2.2.26",
4
4
  "description": "This will hold the core better-sqlite3-powered application for creating and modifying goby databases",
5
5
  "main": "dist/index.js",
6
6
  "files": [