Summary#
Once an app registers a data source, osy import-schema asks that source what it holds and writes an entity for each
table: [DataSource], its [ExternalName] address, a member per column with its type, and [Key] on the columns that
identify a row. What it writes is source like any other — Order is then a type your functions and pages use, that
osy model shows and the editor completes.
Signature#
osy import-schema <source> [path] [--table <name>] [--schema <name>] [--as <entity>] [-o <file>] [--force] [--list] [--json]Description#
What it reads#
The source's own DescribeSchema() — the provider class the app registered, built from its entry in
app.DataSources with its secrets, running on the local platform. So the source has to be in the compiled app:
add it to app.DataSources, osy compile, then import. The CLI never holds the credentials.
What it writes#
One entity per table, into <source>.osy in the project (or -o <file>):
// Generated by `osy import-schema Analytics` from what data source `Analytics` describes.
// Ordinary source: review it, trim it, grant reads, and commit it. A later import never overwrites it.
[DataSource(DataSource.Analytics), ExternalName("SALES.ORDERS")]
entity Orders {
[Key, ExternalName("ORDER_ID")] string OrderId;
[ExternalName("REGION")] string? Region;
[ExternalName("TOTAL")] decimal Total;
[ExternalName("CREATED_AT")] DateTimeOffset CreatedAt;
// Nobody can read these rows until you say who may — for example:
// security { allow read when IsAuthenticated; }
}- Names are PascalCase, with
[ExternalName]carrying the exact column whenever the two differ. The entity is named after the table exactly —ORDERSbecomesOrders, never a guessed singular — and--as Orderrenames it. A column namedIDbecomesIdColumn, because every entity'sIdis the platform's. - Types are the ones a source hands values back in:
string,bool,int,long,decimal,bigdecimal,double,DateTime,DateOnly,TimeOnly,DateTimeOffset,GuidandGeography. A nullable column is writtenT?. - A column of any other type is never dropped silently: it is written as a
⚠ SKIPPEDcomment naming it, and listed when the command finishes. - Keys come from the source marking its key columns. A table with none is written with a
⚠ NO KEYcomment and does not compile until you mark the column or columns that identify a row with[Key].
Nothing is granted#
The generated entities have no security { } block, so under secure-by-default nobody can read them. Who may see a
source's data is your decision, not a generator's: write the rule in each entity before you ship it.
Choosing tables#
--list prints the tables the source holds and writes nothing. --table <name> imports one table — by its full name
or its last part, so ORDERS finds SALES.ORDERS — and repeats for more. --schema SALES limits the import to that
schema. --json prints the generated source (or, with --list, the tables) instead of writing.
It never overwrites#
The file is yours once it is written: you trim columns, rename members and add security. So an import refuses to
replace an existing file. -o a different file to compare, or --force when you mean to start again.
Asking whether it is still true#
Because the file is yours, a second import cannot tell you anything useful by rewriting it — the interesting question
is whether what you wrote is still true of the source. --check answers exactly that and writes nothing:
osy import-schema Analytics --checkIt reports, per entity:
| ✗ a column that is gone | with the nearest name at the source, because a drop and a RENAME look identical from here and the remedies are opposites |
| ✗ a table that is gone, a type that no longer fits, a column that started admitting NULL, a key that moved | each one meaning a read will fail, or already does on some row |
| ⓘ a column you do not read, one that stopped admitting NULL | information, never a problem — trimming the import is the point of it being source |
--json gives the same findings with a kind and a refusal flag per entry. The exit code is non-zero when
anything in the first two rows was found.
⚠ Widening is not drift. A decimal column read into a bigdecimal member, or an int into a long, is fine
and is not reported — an author who widened a member ahead of the warehouse has not broken anything. Nor is a member
typed as your own enum over a code column: that is a hand-edit the generator could not have made, and the check
does not punish it.
osy compile refuses drift#
The same comparison runs as a pre-flight on every osy compile, before a version is minted, and fails the compile
naming the column. Without it the first sign of a dropped column is a read failing in a provider's words, on whoever
opens the page first.
⚠ A source that cannot be reached never fails a compile. A warehouse is somebody else's machine, and it is down sometimes; a gate that turned "I could not ask" into "your app is broken" would stop the whole team compiling — including the fix — for an outage they did not cause. Only an answer refuses.
⚠ And osy validate does not run it, because validate is offline by design. Its footer says so rather than
letting a clean local run read as schema-checked.
Examples#
What an import leaves you with, beside the provider it came from — with the read the author then granted:
using Osysharp.Sources;
class Warehouse : IEntitySource {
public const QueryFeatures Pushdown = QueryFeatures.Filter | QueryFeatures.OrderBy | QueryFeatures.Paging;
public const string SecurityKitVersion = "1";
public stream<SourceRow> Query(QueryPlan plan) { yield return new SourceRow(); }
public SourceSchema DescribeSchema() {
return new SourceSchema { Tables = [
new SourceTable { Name = "SALES.ORDERS", Columns = [
new SourceColumn { Name = "ORDER_ID", Type = "string", Key = true },
new SourceColumn { Name = "TOTAL", Type = "decimal" },
] },
] };
}
}
app.DataSources = [ new Warehouse("Analytics") ];
// Generated by `osy import-schema Analytics`, then reviewed: the author added the read.
[DataSource(DataSource.Analytics), ExternalName("SALES.ORDERS")]
entity Orders {
[Key, ExternalName("ORDER_ID")] string OrderId;
[ExternalName("TOTAL")] decimal Total;
security { allow read when IsAuthenticated; }
}And the commands that write it:
osy import-schema Analytics --list
osy import-schema Analytics --schema SALES --table ORDERS --as Order -o model/orders.osy
osy import-schema Analytics --table ORDERS --json
osy import-schema Analytics --checkSee also#
- data held somewhere else (app.DataSources) — registering a source, and the entities whose rows live in one
- Importing data — loading your app's own rows, rather than describing a source's
- Compiling your app — a source is read from the compiled app; and its pre-flight refuses a column the source has dropped