mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-10-26 18:41:18 +00:00
Try to apply ESENT database #277
This commit is contained in:
parent
2aa6fdc256
commit
7aa70a2eeb
|
|
@ -15,17 +15,20 @@ namespace WelsonJS.Launcher
|
|||
private string entryFileName;
|
||||
private string scriptName;
|
||||
private const string timestampFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
private static MetadataStore metadataStore;
|
||||
|
||||
public InstancesForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// set the entry file name to run the instance
|
||||
entryFileName = "bootstrap.bat";
|
||||
}
|
||||
|
||||
private void InstancesForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
lvInstances.Items.Clear();
|
||||
|
||||
LoadInstances(Program.GetAppDataPath());
|
||||
LoadInstances(Path.GetTempPath());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
|
@ -158,6 +159,7 @@ namespace WelsonJS.Launcher
|
|||
|
||||
private void RecordFirstDeployTime(string directory)
|
||||
{
|
||||
/*
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(directory, ".welsonjs_first_deploy_time");
|
||||
|
|
@ -169,6 +171,21 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
throw new Exception($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
object key;
|
||||
Program._MetadataStore.Insert(new Dictionary<string, object>
|
||||
{
|
||||
["InstanceId"] = "abc123",
|
||||
["FirstDeployTime"] = "2025-06-19 10:00:00"
|
||||
}, out key);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceWarning(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInAdministrator()
|
||||
|
|
@ -242,26 +259,26 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
Program.StartResourceServer();
|
||||
|
||||
if (!Program.resourceServer.IsRunning())
|
||||
if (!Program._ResourceServer.IsRunning())
|
||||
{
|
||||
Program.resourceServer.Start();
|
||||
Program._ResourceServer.Start();
|
||||
((ToolStripMenuItem)sender).Text = "Open the code editor...";
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.OpenWebBrowser(Program.resourceServer.GetPrefix());
|
||||
Program.OpenWebBrowser(Program._ResourceServer.GetPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
private void openCodeEditorToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Program.resourceServer == null)
|
||||
if (Program._ResourceServer == null)
|
||||
{
|
||||
MessageBox.Show("A resource server is not running.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.OpenWebBrowser(Program.resourceServer.GetPrefix());
|
||||
Program.OpenWebBrowser(Program._ResourceServer.GetPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
380
WelsonJS.Toolkit/WelsonJS.Launcher/MetadataStore.cs
Normal file
380
WelsonJS.Toolkit/WelsonJS.Launcher/MetadataStore.cs
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
// MetadataStore.cs
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Isam.Esent.Interop;
|
||||
using WelsonJS.Launcher.Storage;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public class MetadataStore : IDisposable
|
||||
{
|
||||
private static readonly object _lock = new object();
|
||||
private static bool _initialized = false;
|
||||
private static Instance _instance;
|
||||
private static string _workingDirectory;
|
||||
private static string _filePath;
|
||||
|
||||
private readonly Session _session;
|
||||
private readonly JET_DBID _dbid;
|
||||
private readonly Schema _schema;
|
||||
private readonly Column _primaryKey;
|
||||
|
||||
private Dictionary<string, JET_COLUMNID> _columnIds;
|
||||
|
||||
public MetadataStore(Schema schema)
|
||||
{
|
||||
_primaryKey = schema.PrimaryKey;
|
||||
|
||||
if (schema == null)
|
||||
throw new ArgumentNullException(nameof(schema));
|
||||
|
||||
if (_primaryKey == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
if (!schema.Columns.Exists(c => c == _primaryKey))
|
||||
throw new ArgumentException($"Primary key '{_primaryKey.Name}' is not in schema.");
|
||||
|
||||
_workingDirectory = Program.GetAppDataPath();
|
||||
_schema = schema;
|
||||
_columnIds = new Dictionary<string, JET_COLUMNID>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
InitializeInstance();
|
||||
|
||||
_session = new Session(_instance);
|
||||
|
||||
if (!File.Exists(_filePath))
|
||||
{
|
||||
Api.JetCreateDatabase(_session, _filePath, null, out _dbid, CreateDatabaseGrbit.None);
|
||||
CreateTable(_schema);
|
||||
}
|
||||
else
|
||||
{
|
||||
Api.JetAttachDatabase(_session, _filePath, AttachDatabaseGrbit.None);
|
||||
Api.JetOpenDatabase(_session, _filePath, null, out _dbid, OpenDatabaseGrbit.None);
|
||||
}
|
||||
|
||||
CacheColumns();
|
||||
}
|
||||
|
||||
private static void InitializeInstance()
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
// set the file path
|
||||
_filePath = Path.Combine(_workingDirectory, "metadata.edb");
|
||||
|
||||
// config the instance
|
||||
_instance = new Instance("WelsonJS.Launcher.MetadataStore");
|
||||
_instance.Parameters.SystemDirectory = _workingDirectory;
|
||||
_instance.Parameters.LogFileDirectory = _workingDirectory;
|
||||
_instance.Parameters.TempDirectory = _workingDirectory;
|
||||
|
||||
// initialize the instance
|
||||
_instance.Init();
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTable(Schema schema)
|
||||
{
|
||||
Api.JetBeginTransaction(_session);
|
||||
JET_TABLEID tableid;
|
||||
Api.JetCreateTable(_session, _dbid, schema.TableName, 0, 100, out tableid);
|
||||
|
||||
foreach (var col in schema.Columns)
|
||||
{
|
||||
var coldef = new JET_COLUMNDEF
|
||||
{
|
||||
coltyp = col.Type,
|
||||
cbMax = col.MaxSize,
|
||||
cp = col.CodePage
|
||||
};
|
||||
Api.JetAddColumn(_session, tableid, col.Name, coldef, null, 0, out _);
|
||||
}
|
||||
|
||||
Api.JetCloseTable(_session, tableid);
|
||||
Api.JetCommitTransaction(_session, CommitTransactionGrbit.None);
|
||||
}
|
||||
|
||||
private void CacheColumns()
|
||||
{
|
||||
using (var table = new Table(_session, _dbid, _schema.TableName, OpenTableGrbit.ReadOnly))
|
||||
{
|
||||
foreach (var col in _schema.Columns)
|
||||
{
|
||||
try
|
||||
{
|
||||
JET_COLUMNID colid = Api.GetTableColumnid(_session, table, col.Name);
|
||||
_columnIds[col.Name] = colid;
|
||||
}
|
||||
catch (EsentColumnNotFoundException)
|
||||
{
|
||||
Trace.TraceWarning($"Column '{col.Name}' not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Insert(Dictionary<string, object> values, out object key)
|
||||
{
|
||||
return TrySaveRecord(values, JET_prep.Insert, expectSeek: false, out key);
|
||||
}
|
||||
|
||||
public bool Update(Dictionary<string, object> values)
|
||||
{
|
||||
return TrySaveRecord(values, JET_prep.Replace, expectSeek: true, out _);
|
||||
}
|
||||
|
||||
private bool TrySaveRecord(
|
||||
Dictionary<string, object> values,
|
||||
JET_prep prepType,
|
||||
bool expectSeek,
|
||||
out object primaryKeyValue)
|
||||
{
|
||||
primaryKeyValue = null;
|
||||
|
||||
if (!TryGetPrimaryKeyValue(values, out var keyValue))
|
||||
return false;
|
||||
|
||||
var keyType = _primaryKey.Type;
|
||||
|
||||
using (var table = new Table(_session, _dbid, _schema.TableName, OpenTableGrbit.Updatable))
|
||||
{
|
||||
try
|
||||
{
|
||||
Api.JetBeginTransaction(_session);
|
||||
|
||||
MakeKeyByType(keyValue, keyType, _session, table);
|
||||
bool found = Api.TrySeek(_session, table, SeekGrbit.SeekEQ);
|
||||
|
||||
if (expectSeek != found)
|
||||
{
|
||||
Trace.TraceWarning($"[ESENT] Operation skipped. Seek result = {found}, expected = {expectSeek}");
|
||||
Api.JetRollback(_session, RollbackTransactionGrbit.None);
|
||||
return false;
|
||||
}
|
||||
|
||||
Api.JetPrepareUpdate(_session, table, prepType);
|
||||
SetAllColumns(values, table);
|
||||
|
||||
Api.JetUpdate(_session, table);
|
||||
Api.JetCommitTransaction(_session, CommitTransactionGrbit.None);
|
||||
|
||||
if (prepType == JET_prep.Insert)
|
||||
primaryKeyValue = keyValue;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"[ESENT] Operation failed: {ex.Message}");
|
||||
Api.JetRollback(_session, RollbackTransactionGrbit.None);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object> FindById(object keyValue)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
var keyType = _primaryKey.Type;
|
||||
|
||||
using (var table = new Table(_session, _dbid, _schema.TableName, OpenTableGrbit.ReadOnly))
|
||||
{
|
||||
MakeKeyByType(keyValue, keyType, _session, table);
|
||||
if (!Api.TrySeek(_session, table, SeekGrbit.SeekEQ))
|
||||
return null;
|
||||
|
||||
foreach (var col in _schema.Columns)
|
||||
{
|
||||
if (!_columnIds.TryGetValue(col.Name, out var colid))
|
||||
continue;
|
||||
|
||||
var value = RetrieveColumnByType(_session, table, colid, col.Type);
|
||||
result[col.Name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> FindAll()
|
||||
{
|
||||
var results = new List<Dictionary<string, object>>();
|
||||
|
||||
using (var table = new Table(_session, _dbid, _schema.TableName, OpenTableGrbit.ReadOnly))
|
||||
{
|
||||
if (!Api.TryMoveFirst(_session, table))
|
||||
return results;
|
||||
|
||||
do
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
foreach (var col in _schema.Columns)
|
||||
{
|
||||
if (!_columnIds.TryGetValue(col.Name, out var colid))
|
||||
continue;
|
||||
|
||||
var value = RetrieveColumnByType(_session, table, colid, col.Type);
|
||||
row[col.Name] = value;
|
||||
}
|
||||
results.Add(row);
|
||||
}
|
||||
while (Api.TryMoveNext(_session, table));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public bool DeleteById(object keyValue)
|
||||
{
|
||||
var keyType = _primaryKey.Type;
|
||||
|
||||
using (var table = new Table(_session, _dbid, _schema.TableName, OpenTableGrbit.Updatable))
|
||||
{
|
||||
MakeKeyByType(keyValue, keyType, _session, table);
|
||||
if (!Api.TrySeek(_session, table, SeekGrbit.SeekEQ))
|
||||
return false;
|
||||
|
||||
Api.JetDelete(_session, table);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private object RetrieveColumnByType(Session session, Table table, JET_COLUMNID columnId, JET_coltyp type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case JET_coltyp.Text:
|
||||
return Api.RetrieveColumnAsString(session, table, columnId, Encoding.Unicode);
|
||||
case JET_coltyp.Long:
|
||||
return Api.RetrieveColumnAsInt32(session, table, columnId);
|
||||
case JET_coltyp.IEEEDouble:
|
||||
return Api.RetrieveColumnAsDouble(session, table, columnId);
|
||||
case JET_coltyp.DateTime:
|
||||
return Api.RetrieveColumnAsDateTime(session, table, columnId);
|
||||
case JET_coltyp.Binary:
|
||||
case JET_coltyp.LongBinary:
|
||||
return Api.RetrieveColumn(session, table, columnId);
|
||||
default:
|
||||
Trace.TraceWarning($"[ESENT] Unsupported RetrieveColumn type: {type}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetPrimaryKeyValue(Dictionary<string, object> values, out object keyValue)
|
||||
{
|
||||
keyValue = null;
|
||||
|
||||
if (!values.TryGetValue(_primaryKey.Name, out keyValue))
|
||||
{
|
||||
Trace.TraceWarning($"[ESENT] Missing primary key '{_primaryKey.Name}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyValue == null)
|
||||
{
|
||||
Trace.TraceWarning("[ESENT] Primary key value cannot be null.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private JET_coltyp GetColumnType(string columnName)
|
||||
{
|
||||
var column = _schema.Columns.FirstOrDefault(c => c.Name == columnName);
|
||||
if (column == null)
|
||||
throw new ArgumentException($"Column '{columnName}' not found in schema.");
|
||||
|
||||
return column.Type;
|
||||
}
|
||||
|
||||
private void SetAllColumns(Dictionary<string, object> values, Table table)
|
||||
{
|
||||
foreach (var kv in values)
|
||||
{
|
||||
if (!_columnIds.TryGetValue(kv.Key, out var colid))
|
||||
{
|
||||
Trace.TraceWarning($"[ESENT] Column '{kv.Key}' not found in cache.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var colType = GetColumnType(kv.Key);
|
||||
SetColumnByType(_session, table, colid, kv.Value, colType);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetColumnByType(Session session, Table table, JET_COLUMNID columnId, object value, JET_coltyp type)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case JET_coltyp.Text:
|
||||
Api.SetColumn(session, table, columnId, value.ToString(), Encoding.Unicode);
|
||||
break;
|
||||
case JET_coltyp.Long:
|
||||
Api.SetColumn(session, table, columnId, Convert.ToInt32(value));
|
||||
break;
|
||||
case JET_coltyp.IEEEDouble:
|
||||
Api.SetColumn(session, table, columnId, Convert.ToDouble(value));
|
||||
break;
|
||||
case JET_coltyp.DateTime:
|
||||
Api.SetColumn(session, table, columnId, Convert.ToDateTime(value));
|
||||
break;
|
||||
case JET_coltyp.Binary:
|
||||
case JET_coltyp.LongBinary:
|
||||
Api.SetColumn(session, table, columnId, (byte[])value);
|
||||
break;
|
||||
default:
|
||||
Trace.TraceWarning($"[ESENT] Unsupported SetColumn type: {type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeKeyByType(object value, JET_coltyp type, Session session, Table table)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case JET_coltyp.Text:
|
||||
Api.MakeKey(session, table, value.ToString(), Encoding.Unicode, MakeKeyGrbit.NewKey);
|
||||
break;
|
||||
case JET_coltyp.Long:
|
||||
Api.MakeKey(session, table, Convert.ToInt32(value), MakeKeyGrbit.NewKey);
|
||||
break;
|
||||
case JET_coltyp.IEEEDouble:
|
||||
Api.MakeKey(session, table, Convert.ToDouble(value), MakeKeyGrbit.NewKey);
|
||||
break;
|
||||
case JET_coltyp.DateTime:
|
||||
Api.MakeKey(session, table, Convert.ToDateTime(value), MakeKeyGrbit.NewKey);
|
||||
break;
|
||||
case JET_coltyp.Binary:
|
||||
case JET_coltyp.LongBinary:
|
||||
Api.MakeKey(session, table, (byte[])value, MakeKeyGrbit.NewKey);
|
||||
break;
|
||||
default:
|
||||
Trace.TraceWarning($"[ESENT] Unsupported MakeKey type: {type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_session?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,28 +10,46 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using WelsonJS.Launcher.Storage;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
static Mutex mutex;
|
||||
public static ResourceServer resourceServer;
|
||||
public static ResourceServer _ResourceServer;
|
||||
public static MetadataStore _MetadataStore;
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
mutex = new Mutex(true, "WelsonJS.Launcher.Mutex", out bool isMutexNotExists);
|
||||
// create the mutex
|
||||
mutex = new Mutex(true, "WelsonJS.Launcher", out bool isMutexNotExists);
|
||||
if (!isMutexNotExists)
|
||||
{
|
||||
MessageBox.Show("WelsonJS Launcher already running.");
|
||||
return;
|
||||
}
|
||||
|
||||
// connect the database to manage an instances
|
||||
Schema schema = new Schema("Instances", new List<Column>
|
||||
{
|
||||
new Column("InstanceId", typeof(string), 255),
|
||||
new Column("FirstDeployTime", typeof(DateTime), 1)
|
||||
});
|
||||
schema.SetPrimaryKey("InstanceId");
|
||||
_MetadataStore = new MetadataStore(schema);
|
||||
|
||||
// draw the main form
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainForm());
|
||||
|
||||
// close the database
|
||||
_MetadataStore.Dispose();
|
||||
|
||||
// destory the mutex
|
||||
mutex.ReleaseMutex();
|
||||
mutex.Dispose();
|
||||
}
|
||||
|
|
@ -147,9 +165,9 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
lock(typeof(Program))
|
||||
{
|
||||
if (resourceServer == null)
|
||||
if (_ResourceServer == null)
|
||||
{
|
||||
resourceServer = new ResourceServer(GetAppConfig("ResourceServerPrefix"), "editor.html");
|
||||
_ResourceServer = new ResourceServer(GetAppConfig("ResourceServerPrefix"), "editor.html");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
66
WelsonJS.Toolkit/WelsonJS.Launcher/Storage/Column.cs
Normal file
66
WelsonJS.Toolkit/WelsonJS.Launcher/Storage/Column.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Column.cs
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.Isam.Esent.Interop;
|
||||
|
||||
namespace WelsonJS.Launcher.Storage
|
||||
{
|
||||
public class Column
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public JET_coltyp Type { get; set; }
|
||||
public int MaxSize { get; set; }
|
||||
public JET_CP CodePage { get; set; }
|
||||
public bool IsPrimaryKey { get; set; } = false;
|
||||
|
||||
public Column(string name, JET_coltyp type, int maxSize = 0, JET_CP codePage = JET_CP.None)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
MaxSize = maxSize;
|
||||
CodePage = codePage == JET_CP.None ?
|
||||
JET_CP.Unicode : codePage;
|
||||
}
|
||||
|
||||
public Column(string name, Type dotNetType, int maxSize = 0, Encoding encoding = null)
|
||||
{
|
||||
Name = name;
|
||||
Type = GetJetColtypFromType(dotNetType);
|
||||
MaxSize = maxSize;
|
||||
CodePage = GetJetCpFromEncoding(encoding ?? Encoding.Unicode);
|
||||
}
|
||||
|
||||
private static JET_coltyp GetJetColtypFromType(Type type)
|
||||
{
|
||||
if (type == typeof(string)) return JET_coltyp.Text;
|
||||
if (type == typeof(int)) return JET_coltyp.Long;
|
||||
if (type == typeof(long)) return JET_coltyp.Currency;
|
||||
if (type == typeof(bool)) return JET_coltyp.Bit;
|
||||
if (type == typeof(float)) return JET_coltyp.IEEESingle;
|
||||
if (type == typeof(double)) return JET_coltyp.IEEEDouble;
|
||||
if (type == typeof(DateTime)) return JET_coltyp.DateTime;
|
||||
if (type == typeof(byte[])) return JET_coltyp.LongBinary;
|
||||
|
||||
throw new NotSupportedException($"Unsupported .NET type: {type.FullName}");
|
||||
}
|
||||
|
||||
private static JET_CP GetJetCpFromEncoding(Encoding encoding)
|
||||
{
|
||||
if (encoding == Encoding.Unicode) return JET_CP.Unicode;
|
||||
if (encoding == Encoding.ASCII) return JET_CP.ASCII;
|
||||
if (encoding.CodePage == 1252) return (JET_CP)1252; // Windows-1252 / Latin1
|
||||
if (encoding.CodePage == 51949) return (JET_CP)51949; // EUC-KR
|
||||
if (encoding.CodePage == 949) return (JET_CP)949; // UHC (Windows Korean)
|
||||
if (encoding.CodePage == 932) return (JET_CP)932; // Shift-JIS (Japanese)
|
||||
if (encoding.CodePage == 936) return (JET_CP)936; // GB2312 (Simplified Chinese)
|
||||
if (encoding.CodePage == 65001) return (JET_CP)65001; // UTF-8
|
||||
if (encoding.CodePage == 28591) return (JET_CP)28591; // ISO-8859-1
|
||||
|
||||
throw new NotSupportedException($"Unsupported encoding: {encoding.WebName} (code page {encoding.CodePage})");
|
||||
}
|
||||
}
|
||||
}
|
||||
42
WelsonJS.Toolkit/WelsonJS.Launcher/Storage/Schema.cs
Normal file
42
WelsonJS.Toolkit/WelsonJS.Launcher/Storage/Schema.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// TableSchema.cs
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WelsonJS.Launcher.Storage
|
||||
{
|
||||
public class Schema
|
||||
{
|
||||
public string TableName { get; set; }
|
||||
public List<Column> Columns { get; set; }
|
||||
public Column PrimaryKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return Columns.Find(c => c.IsPrimaryKey) ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
public Schema(string tableName, List<Column> columns)
|
||||
{
|
||||
TableName = tableName;
|
||||
Columns = columns ?? new List<Column>();
|
||||
}
|
||||
|
||||
public void SetPrimaryKey(string columnName)
|
||||
{
|
||||
Column column = Columns.Find(c => c.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase));
|
||||
if (column != null)
|
||||
{
|
||||
column.IsPrimaryKey = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Column '{columnName}' does not exist in schema '{TableName}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,28 @@
|
|||
<PropertyGroup>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Esent.Interop, Version=1.9.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ManagedEsent.1.9.4\lib\net40\Esent.Interop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
|
|
@ -103,6 +124,9 @@
|
|||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ResourceServer.cs" />
|
||||
<Compile Include="Storage\Column.cs" />
|
||||
<Compile Include="MetadataStore.cs" />
|
||||
<Compile Include="Storage\Schema.cs" />
|
||||
<EmbeddedResource Include="EnvForm.resx">
|
||||
<DependentUpon>EnvForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
@ -121,6 +145,7 @@
|
|||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
|
|
|||
4
WelsonJS.Toolkit/WelsonJS.Launcher/packages.config
Normal file
4
WelsonJS.Toolkit/WelsonJS.Launcher/packages.config
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ManagedEsent" version="1.9.4" targetFramework="net472" />
|
||||
</packages>
|
||||
Loading…
Reference in New Issue
Block a user