Skip to content

Commit 2b93f08

Browse files
authored
Merge pull request #43 from funktechno/f/updates
F/updates improved openapi spec support
2 parents 63ffbd1 + a506b1b commit 2b93f08

File tree

11 files changed

+1838
-858
lines changed

11 files changed

+1838
-858
lines changed

dist/nosql-ts.js

Lines changed: 632 additions & 325 deletions
Large diffs are not rendered by default.

dist/nosql-ts.min.js

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/nosql.js

Lines changed: 631 additions & 307 deletions
Large diffs are not rendered by default.

dist/nosql.min.js

Lines changed: 25 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/sql.js

Lines changed: 318 additions & 164 deletions
Large diffs are not rendered by default.

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default [
99
files: ["**/*.{js,mjs,cjs,ts}"],
1010
rules: {
1111
semi: ["error", "always"],
12-
quotes: ["error", "double"],
12+
quotes: ["off", "double"],
1313
"@typescript-eslint/explicit-function-return-type": "off",
1414
"@typescript-eslint/camelcase": "off",
1515
"@typescript-eslint/no-unsafe-function-type": "off",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sqltooling-drawio",
3-
"version": "0.0.5",
3+
"version": "0.0.6",
44
"description": "plugins for sql tooling in drawio",
55
"main": "index.js",
66
"engines": {

src/utils/constants-nosql.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { pluginVersion } from "./constants";
2+
import { JSONSchema4TypeName } from "json-schema";
23

34
export const defaultReset = `/*\n\tDrawio default value\n\tPlugin: nosql\n\tVersion: ${pluginVersion}\n*/\n\n
45
export interface WeatherForecast {
@@ -88,4 +89,17 @@ export const defaultResetOpenApi = `
8889
}
8990
}
9091
}
91-
`;
92+
`;
93+
94+
const JSONSchemaTypes:JSONSchema4TypeName[] = [
95+
"string",
96+
"number",
97+
"integer",
98+
"boolean",
99+
"object",
100+
"array",
101+
"null",
102+
"any"
103+
];
104+
105+
export const validJSONSchemaTypes:string[] = JSONSchemaTypes;

src/utils/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,3 @@ export const nullableKeyword = "nullable";
1717
export const arrayKeyword = "array";
1818

1919
export const objectKeyword = "object";
20-
21-
export const validEnumTypes = ["string", "number", "integer", "boolean"];

src/utils/nosqlUtils.ts

Lines changed: 113 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
nullableKeyword,
1212
objectKeyword,
1313
pluginVersion,
14-
validEnumTypes,
1514
} from "./constants";
1615
import { JSONSchema4, JSONSchema4TypeName } from "json-schema";
1716
import {
@@ -24,13 +23,15 @@ import {
2423
GetColumnQuantifiers,
2524
getCommentIndexes,
2625
getDbLabel,
26+
RemoveNameQuantifiers,
2727
} from "./sharedUtils";
2828
import {
2929
DatabaseModel,
3030
ForeignKeyModel,
3131
PropertyModel,
3232
TableModel,
3333
} from "@funktechno/sqlsimpleparser/lib/types";
34+
import { validJSONSchemaTypes } from "./constants-nosql";
3435

3536
/**
3637
* convert db to openapi
@@ -58,14 +59,14 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
5859
let schemaKey = key;
5960
const entity = entities[key];
6061
let commentIndexes = getCommentIndexes(key);
61-
let description = "";
62+
let schemaDescription = "";
6263
let formatValue = "";
6364
if (commentIndexes.start > -1 && commentIndexes.end > -1) {
6465
let result = schemaKey.toString().trim();
6566
commentIndexes = getCommentIndexes(result);
6667
const firstSpaceIndex = commentIndexes.start;
6768
const lastSpaceIndex = commentIndexes.end;
68-
schemaKey = result.substring(0, commentIndexes.beforeStart);
69+
schemaKey = result.substring(0, commentIndexes.beforeStart).trim();
6970
result = result.substring(firstSpaceIndex, lastSpaceIndex).trim();
7071
if (result.indexOf(formatKeyword) !== -1) {
7172
const formatIndex = result.indexOf(formatKeyword);
@@ -75,7 +76,7 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
7576
result = result.substring(0, formatIndex);
7677
}
7778
if (result) {
78-
description = result;
79+
schemaDescription = result;
7980
}
8081
}
8182
if (schema[schemaKey]) {
@@ -87,8 +88,8 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
8788
additionalProperties: false,
8889
properties: {},
8990
};
90-
if (description) {
91-
schema[schemaKey].description = description.trim();
91+
if (schemaDescription) {
92+
schema[schemaKey].description = schemaDescription.trim();
9293
}
9394
if (formatValue) {
9495
schema[schemaKey].format = formatValue.trim();
@@ -108,26 +109,26 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
108109
const splitPropName = propName.split(" ");
109110
if (
110111
splitPropName.length == 2 &&
111-
validEnumTypes.indexOf(splitPropName[0]) !== -1 &&
112+
validJSONSchemaTypes.indexOf(splitPropName[0]) !== -1 &&
112113
splitPropName[1] == enumKeyword
113114
) {
114115
isEnum = true;
115116
type = splitPropName[0] as JSONSchema4TypeName;
116117
}
117118
}
118119
// extract desciption /** asdf */
119-
let description = "";
120+
let propertyDescription = "";
120121
let formatValue = "";
121122
let enumValues: any[] | null = null;
122123
if (
123124
attribute.attributeType?.includes(commentColumnQuantifiers.Start) &&
124125
attribute.attributeType?.includes(commentColumnQuantifiers.End)
125126
) {
126-
let result = attribute.attributeType;
127-
const commentIndexes = getCommentIndexes(result);
127+
let attributeTypeResult = attribute.attributeType;
128+
const commentIndexes = getCommentIndexes(attributeTypeResult);
128129
const firstSpaceIndex = commentIndexes.start;
129130
const lastSpaceIndex = commentIndexes.end;
130-
const enumRaw = result
131+
const enumRaw = attributeTypeResult
131132
.substring(0, commentIndexes.beforeStart)
132133
.trim();
133134
if (enumRaw) {
@@ -141,16 +142,16 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
141142
);
142143
}
143144
}
144-
result = result.substring(firstSpaceIndex, lastSpaceIndex);
145-
if (result.indexOf(formatKeyword) !== -1) {
146-
const formatIndex = result.indexOf(formatKeyword);
147-
formatValue = result
145+
attributeTypeResult = attributeTypeResult.substring(firstSpaceIndex, lastSpaceIndex);
146+
if (attributeTypeResult.indexOf(formatKeyword) !== -1) {
147+
const formatIndex = attributeTypeResult.indexOf(formatKeyword);
148+
formatValue = attributeTypeResult
148149
.substring(formatIndex + formatKeyword.length)
149150
.trim();
150-
result = result.substring(0, formatIndex);
151+
attributeTypeResult = attributeTypeResult.substring(0, formatIndex);
151152
}
152-
if (result) {
153-
description = result;
153+
if (attributeTypeResult.trim()) {
154+
propertyDescription = attributeTypeResult.trim();
154155
}
155156

156157
// decription = attribute.attributeType?.replace("/**", "").replace("*/", "");
@@ -160,24 +161,92 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
160161
if (enumValues) {
161162
schema[schemaKey].enum = enumValues;
162163
}
163-
if (description) {
164-
schema[schemaKey].description = description.trim();
164+
if (propertyDescription.trim()) {
165+
schema[schemaKey].description = propertyDescription.trim();
165166
}
166-
if (formatValue) {
167+
if (formatValue.trim()) {
167168
schema[schemaKey].format = formatValue.trim();
168169
}
169170
schema[schemaKey].type = type;
170171
} else {
172+
// check if type is jsonschema type
173+
let $ref = null;
174+
let removeType = false;
175+
let items: JSONSchema4 | null = null;
176+
let additionalProperties: JSONSchema4 | null = null;
177+
if (validJSONSchemaTypes.indexOf(type) === -1) {
178+
if (type.indexOf("[]") != -1) {
179+
const itemsType = type.replace("[]", "") as JSONSchema4TypeName;
180+
if (validJSONSchemaTypes.indexOf(itemsType) != -1) {
181+
items = {
182+
type: itemsType,
183+
};
184+
type = "array";
185+
}
186+
}
187+
188+
if (validJSONSchemaTypes.indexOf(type) != -1) {
189+
//
190+
} else {
191+
// else {
192+
removeType = true;
193+
$ref = `#/components/schemas/${RemoveNameQuantifiers(type)}`;
194+
}
195+
}
196+
if(["array", "object"].indexOf(type) !== -1) {
197+
const relationships = db.getRelationships().filter(x=> x.entityA == key);
198+
const roleLookup = `[${key}.${propName}]`;
199+
// FIND MATCH
200+
const rel = relationships.find(x => x.roleA.indexOf(roleLookup) != -1);
201+
if(rel) {
202+
const commentFKIndexes = getCommentIndexes(rel.entityB);
203+
const entityBName = rel.entityB.substring(0, commentFKIndexes.beforeStart).trim();
204+
$ref = `#/components/schemas/${entityBName}`;
205+
}
206+
if($ref) {
207+
// if array additionalProperties.$ref
208+
if(type == "array") {
209+
items = {
210+
$ref: $ref
211+
};
212+
}
213+
// if object items.$ref
214+
if(type == "object") {
215+
additionalProperties = {
216+
$ref: $ref
217+
};
218+
}
219+
}
220+
}
221+
171222
const property: JSONSchema4 = {
172223
title: `${schemaKey}.${propName}`,
173-
nullable: attribute.attributeType?.includes("nullable") ?? false,
174224
type: type,
175225
};
176-
if (description) {
177-
property.description = description.trim();
226+
if(additionalProperties) {
227+
property.additionalProperties = additionalProperties;
228+
}
229+
if (items) {
230+
property.items = items;
178231
}
179-
if (formatValue) {
180-
property.format = formatValue.trim();
232+
if (attribute.attributeType?.includes("nullable")) {
233+
property.nullable = true;
234+
}
235+
if ($ref && !additionalProperties?.$ref && !items?.$ref) {
236+
property["$ref"] = $ref;
237+
}
238+
if (removeType) {
239+
delete property.type;
240+
}
241+
// $ref properties don't have descriptions
242+
if (propertyDescription.trim() && !$ref) {
243+
// TODO: pull from proper location
244+
property.description = propertyDescription.trim();
245+
}
246+
if (formatValue.trim()) {
247+
if (property.items) {
248+
(property.items as JSONSchema4).format = formatValue.trim();
249+
} else property.format = formatValue.trim();
181250
}
182251
schema[schemaKey].properties[attribute.attributeName!] = property;
183252
}
@@ -191,7 +260,13 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
191260
return result;
192261
}
193262

194-
// TODO: may need to make recursive for when schema property items is array
263+
/**
264+
* used in uml generation
265+
* @param tableName
266+
* @param propertyName
267+
* @param property
268+
* @returns
269+
*/
195270
export function GeneratePropertyModel(
196271
tableName: string,
197272
propertyName: string,
@@ -200,9 +275,12 @@ export function GeneratePropertyModel(
200275
let columnProperties = (property.type ?? objectKeyword).toString();
201276
if (columnProperties === arrayKeyword) {
202277
if (property.items && typeof property.items === objectKeyword) {
203-
if ((property.items as JSONSchema4).format)
204-
columnProperties = `${(property.items as JSONSchema4).format}[]`;
205-
else if ((property.items as JSONSchema4).type)
278+
if ((property.items as JSONSchema4).format && !property.format) {
279+
property.format = (property.items as JSONSchema4).format;
280+
// columnProperties = `${(property.items as JSONSchema4).format}[]`;
281+
}
282+
// else
283+
if ((property.items as JSONSchema4).type)
206284
columnProperties = `${(property.items as JSONSchema4).type}[]`;
207285
}
208286
}
@@ -225,7 +303,11 @@ export function GeneratePropertyModel(
225303
};
226304
return result;
227305
}
228-
306+
/**
307+
* convert openapi schema to database model
308+
* @param schemas
309+
* @returns
310+
*/
229311
export function ConvertOpenApiToDatabaseModel(
230312
schemas: Record<string, OpenApiSchemaTypeDefinition>
231313
): DatabaseModel {

0 commit comments

Comments
 (0)