From 4421da2833b26683a1d0c9960950db8625ab8777 Mon Sep 17 00:00:00 2001 From: Nils Date: Thu, 26 Oct 2023 14:35:07 +0200 Subject: [PATCH] update --- functions/SFmSchema/json/REAMDE.md | 37 +++ .../SFmSchema/json/SFmSChema.json_v1.fmfn | 248 ++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 functions/SFmSchema/json/REAMDE.md create mode 100644 functions/SFmSchema/json/SFmSChema.json_v1.fmfn diff --git a/functions/SFmSchema/json/REAMDE.md b/functions/SFmSchema/json/REAMDE.md new file mode 100644 index 0000000..278d8f2 --- /dev/null +++ b/functions/SFmSchema/json/REAMDE.md @@ -0,0 +1,37 @@ +## SFmSchema.json() Custom Function + +### Parameters + +#### _tables + +This can be used to filter tables in the current file. You can use list of table names and even wildcards. + +Example: providing "Global¶C*" returns the table 'Global' along with all other tables starting with 'C' + +#### _options + +You can provide one or more keywords to specify the output: + +- format: the json output will be formatted +- debug: adds the original outputs from Get( FieldType ) and FileMaker_Fields +- nocache: results are cached in global variable so subsequent calls are significantly faster. For developing or debugging you might want to disable this. +- standard: only standard fields are being returned. Global fields, calculations and summary fields will be excluded from the result. +- stored: like 'standard' but with additional stored calculations. +- comments: includes the field comment from the field definitions. +- nextvalue: includes the next value for auto-incrementing fields like numeric ids. + +### Result + +The result is a json object with the table names as keys. Every table then is an object with can have the following keys: + +- fmType: can either be standard, global, calculation, summary +- dataType: text, number, container, date, time, timestamp +- hasIndex: true if there is an index on the field. False values are omitted. +- id: internal field id +- modCount: number of changes applied to the field's definition +- isStored: only for calculation fields if the value is stored +- repCount: only for repeating fields +- nextValue: optional result from GetNextSerialValue() function. +- comment: comment from field definitions, null values are omitted. +- debugFromFunction: result from Get( FieldType ) function. +- debugFromSql: row from internal FileMaker_Fields table \ No newline at end of file diff --git a/functions/SFmSchema/json/SFmSChema.json_v1.fmfn b/functions/SFmSchema/json/SFmSChema.json_v1.fmfn new file mode 100644 index 0000000..2a06427 --- /dev/null +++ b/functions/SFmSchema/json/SFmSChema.json_v1.fmfn @@ -0,0 +1,248 @@ +/* SFmDatabase.schemaJson( _tables; _options ) + @about output detailled schema info as json + @author Nils Waldherr + @copyright ©2023 FMGARAGE.com + @version 1.0.0-100 - 24.10.2023 - NW: + @param list _tables = "" -- filter table names, use * as wildcard + @param list _options = "" -- format, standard, stored, debug, nocache, comments, nextvalue + @return json +*/ +Case( + + /* return version + ---------------------------------------------------------------------------------- + */ + _tables = "--version" or $_Db.inVersionMode; 1000000; + + + /* preconditions + ---------------------------------------------------------------------------------- + */ + + // empty _param + //IstLeer( _param ); "ERROR: parameter _param must not be empty"; + + + /* main + ---------------------------------------------------------------------------------- + */ + Case( + // write cache + IsEmpty( $$SFmSchema.json ) or Position( _options; "nocache"; 1; 1 ); + Let( + [ + // settings + column_separator = "<<,>>"; + file = GetValue( Substitute( Get( FileName ); " ("; ¶ ); 1 ); + + // filter tables by name using wildcard + _tables = Lower( _tables ); + _tables_count = ValueCount( _tables ); + tables_filter_uses_wildcards = Position( _tables; "*"; 1; 1 ); + tables_filter_wildcards = Case( + tables_filter_uses_wildcards; + While( + [ + tables = ""; + i = 1 + ]; + i <= _tables_count; + [ + table = GetValue( _tables; i ); + tables = List( + tables; + Case( Position( table; "*"; 1; 1 ); Substitute( table; "*"; "%" )) + ); + i=i+1 + ]; + tables + ) + ); + + // filter tables by exact name + tables_filter = Case( + // filter-out wildcards + not IsEmpty( _tables ) and tables_filter_uses_wildcards; + While( + [ + tables = ""; + i = 1 + ]; + i <= _tables_count; + [ + table = GetValue( _tables; i ); + tables = List( + tables; + Case( not Position( table; "*"; 1; 1 ); table ) + ); + i=i+1 + ]; + tables + ); + _tables + ); + table_filter = Substitute( + List( + // tables_filter + Case( + not IsEmpty( tables_filter ); + " lower(TableName) in ('" + & Substitute( tables_filter; ¶; "', '" ) + & "') " + ); + Case( + not IsEmpty( tables_filter_wildcards ); + " lower(TableName) like '" + & Substitute( tables_filter_wildcards; ¶; "' OR lower(TableName) like '" ) + & "' " + ) + ); + "¶"; + " OR " + ); + + // get tables + sql = "select * from FileMaker_Tables where lower(TableName) = lower(BaseTableName) " + & Case( not IsEmpty( table_filter ); " AND ( " & table_filter & " ) " ); + tables = ExecuteSQL( sql; column_separator; ""; file; file & " (%" ); + + + // compose fields sql + + stored_only = Position( _options; "stored"; 1; 1); + + sql = "select * from FileMaker_Fields where TableName = ? " + & Case( + // standard_only + Position( _options; "standard"; 1; 1); + " and FieldClass = 'Normal' and FieldType not like 'global %'"; + + // stored only + stored_only; + " and FieldClass IN ( 'Normal', 'Calculated' ) and FieldType not like 'global %'"; + ); + + + // foreach in tables + json = While( + [ + json = ""; + len = ValueCount( tables ); + i = 1 + ]; + i <= len; + [ + list = Substitute( GetValue( tables; i ); column_separator; "¶" ); + table = GetValue( list; 1 ); + record_count = ExecuteSQL( "select count(*) from \"" & table & "\""; ""; "" ); + json = JSONSetElement( json; + [ table & ".id"; GetValue( list; 2 ); JSONNumber ]; + [ table & ".modCount"; GetValue( list; 5 ); JSONNumber ]; + [ table & ".recordCount"; record_count; JSONNumber ] + ); + + // get fields for table + fields = ExecuteSQL( sql; column_separator; ""; table ); + json = While( + [ + json = json; + i = 1; + len = ValueCount( fields ) + ]; + i <= len; + [ + sql_field = Substitute( GetValue( fields; i ); column_separator; ¶ ); + field = GetValue( sql_field; 2 ); + get_field = Substitute( FieldType( Get( FileName ); table & "::" & field ); " "; ¶ ); + type_fm_pre = Lower( GetValue( get_field; 1 )); + + json = Case( + + // exclude + type_fm_pre = "UnstoredCalc" and stored_only; json; + + // include + Let( + [ + type_fm = Case( type_fm_pre = "UnstoredCalc" or type_fm_pre = "StoredCalc"; "calculation"; type_fm_pre ); + type_data = Lower ( GetValue( get_field; 2 )); + path = table & ".fields." & field & "."; + json = JSONSetElement ( json; + [path & "fmType"; type_fm; JSONString]; + [path & "dataType"; type_data; JSONString]; + [path & "id"; GetValue( sql_field; 4 ); JSONNumber]; + [path & "modCount"; GetValue( sql_field; 7 ); JSONNumber] + ); + // optional values + + // comment + comment = Case( + Position( _options; "comments"; 1; 1 ); + FieldComment( Get( FileName ); table & "::" & field ) + ); + json = Case( + IsEmpty( comment ); json; + JSONSetElement( json; path & "comment"; comment; JSONString ) + ); + // repCount + rep_count = GetValue( sql_field; 6 ); + json = Case( + rep_count = 1; json; + JSONSetElement( json; path & "repCount"; rep_count; JSONNumber ) + ); + // hasIndex + json = Case( + GetValue( get_field; 3 ) <> "Indexed"; json; + JSONSetElement( json; path & "hasIndex"; 1; JSONBoolean ) + ); + // isStored + json = Case( + type_fm_pre <> "StoredCalc"; json; + JSONSetElement( json; path & "isStored"; 1; JSONBoolean ) + ); + // nextValue + next_value = Case( + Position( _options; "nextvalue"; 1; 1 ) and type_fm = "standard"; + GetNextSerialValue ( file; table & "::" & field ) + ); + json = Case( + next_value < 1; json; + JSONSetElement( json; path & "nextValue"; next_value; JSONNumber ) + ); + // debug + json = Case( + not Position( _options; "debug"; 1; 1 ); json; + JSONSetElement( json; + [path & "debugFromFunction"; Substitute( get_field; ¶; " | "); JSONString]; + [path & "debugFromSql"; Substitute( sql_field; ¶; " | "); JSONString] + ) + ) + ]; + json + ) + ); + + // next + i = i+1 + ]; + json + ); + + + + i = i+1 + ]; + json + ); + $$SFmSchema.json = json + ]; + "" + ) + ) + & Case( + Position( _options; "format"; 1; 1 ); + JSONFormatElements( $$SFmSchema.json ); + $$SFmSchema.json + ) +) +