tina4-nodejs 3.8.3 → 3.8.5
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/README.md +11 -11
- package/package.json +2 -4
- package/packages/core/src/ai.ts +1 -1
- package/packages/core/src/response.ts +9 -26
- package/packages/core/src/server.ts +11 -12
- package/packages/core/src/sessionHandlers/databaseHandler.ts +3 -12
- package/packages/frond/src/engine.ts +2 -0
- package/packages/orm/src/adapters/sqlite.ts +38 -92
package/README.md
CHANGED
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
Laravel joy. TypeScript speed. 10x less code. Zero third-party dependencies.
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/tina4-nodejs"><img src="https://img.shields.io/npm/v/tina4-nodejs?color=7b1fa2&label=npm" alt="npm"></a>
|
|
14
|
+
<img src="https://img.shields.io/badge/tests-1%2C812%20passing-brightgreen" alt="Tests">
|
|
15
|
+
<img src="https://img.shields.io/badge/features-38-blue" alt="Features">
|
|
16
|
+
<img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="Zero Deps">
|
|
17
|
+
<a href="https://tina4.com"><img src="https://img.shields.io/badge/docs-tina4.com-7b1fa2" alt="Docs"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
12
20
|
<p align="center">
|
|
13
21
|
<a href="https://tina4.com">Documentation</a> •
|
|
14
22
|
<a href="#getting-started">Getting Started</a> •
|
|
@@ -17,14 +25,6 @@
|
|
|
17
25
|
<a href="https://tina4.com">tina4.com</a>
|
|
18
26
|
</p>
|
|
19
27
|
|
|
20
|
-
<p align="center">
|
|
21
|
-
<img src="https://img.shields.io/badge/tests-1669%20passing-brightgreen" alt="Tests">
|
|
22
|
-
<img src="https://img.shields.io/badge/carbonah-A%2B%20rated-00cc44" alt="Carbonah A+">
|
|
23
|
-
<img src="https://img.shields.io/badge/zero--dep-core-blue" alt="Zero Dependencies">
|
|
24
|
-
<img src="https://img.shields.io/badge/node-20%2B-blue" alt="Node 20+">
|
|
25
|
-
<img src="https://img.shields.io/badge/license-MIT-lightgrey" alt="MIT License">
|
|
26
|
-
</p>
|
|
27
|
-
|
|
28
28
|
---
|
|
29
29
|
|
|
30
30
|
## Quick Start
|
|
@@ -84,8 +84,8 @@ Every feature is built from scratch -- no npm install, no node_modules bloat, no
|
|
|
84
84
|
| **Templates** | Frond engine (Twig-compatible), inheritance, partials, 53+ filters, macros, fragment caching, sandboxing |
|
|
85
85
|
| **ORM** | Active Record, typed fields with validation, soft delete, relationships (`hasOne`/`hasMany`/`belongsTo`), scopes, result caching, auto-CRUD |
|
|
86
86
|
| **Database** | SQLite, PostgreSQL, MySQL, MSSQL/SQL Server, Firebird -- unified adapter interface, query caching (TINA4_DB_CACHE=true for 4x speedup) |
|
|
87
|
-
| **Auth** | Zero-dep JWT (HS256
|
|
88
|
-
| **API** | Swagger/OpenAPI auto-generation, GraphQL with schema
|
|
87
|
+
| **Auth** | Zero-dep JWT (HS256/RS256), sessions (file/Redis/Valkey/MongoDB/database), password hashing, form tokens |
|
|
88
|
+
| **API** | Swagger/OpenAPI auto-generation, GraphQL with ORM auto-schema and GraphiQL IDE, WSDL/SOAP with auto WSDL |
|
|
89
89
|
| **Background** | Queue (SQLite/RabbitMQ/Kafka/MongoDB) with priority, delayed jobs, retry, batch processing |
|
|
90
90
|
| **Real-time** | Native WebSocket (RFC 6455), per-path routing, connection manager, broadcast |
|
|
91
91
|
| **Frontend** | tina4-css (~24 KB), frond.js helper, SCSS compiler, live reload, CSS hot-reload |
|
|
@@ -93,7 +93,7 @@ Every feature is built from scratch -- no npm install, no node_modules bloat, no
|
|
|
93
93
|
| **Data** | Migrations with rollback, 26+ fake data generators, ORM and table seeders |
|
|
94
94
|
| **Other** | Service runner, localization (i18n), cache (memory/Redis/file), messenger (.env driven), HTTP constants, health check, configurable error pages |
|
|
95
95
|
|
|
96
|
-
**1,
|
|
96
|
+
**1,812 tests across 38 built-in features. Zero dependencies. All Carbonah benchmarks rated A+.**
|
|
97
97
|
|
|
98
98
|
For full documentation visit **[tina4.com](https://tina4.com)**.
|
|
99
99
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tina4-nodejs",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "This is not a framework. Tina4 for Node.js/TypeScript — zero deps, 38 built-in features.",
|
|
6
6
|
"keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
|
|
@@ -49,9 +49,7 @@
|
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=20.0.0"
|
|
51
51
|
},
|
|
52
|
-
"dependencies": {
|
|
53
|
-
"better-sqlite3": "^11.0.0"
|
|
54
|
-
},
|
|
52
|
+
"dependencies": {},
|
|
55
53
|
"devDependencies": {
|
|
56
54
|
"typescript": "^5.7.0",
|
|
57
55
|
"tsx": "^4.19.0",
|
package/packages/core/src/ai.ts
CHANGED
|
@@ -170,7 +170,7 @@ test/ — Test files
|
|
|
170
170
|
| Routing | router | \`import { get, post, put, del } from "@tina4/core"\` |
|
|
171
171
|
| ORM | orm | \`import { BaseModel } from "@tina4/orm"\` |
|
|
172
172
|
| Database | database | \`import { initDatabase } from "@tina4/orm"\` |
|
|
173
|
-
| Templates | twig | \`import { renderTemplate } from "@tina4/
|
|
173
|
+
| Templates | twig | \`import { renderTemplate } from "@tina4/frond"\` |
|
|
174
174
|
| JWT Auth | auth | \`import { createToken, validateToken } from "@tina4/core"\` |
|
|
175
175
|
| REST API Client | api | \`import { Api } from "@tina4/core"\` |
|
|
176
176
|
| GraphQL | graphql | \`import { GraphQL } from "@tina4/core"\` |
|
|
@@ -161,36 +161,19 @@ export function createResponse(res: ServerResponse): Tina4Response {
|
|
|
161
161
|
return response;
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
error: "Template rendering failed",
|
|
173
|
-
statusCode: 500,
|
|
174
|
-
message: String(err),
|
|
175
|
-
});
|
|
176
|
-
}
|
|
164
|
+
// Default render/template stubs — overwritten by server.ts when Frond is available
|
|
165
|
+
response.render = async function (templateName: string, _data?: Record<string, unknown>): Promise<Tina4Response> {
|
|
166
|
+
res.statusCode = 500;
|
|
167
|
+
response.json({
|
|
168
|
+
error: "Template engine not available",
|
|
169
|
+
statusCode: 500,
|
|
170
|
+
message: "Frond template engine is not initialized. Ensure @tina4/frond is installed.",
|
|
171
|
+
});
|
|
177
172
|
return response;
|
|
178
173
|
};
|
|
179
174
|
|
|
180
175
|
response.template = async function (name: string, data?: Record<string, unknown>): Promise<Tina4Response> {
|
|
181
|
-
|
|
182
|
-
const twig = await import("@tina4/twig");
|
|
183
|
-
const html = await twig.renderTemplate(name, data);
|
|
184
|
-
response.html(html);
|
|
185
|
-
} catch (err) {
|
|
186
|
-
res.statusCode = 500;
|
|
187
|
-
response.json({
|
|
188
|
-
error: "Template rendering failed",
|
|
189
|
-
statusCode: 500,
|
|
190
|
-
message: String(err),
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
return response;
|
|
176
|
+
return response.render(name, data);
|
|
194
177
|
};
|
|
195
178
|
|
|
196
179
|
return response;
|
|
@@ -446,14 +446,13 @@ ${reset}
|
|
|
446
446
|
const healthRoute = createHealthRoute(TINA4_VERSION);
|
|
447
447
|
router.addRoute(healthRoute);
|
|
448
448
|
|
|
449
|
-
// Initialize
|
|
450
|
-
let
|
|
449
|
+
// Initialize Frond template engine
|
|
450
|
+
let frondEngine: any = null;
|
|
451
451
|
try {
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
twigAvailable = true;
|
|
452
|
+
const { Frond } = await import("@tina4/frond");
|
|
453
|
+
frondEngine = new Frond(templatesDir);
|
|
455
454
|
} catch {
|
|
456
|
-
//
|
|
455
|
+
// Frond not available
|
|
457
456
|
}
|
|
458
457
|
|
|
459
458
|
// Built-in middleware
|
|
@@ -569,12 +568,12 @@ ${reset}
|
|
|
569
568
|
const req = createRequest(rawReq);
|
|
570
569
|
const res = createResponse(rawRes);
|
|
571
570
|
|
|
572
|
-
// Add res.render() if
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
}
|
|
571
|
+
// Add res.render() if Frond is available
|
|
572
|
+
if (frondEngine) {
|
|
573
|
+
res.render = (template: string, data?: Record<string, unknown>, statusCode?: number) => {
|
|
574
|
+
const html = frondEngine.render(template, data);
|
|
575
|
+
return res.html(html, statusCode ?? 200);
|
|
576
|
+
};
|
|
578
577
|
}
|
|
579
578
|
|
|
580
579
|
try {
|
|
@@ -39,18 +39,9 @@ export class DatabaseSessionHandler implements SessionHandler {
|
|
|
39
39
|
constructor(config?: DatabaseSessionConfig) {
|
|
40
40
|
const dbPath = config?.dbPath ?? this.resolveDbPath();
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} catch {
|
|
46
|
-
throw new Error(
|
|
47
|
-
"DatabaseSessionHandler requires 'better-sqlite3'. " +
|
|
48
|
-
"Install it with: npm install better-sqlite3"
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.db = new Database(dbPath);
|
|
53
|
-
this.db.pragma("journal_mode = WAL");
|
|
42
|
+
const { DatabaseSync } = require("node:sqlite");
|
|
43
|
+
this.db = new DatabaseSync(dbPath);
|
|
44
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
54
45
|
}
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -848,6 +848,8 @@ export class Frond {
|
|
|
848
848
|
/** Token pre-compilation cache for string templates */
|
|
849
849
|
private compiledStrings = new Map<string, Token[]>();
|
|
850
850
|
|
|
851
|
+
getTemplateDir(): string { return this.templateDir; }
|
|
852
|
+
|
|
851
853
|
constructor(templateDir: string = "src/templates") {
|
|
852
854
|
this.templateDir = resolve(templateDir);
|
|
853
855
|
this.filters = { ...BUILTIN_FILTERS };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import { mkdirSync } from "node:fs";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import type { DatabaseAdapter, DatabaseResult, ColumnInfo, FieldDefinition } from "../types.js";
|
|
5
5
|
|
|
6
6
|
export class SQLiteAdapter implements DatabaseAdapter {
|
|
7
|
-
private db:
|
|
7
|
+
private db: DatabaseSync;
|
|
8
8
|
private _lastInsertId: number | bigint | null = null;
|
|
9
9
|
|
|
10
10
|
constructor(dbPath: string) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.db = new
|
|
15
|
-
this.db.
|
|
16
|
-
this.db.
|
|
11
|
+
if (dbPath !== ":memory:") {
|
|
12
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
this.db = new DatabaseSync(dbPath);
|
|
15
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
16
|
+
this.db.exec("PRAGMA foreign_keys = ON");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
execute(sql: string, params?: unknown[]): unknown {
|
|
@@ -30,8 +30,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
30
30
|
let totalAffected = 0;
|
|
31
31
|
let lastId: number | bigint | undefined;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
this.db.exec("BEGIN TRANSACTION");
|
|
34
|
+
try {
|
|
35
|
+
for (const params of paramsList) {
|
|
35
36
|
const result = stmt.run(...params);
|
|
36
37
|
totalAffected += result.changes;
|
|
37
38
|
if (result.lastInsertRowid) {
|
|
@@ -39,9 +40,12 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
39
40
|
this._lastInsertId = result.lastInsertRowid;
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
this.db.exec("COMMIT");
|
|
44
|
+
} catch (e) {
|
|
45
|
+
this.db.exec("ROLLBACK");
|
|
46
|
+
throw e;
|
|
47
|
+
}
|
|
43
48
|
|
|
44
|
-
runMany(paramsList);
|
|
45
49
|
return { totalAffected, lastInsertId: lastId };
|
|
46
50
|
}
|
|
47
51
|
|
|
@@ -68,7 +72,6 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
insert(table: string, data: Record<string, unknown> | Record<string, unknown>[]): DatabaseResult {
|
|
71
|
-
// Handle list of rows — batch insert
|
|
72
75
|
if (Array.isArray(data)) {
|
|
73
76
|
if (data.length === 0) return { success: true, rowsAffected: 0 };
|
|
74
77
|
const keys = Object.keys(data[0]);
|
|
@@ -87,17 +90,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
87
90
|
try {
|
|
88
91
|
const result = this.db.prepare(sql).run(...values);
|
|
89
92
|
this._lastInsertId = result.lastInsertRowid;
|
|
90
|
-
return {
|
|
91
|
-
success: true,
|
|
92
|
-
rowsAffected: result.changes,
|
|
93
|
-
lastInsertId: result.lastInsertRowid,
|
|
94
|
-
};
|
|
93
|
+
return { success: true, rowsAffected: result.changes, lastInsertId: result.lastInsertRowid };
|
|
95
94
|
} catch (e) {
|
|
96
|
-
return {
|
|
97
|
-
success: false,
|
|
98
|
-
rowsAffected: 0,
|
|
99
|
-
error: (e as Error).message,
|
|
100
|
-
};
|
|
95
|
+
return { success: false, rowsAffected: 0, error: (e as Error).message };
|
|
101
96
|
}
|
|
102
97
|
}
|
|
103
98
|
|
|
@@ -116,7 +111,6 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
116
111
|
}
|
|
117
112
|
|
|
118
113
|
delete(table: string, filter: Record<string, unknown> | string | Record<string, unknown>[]): DatabaseResult {
|
|
119
|
-
// Array of objects — delete each row
|
|
120
114
|
if (Array.isArray(filter)) {
|
|
121
115
|
let totalAffected = 0;
|
|
122
116
|
for (const row of filter) {
|
|
@@ -126,7 +120,6 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
126
120
|
return { success: true, rowsAffected: totalAffected };
|
|
127
121
|
}
|
|
128
122
|
|
|
129
|
-
// String filter — raw WHERE clause
|
|
130
123
|
if (typeof filter === "string") {
|
|
131
124
|
const sql = filter ? `DELETE FROM "${table}" WHERE ${filter}` : `DELETE FROM "${table}"`;
|
|
132
125
|
try {
|
|
@@ -137,7 +130,6 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
137
130
|
}
|
|
138
131
|
}
|
|
139
132
|
|
|
140
|
-
// Object filter — build WHERE from keys
|
|
141
133
|
const whereClauses = Object.keys(filter).map((k) => `"${k}" = ?`).join(" AND ");
|
|
142
134
|
const sql = `DELETE FROM "${table}" WHERE ${whereClauses}`;
|
|
143
135
|
const values = Object.values(filter);
|
|
@@ -150,17 +142,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
150
142
|
}
|
|
151
143
|
}
|
|
152
144
|
|
|
153
|
-
startTransaction(): void {
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
commit(): void {
|
|
158
|
-
this.db.exec("COMMIT");
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
rollback(): void {
|
|
162
|
-
this.db.exec("ROLLBACK");
|
|
163
|
-
}
|
|
145
|
+
startTransaction(): void { this.db.exec("BEGIN TRANSACTION"); }
|
|
146
|
+
commit(): void { this.db.exec("COMMIT"); }
|
|
147
|
+
rollback(): void { this.db.exec("ROLLBACK"); }
|
|
164
148
|
|
|
165
149
|
tables(): string[] {
|
|
166
150
|
const rows = this.query<{ name: string }>(
|
|
@@ -171,95 +155,57 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
171
155
|
|
|
172
156
|
columns(table: string): ColumnInfo[] {
|
|
173
157
|
const rows = this.db.prepare(`PRAGMA table_info("${table}")`).all() as Array<{
|
|
174
|
-
name: string;
|
|
175
|
-
type: string;
|
|
176
|
-
notnull: number;
|
|
177
|
-
dflt_value: unknown;
|
|
178
|
-
pk: number;
|
|
158
|
+
name: string; type: string; notnull: number; dflt_value: unknown; pk: number;
|
|
179
159
|
}>;
|
|
180
160
|
return rows.map((r) => ({
|
|
181
|
-
name: r.name,
|
|
182
|
-
type: r.type,
|
|
183
|
-
nullable: r.notnull === 0,
|
|
184
|
-
default: r.dflt_value,
|
|
185
|
-
primaryKey: r.pk === 1,
|
|
161
|
+
name: r.name, type: r.type, nullable: r.notnull === 0, default: r.dflt_value, primaryKey: r.pk === 1,
|
|
186
162
|
}));
|
|
187
163
|
}
|
|
188
164
|
|
|
189
|
-
lastInsertId(): number | bigint | null {
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
close(): void {
|
|
194
|
-
this.db.close();
|
|
195
|
-
}
|
|
165
|
+
lastInsertId(): number | bigint | null { return this._lastInsertId; }
|
|
166
|
+
close(): void { this.db.close(); }
|
|
196
167
|
|
|
197
168
|
tableExists(name: string): boolean {
|
|
198
|
-
const result = this.db
|
|
199
|
-
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?")
|
|
200
|
-
.get(name);
|
|
169
|
+
const result = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(name);
|
|
201
170
|
return !!result;
|
|
202
171
|
}
|
|
203
172
|
|
|
204
173
|
createTable(name: string, columns: Record<string, FieldDefinition>): void {
|
|
205
174
|
const colDefs: string[] = [];
|
|
206
|
-
|
|
207
175
|
for (const [colName, def] of Object.entries(columns)) {
|
|
208
176
|
const sqlType = fieldTypeToSQLite(def.type);
|
|
209
177
|
const parts = [`"${colName}" ${sqlType}`];
|
|
210
|
-
|
|
211
178
|
if (def.primaryKey) parts.push("PRIMARY KEY");
|
|
212
179
|
if (def.autoIncrement) parts.push("AUTOINCREMENT");
|
|
213
180
|
if (def.required && !def.primaryKey) parts.push("NOT NULL");
|
|
214
|
-
if (def.default !== undefined && def.default !== "now") {
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
if (def.default === "now") {
|
|
218
|
-
parts.push("DEFAULT CURRENT_TIMESTAMP");
|
|
219
|
-
}
|
|
220
|
-
|
|
181
|
+
if (def.default !== undefined && def.default !== "now") parts.push(`DEFAULT ${sqlDefault(def.default)}`);
|
|
182
|
+
if (def.default === "now") parts.push("DEFAULT CURRENT_TIMESTAMP");
|
|
221
183
|
colDefs.push(parts.join(" "));
|
|
222
184
|
}
|
|
223
|
-
|
|
224
|
-
const sql = `CREATE TABLE IF NOT EXISTS "${name}" (${colDefs.join(", ")})`;
|
|
225
|
-
this.db.exec(sql);
|
|
185
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS "${name}" (${colDefs.join(", ")})`);
|
|
226
186
|
}
|
|
227
187
|
|
|
228
188
|
getTableColumns(name: string): Array<{ name: string; type: string }> {
|
|
229
|
-
return this.db.prepare(`PRAGMA table_info("${name}")`).all() as Array<{
|
|
230
|
-
name: string;
|
|
231
|
-
type: string;
|
|
232
|
-
}>;
|
|
189
|
+
return this.db.prepare(`PRAGMA table_info("${name}")`).all() as Array<{ name: string; type: string }>;
|
|
233
190
|
}
|
|
234
191
|
|
|
235
192
|
addColumn(table: string, colName: string, def: FieldDefinition): void {
|
|
236
193
|
const sqlType = fieldTypeToSQLite(def.type);
|
|
237
194
|
let sql = `ALTER TABLE "${table}" ADD COLUMN "${colName}" ${sqlType}`;
|
|
238
|
-
if (def.default !== undefined && def.default !== "now") {
|
|
239
|
-
|
|
240
|
-
} else if (def.default === "now") {
|
|
241
|
-
sql += " DEFAULT CURRENT_TIMESTAMP";
|
|
242
|
-
}
|
|
195
|
+
if (def.default !== undefined && def.default !== "now") sql += ` DEFAULT ${sqlDefault(def.default)}`;
|
|
196
|
+
else if (def.default === "now") sql += " DEFAULT CURRENT_TIMESTAMP";
|
|
243
197
|
this.db.exec(sql);
|
|
244
198
|
}
|
|
245
199
|
}
|
|
246
200
|
|
|
247
201
|
function fieldTypeToSQLite(type: string): string {
|
|
248
202
|
switch (type) {
|
|
249
|
-
case "integer":
|
|
250
|
-
|
|
251
|
-
case "
|
|
252
|
-
case "
|
|
253
|
-
|
|
254
|
-
case "
|
|
255
|
-
return "INTEGER";
|
|
256
|
-
case "datetime":
|
|
257
|
-
return "TEXT";
|
|
258
|
-
case "text":
|
|
259
|
-
return "TEXT";
|
|
260
|
-
case "string":
|
|
261
|
-
default:
|
|
262
|
-
return "TEXT";
|
|
203
|
+
case "integer": return "INTEGER";
|
|
204
|
+
case "number": case "numeric": return "REAL";
|
|
205
|
+
case "boolean": return "INTEGER";
|
|
206
|
+
case "datetime": return "TEXT";
|
|
207
|
+
case "text": return "TEXT";
|
|
208
|
+
case "string": default: return "TEXT";
|
|
263
209
|
}
|
|
264
210
|
}
|
|
265
211
|
|