goby-database 2.2.28 → 2.2.30
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 +21 -2
- package/dist/index.js +98 -73
- package/dist/types.d.ts +5 -0
- package/dist/utils.d.ts +11 -1
- package/dist/utils.js +43 -0
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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 = [];
|
|
@@ -17,7 +14,8 @@ export default class Project {
|
|
|
17
14
|
else {
|
|
18
15
|
console.log('opened goby database');
|
|
19
16
|
}
|
|
20
|
-
//prepared statements with arguments so my code isn't as verbose elsewhere
|
|
17
|
+
// prepared statements with arguments so my code isn't as verbose elsewhere
|
|
18
|
+
// obviously can only do this for actions on determinate columns
|
|
21
19
|
this.run = {
|
|
22
20
|
begin: this.db.prepare('BEGIN IMMEDIATE'),
|
|
23
21
|
commit: this.db.prepare('COMMIT'),
|
|
@@ -689,14 +687,42 @@ export default class Project {
|
|
|
689
687
|
throw new Error('Cannot find class in class list.');
|
|
690
688
|
return class_data;
|
|
691
689
|
}
|
|
692
|
-
|
|
690
|
+
/**
|
|
691
|
+
* Creates a new item and adds it to the class you indicate
|
|
692
|
+
* @param class_id - class you want to add new item to
|
|
693
|
+
* @param property_values - any properties you want to fill in as you create this item (data props only for now)
|
|
694
|
+
* @returns - id of new item
|
|
695
|
+
*/
|
|
696
|
+
action_add_row(class_id, property_values = []) {
|
|
693
697
|
const class_data = this.lookup_class(class_id);
|
|
694
698
|
let class_name = class_data.name;
|
|
695
699
|
//first add new row to root and get id
|
|
696
700
|
const root_id = this.create_item_in_root({ type: 'class_' + class_id });
|
|
701
|
+
// NOTE: I will need a second handler in the future if I want to support relation props here
|
|
702
|
+
// (probably utilizing action_edit_relations)
|
|
703
|
+
const data_property_sql = property_values.reduce((obj, current) => {
|
|
704
|
+
const corresponding_prop = class_data.properties.find((prop) => {
|
|
705
|
+
return prop.id == current.property_id;
|
|
706
|
+
});
|
|
707
|
+
if ((corresponding_prop === null || corresponding_prop === void 0 ? void 0 : corresponding_prop.type) == 'data') {
|
|
708
|
+
const validated = validate_data_value(current.value, corresponding_prop.data_type, corresponding_prop.max_values);
|
|
709
|
+
if (validated.valid) {
|
|
710
|
+
const v = text_data_types.includes(corresponding_prop.data_type) ? `'${validated.output}'` : validated.output;
|
|
711
|
+
obj.columns += `, [user_${corresponding_prop.name}]`;
|
|
712
|
+
obj.values += `, ${v}`;
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
console.log(`Did not modify ${corresponding_prop.name} for item: ${validated.message}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return obj;
|
|
719
|
+
}, {
|
|
720
|
+
columns: '',
|
|
721
|
+
values: ''
|
|
722
|
+
});
|
|
697
723
|
//get the last item in class table order and use it to get the order for the new item
|
|
698
724
|
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();
|
|
725
|
+
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
726
|
return root_id;
|
|
701
727
|
}
|
|
702
728
|
get_next_order(table_name) {
|
|
@@ -704,15 +730,21 @@ export default class Project {
|
|
|
704
730
|
const new_order = last_ordered_item ? last_ordered_item.system_order + 1000 : 0;
|
|
705
731
|
return new_order;
|
|
706
732
|
}
|
|
707
|
-
|
|
708
|
-
|
|
733
|
+
/**
|
|
734
|
+
* Sets 1 or more data property values for a given class item.
|
|
735
|
+
* @param class_id - class of item
|
|
736
|
+
* @param item_id - id of item
|
|
737
|
+
* @param changes - array of data properties to be set
|
|
738
|
+
*/
|
|
739
|
+
action_edit_item_data(class_id, item_id, changes) {
|
|
740
|
+
// 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
741
|
const class_data = this.lookup_class(class_id);
|
|
710
742
|
const sql_column_inserts = [];
|
|
711
743
|
for (let change of changes) {
|
|
712
744
|
const prop_data = class_data.properties.find((p) => p.id == change.property_id);
|
|
713
745
|
if (prop_data && prop_data.type == 'data') {
|
|
714
746
|
// const data_type=prop_data.data_type;
|
|
715
|
-
const cell_value =
|
|
747
|
+
const cell_value = validate_data_value(change.value, prop_data.data_type, prop_data.max_values);
|
|
716
748
|
if (cell_value.valid) {
|
|
717
749
|
sql_column_inserts.push({
|
|
718
750
|
column_name: `[user_${prop_data.name}]`,
|
|
@@ -731,47 +763,11 @@ export default class Project {
|
|
|
731
763
|
const set_statements = sql_column_inserts.map((p) => `${p.column_name} = ?`).join(',');
|
|
732
764
|
const insert_statement = `UPDATE [class_${class_data.name}] SET ${set_statements} WHERE system_id=${item_id}`;
|
|
733
765
|
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
766
|
}
|
|
767
|
+
/**
|
|
768
|
+
* Adds/removes relations between items/item properties
|
|
769
|
+
* @param relations - list of pairs of items for which relations should be added or removed between specified properties
|
|
770
|
+
*/
|
|
775
771
|
action_edit_relations(relations) {
|
|
776
772
|
// NOTE: changes to make to this in the future:
|
|
777
773
|
// - 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
|
|
@@ -808,27 +804,29 @@ export default class Project {
|
|
|
808
804
|
}
|
|
809
805
|
// MARKER: modify item retrieval
|
|
810
806
|
retrieve_class_items({ class_id, class_name, class_data, pagination = {} }) {
|
|
807
|
+
// 1. DETERMINE COLUMNS AND ROWS TO RETRIEVE ---------------------------------------------------
|
|
811
808
|
var _a, _b, _c, _d, _e;
|
|
812
809
|
const pagination_defaults = {
|
|
813
810
|
page_size: null,
|
|
814
811
|
property_range: 'all',
|
|
815
|
-
item_range: 'all'
|
|
812
|
+
item_range: 'all',
|
|
813
|
+
conditions: []
|
|
816
814
|
};
|
|
815
|
+
// set pagination rules by overriding defaults with any custom settings
|
|
817
816
|
pagination = Object.assign(Object.assign({}, pagination_defaults), pagination);
|
|
817
|
+
// get class data+name if not already passed in
|
|
818
818
|
if (class_name == undefined || class_data == undefined) {
|
|
819
819
|
class_data = this.lookup_class(class_id);
|
|
820
820
|
class_name = class_data.name;
|
|
821
821
|
}
|
|
822
822
|
;
|
|
823
|
-
|
|
824
|
-
// joined+added at beginning of the query, built from relations
|
|
825
|
-
const cte_strings = [];
|
|
826
|
-
// joined+added near the end of the query, built from relations
|
|
827
|
-
const cte_joins = [];
|
|
828
|
-
// joined+added between SELECT and FROM, built from relations
|
|
829
|
-
const relation_selections = [];
|
|
823
|
+
// gets the label prop for this class
|
|
830
824
|
const label_prop_ids = (_b = (_a = class_data.metadata.label) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : [];
|
|
831
|
-
|
|
825
|
+
const where_conditions = [];
|
|
826
|
+
if (pagination.item_range && pagination.item_range !== 'all') {
|
|
827
|
+
where_conditions.push(`system_id in (${pagination.item_range.join(',')})`);
|
|
828
|
+
}
|
|
829
|
+
// if a property_range is defined, first filter properties retrieved by those IDs
|
|
832
830
|
const retrieved_properties = class_data.properties.filter((prop) => {
|
|
833
831
|
if (pagination.property_range == 'all' || !pagination.property_range) {
|
|
834
832
|
return true;
|
|
@@ -843,22 +841,51 @@ export default class Project {
|
|
|
843
841
|
return true;
|
|
844
842
|
}
|
|
845
843
|
});
|
|
844
|
+
const cte_properties = [];
|
|
845
|
+
for (let condition of (pagination.conditions || [])) {
|
|
846
|
+
if (condition.name == 'under_property_max') {
|
|
847
|
+
const property = class_data.properties.find((p) => p.id == condition.property_id);
|
|
848
|
+
if ((property === null || property === void 0 ? void 0 : property.type) == 'relation' && property.max_values !== null) {
|
|
849
|
+
if (!cte_properties.some((p) => p.id == condition.property_id) && !retrieved_properties.some((p) => p.id == condition.property_id)) {
|
|
850
|
+
// if this property isn’t retrieved directly, we have to make sure a CTE is created for it, just so we can count the values
|
|
851
|
+
cte_properties.push(Object.assign(Object.assign({}, property), { cte_only: true }));
|
|
852
|
+
}
|
|
853
|
+
// add a condition that counts the items selected by this item for this property
|
|
854
|
+
where_conditions.push(`COALESCE([count_user_${property.name}],0) < ${property.max_values}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// separates these, since they are handled separately in the query
|
|
846
859
|
const relation_properties = retrieved_properties.filter(a => a.type == 'relation');
|
|
847
860
|
const data_properties = retrieved_properties.filter(a => a.type == 'data');
|
|
848
|
-
|
|
861
|
+
// 2. GENERATE SQLITE QUERY --------------------------------------------------
|
|
862
|
+
// class table name in db
|
|
863
|
+
const class_string = `[class_${class_name}]`;
|
|
864
|
+
// 2a. Handle relation properties by generating common table expressions (ctes)
|
|
865
|
+
// joined+added at beginning of the query, built from relations
|
|
866
|
+
const cte_strings = [];
|
|
867
|
+
// joined+added near the end of the query, built from relations
|
|
868
|
+
const cte_joins = [];
|
|
869
|
+
// joined+added between SELECT and FROM, built from relations
|
|
870
|
+
const relation_selections = [];
|
|
871
|
+
for (let prop of [...relation_properties, ...cte_properties]) {
|
|
849
872
|
const target_selects = [];
|
|
850
|
-
|
|
873
|
+
// name of column for this class/property in junction table
|
|
874
|
+
const property_junction_column_name = junction_col_name(class_id, prop.id);
|
|
875
|
+
// loop through each target
|
|
851
876
|
if (prop.relation_targets.length > 0) {
|
|
852
877
|
for (let i = 0; i < prop.relation_targets.length; i++) {
|
|
853
878
|
// find the side that does not match both the class and prop IDs
|
|
854
|
-
|
|
879
|
+
const target = prop.relation_targets[i];
|
|
855
880
|
const target_class = this.class_cache.find((a) => a.id == (target === null || target === void 0 ? void 0 : target.class_id));
|
|
856
881
|
if (target && target_class) {
|
|
882
|
+
// target column name in junction table
|
|
857
883
|
let target_junction_column_name = junction_col_name(target.class_id, target.prop_id);
|
|
858
|
-
//
|
|
884
|
+
// get label of label property in target prop
|
|
859
885
|
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];
|
|
860
886
|
const target_label = target_class === null || target_class === void 0 ? void 0 : target_class.properties.find((p) => p.id == target_label_id);
|
|
861
887
|
const label_sql_string = target_label ? `,'user_${target_label.name}',target_class."user_${target_label.name}"` : '';
|
|
888
|
+
// NOTE: as mentioned elsewhere, possibly allow multiple label props
|
|
862
889
|
let junction_id = target.junction_id;
|
|
863
890
|
let target_select = `
|
|
864
891
|
SELECT
|
|
@@ -875,7 +902,7 @@ export default class Project {
|
|
|
875
902
|
}
|
|
876
903
|
// uses built-in aggregate json function instead of group_concat craziness
|
|
877
904
|
const cte = `[${prop.id}_cte] AS (
|
|
878
|
-
SELECT "${property_junction_column_name}", json_group_array( json(target_data) ) AS [user_${prop.name}]
|
|
905
|
+
SELECT "${property_junction_column_name}", json_group_array( json(target_data) ) AS [user_${prop.name}], COUNT(1) AS [count_user_${prop.name}]
|
|
879
906
|
FROM
|
|
880
907
|
(
|
|
881
908
|
${target_selects.join(`
|
|
@@ -887,30 +914,28 @@ export default class Project {
|
|
|
887
914
|
|
|
888
915
|
)`;
|
|
889
916
|
cte_strings.push(cte);
|
|
890
|
-
|
|
917
|
+
if (!("cte_only" in prop && prop.cte_only))
|
|
918
|
+
relation_selections.push(`[${prop.id}_cte].[user_${prop.name}]`);
|
|
891
919
|
cte_joins.push(`LEFT JOIN [${prop.id}_cte] ON [${prop.id}_cte]."${property_junction_column_name}" = ${class_string}.system_id`);
|
|
892
920
|
}
|
|
893
921
|
else {
|
|
894
|
-
|
|
922
|
+
if (!("cte_only" in prop && prop.cte_only))
|
|
923
|
+
relation_selections.push(`'[]' AS [user_${prop.name}]`);
|
|
895
924
|
}
|
|
896
925
|
}
|
|
897
926
|
let orderby = `ORDER BY ${class_string}.system_order`;
|
|
898
927
|
const data_prop_sql_string = data_properties.length > 0 ? ', ' + data_properties.map((p) => `[user_${p.name}]`).join(',') : '';
|
|
899
928
|
const table_selection = pagination.property_range == 'all' ? `[class_${class_name}].*` : `system_id,system_order${data_prop_sql_string}`;
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
filter_by_items = `WHERE system_id in (${pagination.item_range.join(',')})`;
|
|
903
|
-
}
|
|
904
|
-
let comma_break = `,
|
|
929
|
+
const where_string = where_conditions.length > 0 ? `WHERE ${where_conditions.map((w) => `(${w})`).join(' AND ')}` : '';
|
|
930
|
+
const comma_break = `,
|
|
905
931
|
`;
|
|
906
932
|
let query = `
|
|
907
933
|
${cte_strings.length > 0 ? "WITH " + cte_strings.join(comma_break) : ''}
|
|
908
934
|
SELECT ${table_selection} ${relation_selections.length > 0 ? ', ' + relation_selections.join(`, `) : ''}
|
|
909
935
|
FROM [class_${class_name}]
|
|
910
936
|
${cte_joins.join(' ')}
|
|
911
|
-
${
|
|
937
|
+
${where_string}
|
|
912
938
|
${orderby}`;
|
|
913
|
-
console.log('query', query);
|
|
914
939
|
// possibly elaborate this any type a little more in the future, e.g. a CellValue or SQLCellValue type that expects some wildcards
|
|
915
940
|
let items = this.db.prepare(query).all();
|
|
916
941
|
let stringified_properties = class_data.properties.filter(a => a.type == 'relation' || can_have_multiple_values(a.max_values));
|
package/dist/types.d.ts
CHANGED
|
@@ -142,6 +142,10 @@ export type ClassData = {
|
|
|
142
142
|
properties: Property[];
|
|
143
143
|
};
|
|
144
144
|
export type ClassList = ClassData[];
|
|
145
|
+
type ConditionUnderPropertyMax = {
|
|
146
|
+
name: 'under_property_max';
|
|
147
|
+
property_id: number;
|
|
148
|
+
};
|
|
145
149
|
export type ItemPagination = {
|
|
146
150
|
page_size?: number | null;
|
|
147
151
|
page_range?: [start: number, end?: number];
|
|
@@ -149,6 +153,7 @@ export type ItemPagination = {
|
|
|
149
153
|
property_range?: number[] | 'slim' | 'all';
|
|
150
154
|
/** Filter by item IDs. If not specified, pulls all */
|
|
151
155
|
item_range?: number[] | 'all';
|
|
156
|
+
conditions?: ConditionUnderPropertyMax[];
|
|
152
157
|
};
|
|
153
158
|
export type PaginatedItems = ItemPagination & {
|
|
154
159
|
loaded: ClassRow[];
|
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
|