Browse Source

schema generation tweaks, get category metadata

Alexander Rose 6 years ago
parent
commit
f6f3f6dfce

+ 0 - 0
src/apps/schema-generator/schema-from-mmcif-dic.ts → src/apps/schema-generator/schema-from-cif-dic.ts


+ 44 - 3
src/apps/schema-generator/util/cif-dic.ts

@@ -77,7 +77,7 @@ interface FrameData {
 }
 
 // get field from given or linked category
-function getField ( category: string, field: string, d: Data.CifFrame, ctx: FrameData): Data.CifField|undefined {
+function getField (category: string, field: string, d: Data.CifFrame, ctx: FrameData): Data.CifField|undefined {
     const { categories, links } = ctx
 
     const cat = d.categories[category]
@@ -130,6 +130,7 @@ function getSubCategory (d: Data.CifFrame, ctx: FrameData): string|undefined {
 function getDescription (d: Data.CifFrame, ctx: FrameData): string|undefined {
     const value = getField('item_description', 'description', d, ctx)
     if (value) {
+        // trim (after newlines) and remove references to square brackets
         return value.str(0).trim()
             .replace(/(\r\n|\r|\n)([ \t]+)/g, '\n')
             .replace(/(\[[1-3]\])+ element/, 'elements')
@@ -195,6 +196,40 @@ export function generateSchema (frames: CifFrame[]) {
     const links: FrameLinks = {}
     const ctx = { categories, links }
 
+    // get category metadata
+    frames.forEach(d => {
+        if (d.header[0] === '_') return
+        const categoryKeyNames = new Set<string>()
+        const categoryKey = d.categories['category_key']
+        if (categoryKey) {
+            const categoryKey_names = categoryKey.getField('name')
+            if (categoryKey_names) {
+                for (let i = 0, il = categoryKey_names.rowCount; i < il; ++i) {
+                    categoryKeyNames.add(categoryKey_names.str(i))
+                }
+            }
+        }
+        let description = ''
+        const category = d.categories['category']
+        if (category) {
+            const category_description = category.getField('description')
+            if (category_description) {
+                description = category_description.str(0).trim()
+                    .replace(/(\r\n|\r|\n)([ \t]+)/g, '\n') // remove padding after newlines
+            } else {
+                console.log(`no description given for category '${category}'`)
+            }
+        }
+        if (categoryKeyNames.size === 0) {
+            console.log(`no key given for category '${category}'`)
+        }
+        schema[d.header] = { description, key: categoryKeyNames, columns: {} }
+        // console.log('++++++++++++++++++++++++++++++++++++++++++')
+        // console.log('name', d.header)
+        // console.log('desc', description)
+        // console.log('key', categoryKeyNames)
+    })
+
     // build list of links between categories
     frames.forEach(d => {
         if (d.header[0] !== '_') return
@@ -216,6 +251,7 @@ export function generateSchema (frames: CifFrame[]) {
         }
     })
 
+    // get field data
     Object.keys(categories).forEach(fullName => {
         const d = categories[fullName]
         if (!d) {
@@ -226,10 +262,15 @@ export function generateSchema (frames: CifFrame[]) {
         const itemName = d.header.substring(d.header.indexOf('.') + 1)
         let fields: { [k: string]: Column }
         if (categoryName in schema) {
-            fields = schema[categoryName]
+            fields = schema[categoryName].columns
         } else {
+            console.log(`category '${categoryName}' has no metadata`)
             fields = {}
-            schema[categoryName] = fields
+            schema[categoryName] = {
+                description: '',
+                key: new Set(),
+                columns: fields
+            }
         }
 
         const description = getDescription(d, ctx) || ''

+ 42 - 19
src/apps/schema-generator/util/generate.ts

@@ -18,17 +18,7 @@ function header (name: string, info: string, importDatabasePath = 'mol-data/db')
 
 import { Database, Column } from '${importDatabasePath}'
 
-import Schema = Column.Schema
-
-const str = Schema.str;
-const int = Schema.int;
-const float = Schema.float;
-const coord = Schema.coord;
-
-const Aliased = Schema.Aliased;
-const Matrix = Schema.Matrix;
-const Vector = Schema.Vector;
-const List = Schema.List;`
+import Schema = Column.Schema`
 }
 
 function footer (name: string) {
@@ -37,6 +27,32 @@ export type ${name}_Schema = typeof ${name}_Schema;
 export interface ${name}_Database extends Database<${name}_Schema> {}`
 }
 
+function getTypeShorthands(schema: Database, fields?: Filter) {
+    const types = new Set<string>()
+    Object.keys(schema).forEach(table => {
+        if (fields && !fields[table]) return
+        const { columns} = schema[table]
+        Object.keys(columns).forEach(columnName => {
+            if (fields && !fields[table][columnName]) return
+            types.add(schema[table].columns[columnName].type)
+        })
+    })
+    const shorthands: string[] = []
+    types.forEach(type => {
+        switch (type) {
+            case 'str': shorthands.push('const str = Schema.str;'); break
+            case 'int': shorthands.push('const int = Schema.int;'); break
+            case 'float': shorthands.push('const float = Schema.float;'); break
+            case 'coord': shorthands.push('const coord = Schema.coord;'); break
+            case 'enum': shorthands.push('const Aliased = Schema.Aliased;'); break
+            case 'matrix': shorthands.push('const Matrix = Schema.Matrix;'); break
+            case 'vector': shorthands.push('const Vector = Schema.Vector;'); break
+            case 'list': shorthands.push('const List = Schema.List;'); break
+        }
+    })
+    return shorthands.join('\n')
+}
+
 function getTypeDef(c: Column): string {
     switch (c.type) {
         case 'str': return 'str'
@@ -63,27 +79,34 @@ function getTypeDef(c: Column): string {
 const reSafePropertyName = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/
 function safePropertyString(name: string) { return name.match(reSafePropertyName) ? name : `'${name}'` }
 
+function doc(description: string, spacesCount: number) {
+    const spaces = ' '.repeat(spacesCount)
+    return [
+        `${spaces}/**`,
+        `${indentString(description, 1, `${spaces} * `)}`.replace(/ +\n/g, '\n'),
+        `${spaces} */`
+    ].join('\n')
+}
+
 export function generate (name: string, info: string, schema: Database, fields?: Filter, importDatabasePath?: string) {
     const codeLines: string[] = []
 
     codeLines.push(`export const ${name}_Schema = {`)
     Object.keys(schema).forEach(table => {
         if (fields && !fields[table]) return
+        const { description, columns} = schema[table]
+        if (description) codeLines.push(doc(description, 4))
         codeLines.push(`    ${safePropertyString(table)}: {`)
-        const columns = schema[table]
         Object.keys(columns).forEach(columnName => {
             if (fields && !fields[table][columnName]) return
-            const typeDef = getTypeDef(columns[columnName])
-            if (columns[columnName].description) {
-                codeLines.push(`        /**`)
-                codeLines.push(`${indentString(columns[columnName].description, 1, '         * ')}`)
-                codeLines.push(`         */`)
-            }
+            const c = columns[columnName]
+            const typeDef = getTypeDef(c)
+            if (c.description) codeLines.push(doc(c.description, 8))
             codeLines.push(`        ${safePropertyString(columnName)}: ${typeDef},`)
         })
         codeLines.push('    },')
     })
     codeLines.push('}')
 
-    return `${header(name, info, importDatabasePath)}\n\n${codeLines.join('\n')}\n${footer(name)}`
+    return `${header(name, info, importDatabasePath)}\n\n${getTypeShorthands(schema, fields)}\n\n${codeLines.join('\n')}\n${footer(name)}`
 }

+ 5 - 1
src/apps/schema-generator/util/schema.ts

@@ -5,7 +5,11 @@
  */
 
 export interface Database { [ tableName: string ]: Table }
-export interface Table { [ columnName: string ]: Column }
+export interface Table {
+    description: string
+    key: Set<string>
+    columns: { [ columnName: string ]: Column }
+}
 export type Column = IntCol | StrCol | FloatCol | CoordCol | EnumCol | VectorCol | MatrixCol | ListCol
 
 type BaseCol = { description: string }