goby-database 2.2.27 → 2.2.29

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
@@ -70,12 +70,31 @@ export default class Project {
70
70
  delete_item_from_root(id: number): void;
71
71
  action_set_root_item_value(id: number, value: string): void;
72
72
  lookup_class(class_id: number): ClassData;
73
- action_add_row(class_id: number): number;
73
+ /**
74
+ * Creates a new item and adds it to the class you indicate
75
+ * @param class_id - class you want to add new item to
76
+ * @param property_values - any properties you want to fill in as you create this item (data props only for now)
77
+ * @returns - id of new item
78
+ */
79
+ action_add_row(class_id: number, property_values?: {
80
+ property_id: number;
81
+ value: any;
82
+ }[]): number;
74
83
  get_next_order(table_name: string): number;
75
- action_set_property_values(class_id: number, item_id: number, changes: {
84
+ /**
85
+ * Sets 1 or more data property values for a given class item.
86
+ * @param class_id - class of item
87
+ * @param item_id - id of item
88
+ * @param changes - array of data properties to be set
89
+ */
90
+ action_edit_item_data(class_id: number, item_id: number, changes: {
76
91
  property_id: number;
77
92
  value: any;
78
93
  }[]): void;
94
+ /**
95
+ * Adds/removes relations between items/item properties
96
+ * @param relations - list of pairs of items for which relations should be added or removed between specified properties
97
+ */
79
98
  action_edit_relations(relations: {
80
99
  change: 'add' | 'remove';
81
100
  sides: [input_1: ItemRelationSide, input_2: ItemRelationSide];
package/dist/index.js CHANGED
@@ -1,8 +1,5 @@
1
1
  import Database from 'better-sqlite3';
2
- import { defined, partial_relation_match, full_relation_match, can_have_multiple_values, junction_col_name, side_match, two_way, edit_has_valid_sides, readable_edit } from './utils.js';
3
- const text_data_types = ['string', 'resource'];
4
- const integer_data_types = ['boolean'];
5
- const real_data_types = ['number'];
2
+ import { defined, partial_relation_match, full_relation_match, can_have_multiple_values, junction_col_name, side_match, two_way, edit_has_valid_sides, readable_edit, text_data_types, integer_data_types, real_data_types, validate_data_value } from './utils.js';
6
3
  export default class Project {
7
4
  constructor(source) {
8
5
  this.class_cache = [];
@@ -689,14 +686,42 @@ export default class Project {
689
686
  throw new Error('Cannot find class in class list.');
690
687
  return class_data;
691
688
  }
692
- action_add_row(class_id) {
689
+ /**
690
+ * Creates a new item and adds it to the class you indicate
691
+ * @param class_id - class you want to add new item to
692
+ * @param property_values - any properties you want to fill in as you create this item (data props only for now)
693
+ * @returns - id of new item
694
+ */
695
+ action_add_row(class_id, property_values = []) {
693
696
  const class_data = this.lookup_class(class_id);
694
697
  let class_name = class_data.name;
695
698
  //first add new row to root and get id
696
699
  const root_id = this.create_item_in_root({ type: 'class_' + class_id });
700
+ // NOTE: I will need a second handler in the future if I want to support relation props here
701
+ // (probably utilizing action_edit_relations)
702
+ const data_property_sql = property_values.reduce((obj, current) => {
703
+ const corresponding_prop = class_data.properties.find((prop) => {
704
+ return prop.id == current.property_id;
705
+ });
706
+ if ((corresponding_prop === null || corresponding_prop === void 0 ? void 0 : corresponding_prop.type) == 'data') {
707
+ const validated = validate_data_value(current.value, corresponding_prop.data_type, corresponding_prop.max_values);
708
+ if (validated.valid) {
709
+ const v = text_data_types.includes(corresponding_prop.data_type) ? `'${validated.output}'` : validated.output;
710
+ obj.columns += `, [user_${corresponding_prop.name}]`;
711
+ obj.values += `, ${v}`;
712
+ }
713
+ else {
714
+ console.log(`Did not modify ${corresponding_prop.name} for item: ${validated.message}`);
715
+ }
716
+ }
717
+ return obj;
718
+ }, {
719
+ columns: '',
720
+ values: ''
721
+ });
697
722
  //get the last item in class table order and use it to get the order for the new item
698
723
  const new_order = this.get_next_order(`[class_${class_name}]`);
699
- this.db.prepare(`INSERT INTO [class_${class_name}] (system_id, system_order) VALUES (${root_id},${new_order})`).run();
724
+ this.db.prepare(`INSERT INTO [class_${class_name}] (system_id, system_order${data_property_sql.columns}) VALUES (${root_id},${new_order}${data_property_sql.values})`).run();
700
725
  return root_id;
701
726
  }
702
727
  get_next_order(table_name) {
@@ -704,15 +729,21 @@ export default class Project {
704
729
  const new_order = last_ordered_item ? last_ordered_item.system_order + 1000 : 0;
705
730
  return new_order;
706
731
  }
707
- // NOTE: seems like there should be a way to pair down "value:any" in params, maybe at least make it one of a few value types
708
- action_set_property_values(class_id, item_id, changes) {
732
+ /**
733
+ * Sets 1 or more data property values for a given class item.
734
+ * @param class_id - class of item
735
+ * @param item_id - id of item
736
+ * @param changes - array of data properties to be set
737
+ */
738
+ action_edit_item_data(class_id, item_id, changes) {
739
+ // NOTE: seems like there should be a way to pair down "value:any" in params, maybe at least make it one of a few value types
709
740
  const class_data = this.lookup_class(class_id);
710
741
  const sql_column_inserts = [];
711
742
  for (let change of changes) {
712
743
  const prop_data = class_data.properties.find((p) => p.id == change.property_id);
713
744
  if (prop_data && prop_data.type == 'data') {
714
745
  // const data_type=prop_data.data_type;
715
- const cell_value = validate(change.value, prop_data.data_type, prop_data.max_values);
746
+ const cell_value = validate_data_value(change.value, prop_data.data_type, prop_data.max_values);
716
747
  if (cell_value.valid) {
717
748
  sql_column_inserts.push({
718
749
  column_name: `[user_${prop_data.name}]`,
@@ -731,47 +762,11 @@ export default class Project {
731
762
  const set_statements = sql_column_inserts.map((p) => `${p.column_name} = ?`).join(',');
732
763
  const insert_statement = `UPDATE [class_${class_data.name}] SET ${set_statements} WHERE system_id=${item_id}`;
733
764
  this.db.prepare(insert_statement).run(params);
734
- function validate(input, data_type, max_values) {
735
- const multiple = max_values == null || max_values > 1;
736
- const values = multiple ? input : [input];
737
- if (!Array.isArray(values)) {
738
- return { valid: false, message: 'Expecting array, got single value' };
739
- }
740
- const validated_values = [];
741
- for (let value of values) {
742
- if (real_data_types.includes(data_type) || integer_data_types.includes(data_type)) {
743
- if (data_type == 'boolean') {
744
- if (typeof value == 'boolean' || [0, 1].includes(value)) {
745
- validated_values.push(+value);
746
- }
747
- else {
748
- return { valid: false, message: `Expecting boolean or binary integer, got "${value}" (${typeof value})` };
749
- }
750
- }
751
- else if (typeof value == 'number') {
752
- validated_values.push(value);
753
- }
754
- else {
755
- return { valid: false, message: `Expecting number, got "${value}" (${typeof value})` };
756
- }
757
- }
758
- else if (text_data_types.includes(data_type)) {
759
- // NOTE: could come back to validate resource as links/filepaths later, but leaving unopinionated for now
760
- if (typeof value == 'string') {
761
- validated_values.push(value);
762
- }
763
- else {
764
- return { valid: false, message: `Expecting string, got "${value}" (${typeof value})` };
765
- }
766
- }
767
- }
768
- const output = multiple ? JSON.stringify(validated_values) : validated_values[0];
769
- return {
770
- valid: true,
771
- output
772
- };
773
- }
774
765
  }
766
+ /**
767
+ * Adds/removes relations between items/item properties
768
+ * @param relations - list of pairs of items for which relations should be added or removed between specified properties
769
+ */
775
770
  action_edit_relations(relations) {
776
771
  // NOTE: changes to make to this in the future:
777
772
  // - 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
@@ -895,8 +890,8 @@ export default class Project {
895
890
  }
896
891
  }
897
892
  let orderby = `ORDER BY ${class_string}.system_order`;
898
- const data_prop_sql_string = data_properties.map((p) => `[user_${p.name}]`).join(',');
899
- const table_selection = pagination.property_range == 'all' ? `[class_${class_name}].*` : `system_id,system_order,${data_prop_sql_string}`;
893
+ const data_prop_sql_string = data_properties.length > 0 ? ', ' + data_properties.map((p) => `[user_${p.name}]`).join(',') : '';
894
+ const table_selection = pagination.property_range == 'all' ? `[class_${class_name}].*` : `system_id,system_order${data_prop_sql_string}`;
900
895
  let filter_by_items = '';
901
896
  if (pagination.item_range && pagination.item_range !== 'all') {
902
897
  filter_by_items = `WHERE system_id in (${pagination.item_range.join(',')})`;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,8 @@
1
- import { JunctionSides, RelationshipSide, MaxValues, RelationshipSideBase, RelationEdit, RelationEditValidSides, ClassData, JunctionList } from "./types.js";
1
+ import { JunctionSides, RelationshipSide, MaxValues, RelationshipSideBase, RelationEdit, RelationEditValidSides, ClassData, JunctionList, DataType } from "./types.js";
2
2
  export declare function defined<T>(v: T): v is NonNullable<T>;
3
+ export declare const text_data_types: string[];
4
+ export declare const integer_data_types: string[];
5
+ export declare const real_data_types: string[];
3
6
  export declare function partial_relation_match(old_relation: JunctionSides, new_relation: JunctionSides): boolean;
4
7
  export declare function side_match(x: RelationshipSide, y: RelationshipSide): boolean;
5
8
  export declare function full_relation_match(a: JunctionSides, b: JunctionSides): boolean;
@@ -11,3 +14,10 @@ export declare function junction_col_name(class_id: number, prop_id: number | un
11
14
  export declare function readable_side(side: RelationshipSide, classlist: ClassData[]): string;
12
15
  export declare function readable_edit(edit: RelationEditValidSides, classlist: ClassData[]): string | undefined;
13
16
  export declare function readable_junctionlist(relationships: JunctionList, classlist: ClassData[]): string[];
17
+ export declare function validate_data_value(input: any, data_type: DataType, max_values: MaxValues): {
18
+ valid: true;
19
+ output: string | number;
20
+ } | {
21
+ valid: false;
22
+ message: string;
23
+ };
package/dist/utils.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export function defined(v) {
2
2
  return v !== undefined && v !== null;
3
3
  }
4
+ export const text_data_types = ['string', 'resource'];
5
+ export const integer_data_types = ['boolean'];
6
+ export const real_data_types = ['number'];
4
7
  // given the type above,
5
8
  // check if two relations share class ids on both sides
6
9
  // and share a property id on at least one side
@@ -103,4 +106,44 @@ export function readable_junctionlist(relationships, classlist) {
103
106
  return readable_sides(r.sides, classlist);
104
107
  });
105
108
  }
109
+ export function validate_data_value(input, data_type, max_values) {
110
+ const multiple = max_values == null || max_values > 1;
111
+ const values = multiple ? input : [input];
112
+ if (!Array.isArray(values)) {
113
+ return { valid: false, message: 'Expecting array, got single value' };
114
+ }
115
+ const validated_values = [];
116
+ for (let value of values) {
117
+ if (real_data_types.includes(data_type) || integer_data_types.includes(data_type)) {
118
+ if (data_type == 'boolean') {
119
+ if (typeof value == 'boolean' || [0, 1].includes(value)) {
120
+ validated_values.push(+value);
121
+ }
122
+ else {
123
+ return { valid: false, message: `Expecting boolean or binary integer, got "${value}" (${typeof value})` };
124
+ }
125
+ }
126
+ else if (typeof value == 'number') {
127
+ validated_values.push(value);
128
+ }
129
+ else {
130
+ return { valid: false, message: `Expecting number, got "${value}" (${typeof value})` };
131
+ }
132
+ }
133
+ else if (text_data_types.includes(data_type)) {
134
+ // NOTE: could come back to validate resource as links/filepaths later, but leaving unopinionated for now
135
+ if (typeof value == 'string') {
136
+ validated_values.push(value);
137
+ }
138
+ else {
139
+ return { valid: false, message: `Expecting string, got "${value}" (${typeof value})` };
140
+ }
141
+ }
142
+ }
143
+ const output = multiple ? JSON.stringify(validated_values) : validated_values[0];
144
+ return {
145
+ valid: true,
146
+ output
147
+ };
148
+ }
106
149
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goby-database",
3
- "version": "2.2.27",
3
+ "version": "2.2.29",
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": [